kernel: add aic8800 wifi6/btdm5.4 driver

aic8800d_linux_sdk_V3.0_2024_0327_3561b08f.7z

Signed-off-by: carbon <carbon@milkv.io>
This commit is contained in:
carbon
2024-08-06 10:17:32 +08:00
parent 6fa73ec641
commit 652259ff93
133 changed files with 84171 additions and 0 deletions

View File

@ -0,0 +1,5 @@
*.symvers
*.order
*.symvers.cmd
*.order.cmd
.tmp_versions/

View File

@ -0,0 +1,18 @@
config AIC_WLAN_SUPPORT
bool "AIC wireless Support"
default n
help
This is support for aic wireless chip.
config AIC_FW_PATH
depends on AIC_WLAN_SUPPORT
string "Firmware & config file path"
default "/vendor/etc/firmware"
#default "/lib/firmware/aic8800_sdio"
help
Path to the firmware & config file.
if AIC_WLAN_SUPPORT
source "drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig"
source "drivers/net/wireless/aic8800/aic8800_btlpm/Kconfig"
endif

View File

@ -0,0 +1,91 @@
CONFIG_AIC8800_BTLPM_SUPPORT := m
CONFIG_AIC8800_WLAN_SUPPORT := m
CONFIG_AIC_WLAN_SUPPORT := m
obj-$(CONFIG_AIC8800_BTLPM_SUPPORT) += aic8800_btlpm/
obj-$(CONFIG_AIC8800_WLAN_SUPPORT) += aic8800_fdrv/
obj-$(CONFIG_AIC_WLAN_SUPPORT) += aic8800_bsp/
MAKEFLAGS +=-j$(shell nproc)
########## config option ##########
export CONFIG_USE_FW_REQUEST = n
export CONFIG_PREALLOC_RX_SKB = n
export CONFIG_PREALLOC_TXQ = y
export CONFIG_OOB = n
export CONFIG_GPIO_WAKEUP = n
export CONFIG_RESV_MEM_SUPPORT = y
###################################
########## Platform support list ##########
export CONFIG_PLATFORM_ROCKCHIP = n
export CONFIG_PLATFORM_ROCKCHIP2 = n
export CONFIG_PLATFORM_ALLWINNER = n
export CONFIG_PLATFORM_AMLOGIC = n
export CONFIG_PLATFORM_UBUNTU = y
ifeq ($(CONFIG_PLATFORM_ROCKCHIP), y)
ARCH = arm64
KDIR = /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/kernel
CROSS_COMPILE = /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
ccflags-y += -DANDROID_PLATFORM
ccflags-y += -DCONFIG_PLATFORM_ROCKCHIP
endif
ifeq ($(CONFIG_PLATFORM_ROCKCHIP2), y)
KDIR := /home/yaya/E/Rockchip/3126/Android6/kernel
ARCH ?= arm
CROSS_COMPILE ?= /home/yaya/E/Rockchip/3288/Android5/rk3288_JHY/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-
ccflags-y += -DANDROID_PLATFORM
ccflags-y += -DCONFIG_PLATFORM_ROCKCHIP2
endif
ifeq ($(CONFIG_PLATFORM_ALLWINNER), y)
KDIR = /home/yaya/E/Allwinner/A133/Android10/linux-4.9
ARCH = arm64
CROSS_COMPILE = /home/yaya/E/Allwinner/r818/Android10/lichee/out/gcc-linaro-5.3.1-2016.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
export CONFIG_SUPPORT_LPM = y
ccflags-y += -DANDROID_PLATFORM
endif
ifeq ($(CONFIG_PLATFORM_AMLOGIC), y)
ARCH = arm
CROSS_COMPILE = /home/yaya/D/Workspace/CyberQuantum/JinHaoYue/amls905x3/SDK/20191101-0tt-asop/android9.0/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androidkernel-
KDIR = /home/yaya/D/Workspace/CyberQuantum/JinHaoYue/amls905x3/SDK/20191101-0tt-asop/android9.0/out/target/product/u202/obj/KERNEL_OBJ/
ccflags-y += -DANDROID_PLATFORM
export CONFIG_SUPPORT_LPM = y
endif
ifeq ($(CONFIG_PLATFORM_UBUNTU), y)
KDIR = /lib/modules/$(shell uname -r)/build
PWD = $(shell pwd)
KVER = $(shell uname -r)
MODDESTDIR = /lib/modules/$(KVER)/kernel/drivers/net/wireless/aic8800
ARCH = x86_64
CROSS_COMPILE ?=
endif
###########################################
all: modules
modules:
make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
install:
mkdir -p $(MODDESTDIR)
install -p -m 644 aic8800_bsp/aic8800_bsp.ko $(MODDESTDIR)/
install -p -m 644 aic8800_fdrv/aic8800_fdrv.ko $(MODDESTDIR)/
install -p -m 644 aic8800_btlpm/aic8800_btlpm.ko $(MODDESTDIR)/
/sbin/depmod -a ${KVER}
uninstall:
rm -rfv $(MODDESTDIR)/aic8800_bsp.ko
rm -rfv $(MODDESTDIR)/aic8800_fdrv.ko
rm -rfv $(MODDESTDIR)/aic8800_btlpm.ko
/sbin/depmod -a ${KVER}
clean:
cd aic8800_bsp/;make clean;cd ..
cd aic8800_fdrv/;make clean;cd ..
cd aic8800_btlpm/;make clean;cd ..
rm -rf modules.order Module.symvers .modules.order.cmd .Module.symvers.cmd .tmp_versions/

View File

@ -0,0 +1,10 @@
*.o
*.ko
*.order
*.symvers
*.o.d
*.o.cmd
*.ko.cmd
*.mod
*.mod.c
*.mod.cmd

View File

@ -0,0 +1,136 @@
CONFIG_SDIO_SUPPORT := y
CONFIG_SDIO_PWRCTRL := y
CONFIG_AIC_FW_PATH = "/vendor/etc/firmware"
#CONFIG_AIC_FW_PATH = "/lib/firmware/aic8800"
export CONFIG_AIC_FW_PATH
ccflags-y += -DCONFIG_AIC_FW_PATH=\"$(CONFIG_AIC_FW_PATH)\"
MODULE_NAME := aic8800_bsp
ifeq ($(CONFIG_SDIO_SUPPORT), y)
ccflags-y += -DAICWF_SDIO_SUPPORT
ccflags-$(CONFIG_SDIO_PWRCTRL) += -DCONFIG_SDIO_PWRCTRL
endif
CONFIG_GPIO_WAKEUP ?= n
CONFIG_M2D_OTA_AUTO_SUPPORT = n
CONFIG_M2D_OTA_LZMA_SUPPORT = n
CONFIG_LINK_DET_5G = y
CONFIG_MCU_MESSAGE = n
CONFIG_FIRMWARE_ARRAY = n
# Need to set fw path in BOARD_KERNEL_CMDLINE
CONFIG_USE_FW_REQUEST ?= n
CONFIG_FDRV_NO_REG_SDIO = n
CONFIG_VRF_DCDC_MODE = y
CONFIG_OOB ?= n
CONFIG_PREALLOC_TXQ = y
CONFIG_DPD = y
CONFIG_FORCE_DPD_CALIB = y
CONFIG_RESV_MEM_SUPPORT ?= y
CONFIG_AMSDU_RX = n
CONFIG_IRQ_FALL ?= n
CONFIG_SDIO_BT = n
ccflags-$(CONFIG_GPIO_WAKEUP) += -DCONFIG_GPIO_WAKEUP
ccflags-$(CONFIG_M2D_OTA_AUTO_SUPPORT) += -DCONFIG_M2D_OTA_AUTO_SUPPORT
ccflags-$(CONFIG_M2D_OTA_LZMA_SUPPORT) += -DCONFIG_M2D_OTA_LZMA_SUPPORT
ccflags-$(CONFIG_LINK_DET_5G) += -DCONFIG_LINK_DET_5G
ccflags-$(CONFIG_MCU_MESSAGE) += -DCONFIG_MCU_MESSAGE
ccflags-$(CONFIG_FIRMWARE_ARRAY) += -DCONFIG_FIRMWARE_ARRAY
ccflags-$(CONFIG_USE_FW_REQUEST) += -DCONFIG_USE_FW_REQUEST
ccflags-$(CONFIG_FDRV_NO_REG_SDIO) += -DCONFIG_FDRV_NO_REG_SDIO
ccflags-$(CONFIG_VRF_DCDC_MODE) += -DCONFIG_VRF_DCDC_MODE
ccflags-$(CONFIG_OOB) += -DCONFIG_OOB
ccflags-$(CONFIG_PREALLOC_TXQ) += -DCONFIG_PREALLOC_TXQ
ccflags-$(CONFIG_DPD) += -DCONFIG_DPD
ccflags-$(CONFIG_FORCE_DPD_CALIB) += -DCONFIG_FORCE_DPD_CALIB -DCONFIG_DPD
ccflags-$(CONFIG_RESV_MEM_SUPPORT) += -DCONFIG_RESV_MEM_SUPPORT
ccflags-$(CONFIG_AMSDU_RX) += -DCONFIG_AMSDU_RX
ccflags-$(CONFIG_IRQ_FALL) += -DCONFIG_IRQ_FALL
ccflags-$(CONFIG_SDIO_BT) += -DCONFIG_SDIO_BT
obj-m := $(MODULE_NAME).o
$(MODULE_NAME)-y := \
aic8800dc_compat.o \
aic8800d80_compat.o \
aic_bsp_main.o \
aic_bsp_driver.o \
aicsdio.o \
aicsdio_txrxif.o \
md5.o
$(MODULE_NAME)-$(CONFIG_PREALLOC_TXQ) += aicwf_txq_prealloc.o
ifeq ($(CONFIG_FIRMWARE_ARRAY),y)
$(MODULE_NAME)-y += aicwf_firmware_array.o
endif
########## Platform support list ##########
CONFIG_PLATFORM_ROCKCHIP ?= n
CONFIG_PLATFORM_ROCKCHIP2 ?= n
CONFIG_PLATFORM_ALLWINNER ?=n
CONFIG_PLATFORM_INGENIC_T20 ?= n
CONFIG_PLATFORM_AMLOGIC ?= n
CONFIG_PLATFORM_UBUNTU ?= y
ifeq ($(CONFIG_PLATFORM_ROCKCHIP), y)
ccflags-$(CONFIG_PLATFORM_ROCKCHIP) += -DCONFIG_PLATFORM_ROCKCHIP
KDIR ?= /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/kernel
ARCH ?= arm64
CROSS_COMPILE ?= /home/yaya/E/Rockchip/3566/Android11/rk3566_rk3568_android11_oranth/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
endif
ifeq ($(CONFIG_PLATFORM_ROCKCHIP2), y)
ccflags-$(CONFIG_PLATFORM_ROCKCHIP2) += -DCONFIG_PLATFORM_ROCKCHIP2
ARCH ?= arm64
KDIR ?= /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/kernel
CROSS_COMPILE ?= /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
endif
ifeq ($(CONFIG_PLATFORM_ALLWINNER), y)
ccflags-$(CONFIG_PLATFORM_ALLWINNER) += -DCONFIG_PLATFORM_ALLWINNER
KDIR ?= /home/yaya/E/Allwinner/r818/Android10/lichee/kernel/linux-4.9/
ARCH ?= arm64
CROSS_COMPILE ?= /home/yaya/E/Allwinner/r818/Android10/android/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-
endif
ifeq ($(CONFIG_PLATFORM_INGENIC_T20), y)
KDIR ?= /home/yaya/E/T40/kernel
ARCH ?= mips
CROSS_COMPILE ?= /home/yaya/E/T40/mips-linux-gnu-ingenic-gcc7.2.0-glibc2.29-fp64/bin/mips-linux-gnu-
endif
ifeq ($(CONFIG_PLATFORM_AMLOGIC), y)
ccflags-$(CONFIG_PLATFORM_AMLOGIC) += -DCONFIG_PLATFORM_AMLOGIC
KDIR ?= /home/aiden/D1/SDK/Amlogic/905x3_a9/android9.0/out/target/product/u202/obj/KERNEL_OBJ/
ARCH ?= arm
CROSS_COMPILE ?= /home/aiden/D1/SDK/Amlogic/905x3_a9/android9.0/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/arm-linux-androideabi-
endif
ifeq ($(CONFIG_PLATFORM_UBUNTU), y)
ccflags-$(CONFIG_PLATFORM_UBUNTU) += -DCONFIG_PLATFORM_UBUNTU
KDIR ?= /lib/modules/$(shell uname -r)/build
PWD ?= $(shell pwd)
KVER ?= $(shell uname -r)
MODDESTDIR ?= /lib/modules/$(KVER)/kernel/drivers/net/wireless/
ARCH ?= x86_64
CROSS_COMPILE ?=
endif
###########################################
all: modules
modules:
make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
install:
mkdir -p $(MODDESTDIR)
install -p -m 644 $(MODULE_NAME).ko $(MODDESTDIR)
/sbin/depmod -a ${KVER}
uninstall:
rm -rfv $(MODDESTDIR)/$(MODULE_NAME).ko
/sbin/depmod -a ${KVER}
clean:
rm -rf *.o *.ko *.o.* *.mod.* modules.* Module.* .a* .o* .*.o.* *.mod .tmp* .cache.mk built-in.a

View File

@ -0,0 +1,252 @@
#include "aic8800d80_compat.h"
#include "aic_bsp_driver.h"
extern struct aicbsp_info_t aicbsp_info;
extern int adap_test;
typedef u32 (*array2_tbl_t)[2];
#define AIC_PATCH_MAGIG_NUM 0x48435450 // "PTCH"
#define AIC_PATCH_MAGIG_NUM_2 0x50544348 // "HCTP"
#define AIC_PATCH_BLOCK_MAX 4
typedef struct {
uint32_t magic_num;
uint32_t pair_start;
uint32_t magic_num_2;
uint32_t pair_count;
uint32_t block_dst[AIC_PATCH_BLOCK_MAX];
uint32_t block_src[AIC_PATCH_BLOCK_MAX];
uint32_t block_size[AIC_PATCH_BLOCK_MAX]; // word count
} aic_patch_t;
#define AIC_PATCH_OFST(mem) ((size_t) &((aic_patch_t *)0)->mem)
#define AIC_PATCH_ADDR(mem) ((u32)(aic_patch_str_base + AIC_PATCH_OFST(mem)))
u32 aicbsp_syscfg_tbl_8800d80[][2] = {
};
int aicbsp_system_config_8800d80(struct aic_sdio_dev *sdiodev)
{
int syscfg_num = sizeof(aicbsp_syscfg_tbl_8800d80) / sizeof(u32) / 2;
int ret, cnt;
for (cnt = 0; cnt < syscfg_num; cnt++) {
ret = rwnx_send_dbg_mem_write_req(sdiodev, aicbsp_syscfg_tbl_8800d80[cnt][0], aicbsp_syscfg_tbl_8800d80[cnt][1]);
if (ret) {
printk("%x write fail: %d\n", aicbsp_syscfg_tbl_8800d80[cnt][0], ret);
return ret;
}
}
return 0;
}
u32 adaptivity_patch_tbl_8800d80[][2] = {
{0x000C, 0x0000320A}, //linkloss_thd
{0x009C, 0x00000000}, //ac_param_conf
{0x0168, 0x00010000}, //tx_adaptivity_en
};
#define USER_CHAN_MAX_TXPWR_EN_FLAG (0x01U << 1)
#define USER_TX_USE_ANA_F_FLAG (0x01U << 2)
#define CFG_USER_CHAN_MAX_TXPWR_EN 0
#define CFG_USER_TX_USE_ANA_F 0
#define CFG_USER_EXT_FLAGS_EN (CFG_USER_CHAN_MAX_TXPWR_EN || CFG_USER_TX_USE_ANA_F)
u32 patch_tbl_8800d80[][2] = {
#ifdef USE_5G
{0x00b4, 0xf3010001},
#else
{0x00b4, 0xf3010000},
#endif
#if defined(CONFIG_AMSDU_RX)
{0x170, 0x0100000a}
#endif
#ifdef CONFIG_IRQ_FALL
{0x00000170, 0x0000010a}, //irqf
#endif
#if CFG_USER_EXT_FLAGS_EN
{0x0188, 0x00000001
#if CFG_USER_CHAN_MAX_TXPWR_EN
| USER_CHAN_MAX_TXPWR_EN_FLAG
#endif
#if CFG_USER_TX_USE_ANA_F
| USER_TX_USE_ANA_F_FLAG
#endif
}, // user_ext_flags
#endif
};
#ifdef CONFIG_OOB
// for 8800d40/d80 map data1 isr to gpiob1
u32 gpio_cfg_tbl_8800d40d80[][2] = {
{0x40504084, 0x00000006},
{0x40500040, 0x00000000},
{0x40100030, 0x00000001},
{0x40241020, 0x00000001},
{0x40240030, 0x00000004},
{0x40240020, 0x03020700},
};
#endif
int aicwifi_sys_config_8800d80(struct aic_sdio_dev *sdiodev)
{
#ifdef CONFIG_OOB
int ret, cnt;
int gpiocfg_num = sizeof(gpio_cfg_tbl_8800d40d80) / sizeof(u32) / 2;
for (cnt = 0; cnt < gpiocfg_num; cnt++) {
ret = rwnx_send_dbg_mem_write_req(sdiodev, gpio_cfg_tbl_8800d40d80[cnt][0], gpio_cfg_tbl_8800d40d80[cnt][1]);
if (ret) {
printk("%x write fail: %d\n", gpio_cfg_tbl_8800d40d80[cnt][0], ret);
return ret;
}
}
#endif
return 0;
}
#define NEW_PATCH_BUFFER_MAP 1
int aicwifi_patch_config_8800d80(struct aic_sdio_dev *sdiodev)
{
const u32 rd_patch_addr = RAM_FMAC_FW_ADDR + 0x0198;
u32 aic_patch_addr;
u32 config_base, aic_patch_str_base;
#if (NEW_PATCH_BUFFER_MAP)
u32 patch_buff_addr, patch_buff_base, rd_version_addr, rd_version_val;
#endif
uint32_t start_addr = 0x0016F800;
u32 patch_addr = start_addr;
u32 patch_cnt = sizeof(patch_tbl_8800d80)/sizeof(u32)/2;
struct dbg_mem_read_cfm rd_patch_addr_cfm;
int ret = 0;
int cnt = 0;
//adap test
int adap_patch_cnt = 0;
if (adap_test) {
printk("%s for adaptivity test \r\n", __func__);
adap_patch_cnt = sizeof(adaptivity_patch_tbl_8800d80)/sizeof(u32)/2;
}
aic_patch_addr = rd_patch_addr + 8;
ret = rwnx_send_dbg_mem_read_req(sdiodev, rd_patch_addr, &rd_patch_addr_cfm);
if (ret) {
printk("patch rd fail\n");
return ret;
}
config_base = rd_patch_addr_cfm.memdata;
ret = rwnx_send_dbg_mem_read_req(sdiodev, aic_patch_addr, &rd_patch_addr_cfm);
if (ret) {
printk("patch str rd fail\n");
return ret;
}
aic_patch_str_base = rd_patch_addr_cfm.memdata;
#if (NEW_PATCH_BUFFER_MAP)
rd_version_addr = RAM_FMAC_FW_ADDR + 0x01C;
if ((ret = rwnx_send_dbg_mem_read_req(sdiodev, rd_version_addr, &rd_patch_addr_cfm))) {
printk("version val[0x%x] rd fail: %d\n", rd_version_addr, ret);
return ret;
}
rd_version_val = rd_patch_addr_cfm.memdata;
printk("rd_version_val=%08X\n", rd_version_val);
sdiodev->fw_version_uint = rd_version_val;
if (rd_version_val > 0x06090100) {
patch_buff_addr = rd_patch_addr + 12;
ret = rwnx_send_dbg_mem_read_req(sdiodev, patch_buff_addr, &rd_patch_addr_cfm);
if (ret) {
printk("patch buf rd fail\n");
return ret;
}
patch_buff_base = rd_patch_addr_cfm.memdata;
patch_addr = start_addr = patch_buff_base;
}
#endif
ret = rwnx_send_dbg_mem_write_req(sdiodev, AIC_PATCH_ADDR(magic_num), AIC_PATCH_MAGIG_NUM);
if (ret) {
printk("0x%x write fail\n", AIC_PATCH_ADDR(magic_num));
return ret;
}
ret = rwnx_send_dbg_mem_write_req(sdiodev, AIC_PATCH_ADDR(magic_num_2), AIC_PATCH_MAGIG_NUM_2);
if (ret) {
printk("0x%x write fail\n", AIC_PATCH_ADDR(magic_num_2));
return ret;
}
ret = rwnx_send_dbg_mem_write_req(sdiodev, AIC_PATCH_ADDR(pair_start), patch_addr);
if (ret) {
printk("0x%x write fail\n", AIC_PATCH_ADDR(pair_start));
return ret;
}
ret = rwnx_send_dbg_mem_write_req(sdiodev, AIC_PATCH_ADDR(pair_count), patch_cnt + adap_patch_cnt);
if (ret) {
printk("0x%x write fail\n", AIC_PATCH_ADDR(pair_count));
return ret;
}
for (cnt = 0; cnt < patch_cnt; cnt++) {
ret = rwnx_send_dbg_mem_write_req(sdiodev, start_addr+8*cnt, patch_tbl_8800d80[cnt][0]+config_base);
if (ret) {
printk("%x write fail\n", start_addr+8*cnt);
return ret;
}
ret = rwnx_send_dbg_mem_write_req(sdiodev, start_addr+8*cnt+4, patch_tbl_8800d80[cnt][1]);
if (ret) {
printk("%x write fail\n", start_addr+8*cnt+4);
return ret;
}
}
if (adap_test){
int tmp_cnt = patch_cnt + adap_patch_cnt;
for (cnt = patch_cnt; cnt < tmp_cnt; cnt++) {
int tbl_idx = cnt - patch_cnt;
ret = rwnx_send_dbg_mem_write_req(sdiodev, start_addr+8*cnt, adaptivity_patch_tbl_8800d80[tbl_idx][0]+config_base);
if(ret) {
printk("%x write fail\n", start_addr+8*cnt);
return ret;
}
ret = rwnx_send_dbg_mem_write_req(sdiodev, start_addr+8*cnt+4, adaptivity_patch_tbl_8800d80[tbl_idx][1]);
if(ret) {
printk("%x write fail\n", start_addr+8*cnt+4);
return ret;
}
}
}
ret = rwnx_send_dbg_mem_write_req(sdiodev, AIC_PATCH_ADDR(block_size[0]), 0);
if (ret) {
printk("block_size[0x%x] write fail: %d\n", AIC_PATCH_ADDR(block_size[0]), ret);
return ret;
}
ret = rwnx_send_dbg_mem_write_req(sdiodev, AIC_PATCH_ADDR(block_size[1]), 0);
if (ret) {
printk("block_size[0x%x] write fail: %d\n", AIC_PATCH_ADDR(block_size[1]), ret);
return ret;
}
ret = rwnx_send_dbg_mem_write_req(sdiodev, AIC_PATCH_ADDR(block_size[2]), 0);
if (ret) {
printk("block_size[0x%x] write fail: %d\n", AIC_PATCH_ADDR(block_size[2]), ret);
return ret;
}
ret = rwnx_send_dbg_mem_write_req(sdiodev, AIC_PATCH_ADDR(block_size[3]), 0);
if (ret) {
printk("block_size[0x%x] write fail: %d\n", AIC_PATCH_ADDR(block_size[3]), ret);
return ret;
}
return 0;
}

View File

@ -0,0 +1,24 @@
#ifndef _AIC8800D80_COMPAT_H_
#define _AIC8800D80_COMPAT_H_
#include "aicsdio.h"
/*typedef u32 (*array2_tbl_t)[2];
typedef uint8_t u8_l;
typedef int8_t s8_l;
typedef bool bool_l;
typedef uint16_t u16_l;
typedef int16_t s16_l;
typedef uint32_t u32_l;
typedef int32_t s32_l;
typedef uint64_t u64_l;*/
int aicbsp_system_config_8800d80(struct aic_sdio_dev *sdiodev);
int aicwifi_sys_config_8800d80(struct aic_sdio_dev *sdiodev);
int aicwifi_patch_config_8800d80(struct aic_sdio_dev *sdiodev);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
#ifndef _AIC8800DC_COMPAT_H_
#define _AIC8800DC_COMPAT_H_
#include "aicsdio.h"
typedef u32 (*array2_tbl_t)[2];
typedef u32 (*array3_tbl_t)[3];
typedef uint8_t u8_l;
typedef int8_t s8_l;
typedef bool bool_l;
typedef uint16_t u16_l;
typedef int16_t s16_l;
typedef uint32_t u32_l;
typedef int32_t s32_l;
typedef uint64_t u64_l;
extern u8 chip_sub_id;
extern u8 chip_mcu_id;
#define FW_PATH_MAX_LEN 200
void aicwf_patch_config_8800dc(struct aic_sdio_dev *rwnx_hw);
void system_config_8800dc(struct aic_sdio_dev *rwnx_hw);
int aicwf_misc_ram_init_8800dc(struct aic_sdio_dev *sdiodev);
#ifdef CONFIG_DPD
int aicwf_dpd_calib_8800dc(struct aic_sdio_dev *sdiodev, rf_misc_ram_lite_t *dpd_res);
int aicwf_dpd_result_apply_8800dc(struct aic_sdio_dev *sdiodev, rf_misc_ram_lite_t *dpd_res);
#ifndef CONFIG_FORCE_DPD_CALIB
int aicwf_dpd_result_load_8800dc(struct aic_sdio_dev *sdiodev, rf_misc_ram_lite_t *dpd_res);
int aicwf_dpd_result_write_8800dc(void *buf, int buf_len);
#endif/* !CONFIG_FORCE_DPD_CALIB */
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,581 @@
/**
******************************************************************************
*
* rwnx_cmds.h
*
* Copyright (C) RivieraWaves 2014-2019
*
******************************************************************************
*/
#ifndef _AIC_BSP_DRIVER_H
#define _AIC_BSP_DRIVER_H
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/module.h>
#include "aic_bsp_export.h"
#define RWNX_80211_CMD_TIMEOUT_MS 3000//500//300
#define RWNX_CMD_FLAG_NONBLOCK BIT(0)
#define RWNX_CMD_FLAG_REQ_CFM BIT(1)
#define RWNX_CMD_FLAG_WAIT_PUSH BIT(2)
#define RWNX_CMD_FLAG_WAIT_ACK BIT(3)
#define RWNX_CMD_FLAG_WAIT_CFM BIT(4)
#define RWNX_CMD_FLAG_DONE BIT(5)
/* ATM IPC design makes it possible to get the CFM before the ACK,
* otherwise this could have simply been a state enum */
#define RWNX_CMD_WAIT_COMPLETE(flags) \
(!(flags & (RWNX_CMD_FLAG_WAIT_ACK | RWNX_CMD_FLAG_WAIT_CFM)))
#define RWNX_CMD_MAX_QUEUED 8
#define IPC_E2A_MSG_PARAM_SIZE 256
#define RWNX_FN_ENTRY_STR ">>> %s()\n", __func__
/* message levels */
#define LOGERROR 0x0001
#define LOGINFO 0x0002
#define LOGTRACE 0x0004
#define LOGDEBUG 0x0008
#define LOGDATA 0x0010
extern int aicwf_dbg_level_bsp;
#define AICWF_LOG "AICWFDBG("
#define AICWFDBG(level, args, arg...) \
do { \
if (aicwf_dbg_level_bsp & level) { \
printk(AICWF_LOG#level")\t" args, ##arg); \
} \
} while (0)
#define RWNX_DBG(fmt, ...) \
do { \
if (aicwf_dbg_level_bsp & LOGTRACE) { \
printk(AICWF_LOG"LOGTRACE)\t"fmt , ##__VA_ARGS__); \
} \
} while (0)
/// Message structure for MSGs from Emb to App
struct ipc_e2a_msg {
u16 id; ///< Message id.
u16 dummy_dest_id;
u16 dummy_src_id;
u16 param_len; ///< Parameter embedded struct length.
u32 pattern; ///< Used to stamp a valid MSG buffer
u32 param[IPC_E2A_MSG_PARAM_SIZE]; ///< Parameter embedded struct. Must be word-aligned.
};
typedef u16 lmac_msg_id_t;
typedef u16 lmac_task_id_t;
struct lmac_msg {
lmac_msg_id_t id; ///< Message id.
lmac_task_id_t dest_id; ///< Destination kernel identifier.
lmac_task_id_t src_id; ///< Source kernel identifier.
u16 param_len; ///< Parameter embedded struct length.
u32 param[]; ///< Parameter embedded struct. Must be word-aligned.
};
#define rwnx_cmd_e2amsg ipc_e2a_msg
#define rwnx_cmd_a2emsg lmac_msg
#define RWNX_CMD_A2EMSG_LEN(m) (sizeof(struct lmac_msg) + m->param_len)
#define RWNX_CMD_E2AMSG_LEN_MAX (IPC_E2A_MSG_PARAM_SIZE * 4)
static inline void put_u16(u8 *buf, u16 data)
{
buf[0] = (u8)(data&0x00ff);
buf[1] = (u8)((data >> 8)&0x00ff);
}
enum rwnx_cmd_mgr_state {
RWNX_CMD_MGR_STATE_DEINIT,
RWNX_CMD_MGR_STATE_INITED,
RWNX_CMD_MGR_STATE_CRASHED,
};
struct rwnx_cmd {
struct list_head list;
lmac_msg_id_t id;
lmac_msg_id_t reqid;
struct rwnx_cmd_a2emsg *a2e_msg;
char *e2a_msg;
u32 tkn;
u16 flags;
struct completion complete;
u32 result;
};
struct aic_sdio_dev;
struct rwnx_cmd;
typedef int (*msg_cb_fct)(struct rwnx_cmd *cmd, struct rwnx_cmd_e2amsg *msg);
struct rwnx_cmd_mgr {
enum rwnx_cmd_mgr_state state;
spinlock_t lock;
u32 next_tkn;
u32 queue_sz;
u32 max_queue_sz;
spinlock_t cb_lock;
void *sdiodev;
struct list_head cmds;
int (*queue)(struct rwnx_cmd_mgr *, struct rwnx_cmd *);
int (*llind)(struct rwnx_cmd_mgr *, struct rwnx_cmd *);
int (*msgind)(struct rwnx_cmd_mgr *, struct rwnx_cmd_e2amsg *, msg_cb_fct);
void (*print)(struct rwnx_cmd_mgr *);
void (*drain)(struct rwnx_cmd_mgr *);
struct work_struct cmdWork;
struct workqueue_struct *cmd_wq;
};
void rwnx_cmd_mgr_init(struct rwnx_cmd_mgr *cmd_mgr);
void rwnx_cmd_mgr_deinit(struct rwnx_cmd_mgr *cmd_mgr);
int cmd_mgr_queue_force_defer(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd);
void rwnx_set_cmd_tx(void *dev, struct lmac_msg *msg, uint len);
enum {
TASK_NONE = (u8) -1,
// MAC Management task.
TASK_MM = 0,
// DEBUG task
TASK_DBG,
/// SCAN task
TASK_SCAN,
/// TDLS task
TASK_TDLS,
/// SCANU task
TASK_SCANU,
/// ME task
TASK_ME,
/// SM task
TASK_SM,
/// APM task
TASK_APM,
/// BAM task
TASK_BAM,
/// MESH task
TASK_MESH,
/// RXU task
TASK_RXU,
// This is used to define the last task that is running on the EMB processor
TASK_LAST_EMB = TASK_RXU,
// nX API task
TASK_API,
TASK_MAX,
};
#define LMAC_FIRST_MSG(task) ((lmac_msg_id_t)((task) << 10))
#define DRV_TASK_ID 100
#define MSG_I(msg) ((msg) & ((1<<10)-1))
#define MSG_T(msg) ((lmac_task_id_t)((msg) >> 10))
enum dbg_msg_tag {
/// Memory read request
DBG_MEM_READ_REQ = LMAC_FIRST_MSG(TASK_DBG),
/// Memory read confirm
DBG_MEM_READ_CFM,
/// Memory write request
DBG_MEM_WRITE_REQ,
/// Memory write confirm
DBG_MEM_WRITE_CFM,
/// Module filter request
DBG_SET_MOD_FILTER_REQ,
/// Module filter confirm
DBG_SET_MOD_FILTER_CFM,
/// Severity filter request
DBG_SET_SEV_FILTER_REQ,
/// Severity filter confirm
DBG_SET_SEV_FILTER_CFM,
/// LMAC/MAC HW fatal error indication
DBG_ERROR_IND,
/// Request to get system statistics
DBG_GET_SYS_STAT_REQ,
/// COnfirmation of system statistics
DBG_GET_SYS_STAT_CFM,
/// Memory block write request
DBG_MEM_BLOCK_WRITE_REQ,
/// Memory block write confirm
DBG_MEM_BLOCK_WRITE_CFM,
/// Start app request
DBG_START_APP_REQ,
/// Start app confirm
DBG_START_APP_CFM,
/// Start npc request
DBG_START_NPC_REQ,
/// Start npc confirm
DBG_START_NPC_CFM,
/// Memory mask write request
DBG_MEM_MASK_WRITE_REQ,
/// Memory mask write confirm
DBG_MEM_MASK_WRITE_CFM,
DBG_RFTEST_CMD_REQ,
DBG_RFTEST_CMD_CFM,
DBG_BINDING_REQ,
DBG_BINDING_CFM,
DBG_BINDING_IND,
DBG_CUSTOM_MSG_REQ,
DBG_CUSTOM_MSG_CFM,
DBG_CUSTOM_MSG_IND,
DBG_GPIO_WRITE_REQ,
DBG_GPIO_WRITE_CFM,
/// Max number of Debug messages
DBG_MAX,
};
#if !defined(CONFIG_M2D_OTA_LZMA_SUPPORT)
#define FW_M2D_OTA_NAME "m2d_ota.bin"
#else
#define FW_M2D_OTA_NAME "m2d_ota_lzma.bin"
#endif
enum {
HOST_START_APP_AUTO = 1,
HOST_START_APP_CUSTOM,
HOST_START_APP_FNCALL = 4,
HOST_START_APP_DUMMY = 5,
};
struct dbg_mem_block_write_req {
u32 memaddr;
u32 memsize;
u32 memdata[1024 / sizeof(u32)];
};
/// Structure containing the parameters of the @ref DBG_MEM_BLOCK_WRITE_CFM message.
struct dbg_mem_block_write_cfm {
u32 wstatus;
};
/// Structure containing the parameters of the @ref DBG_MEM_WRITE_REQ message.
struct dbg_mem_write_req {
u32 memaddr;
u32 memdata;
};
/// Structure containing the parameters of the @ref DBG_MEM_WRITE_CFM message.
struct dbg_mem_write_cfm {
u32 memaddr;
u32 memdata;
};
/// Structure containing the parameters of the @ref DBG_MEM_READ_REQ message.
struct dbg_mem_read_req {
u32 memaddr;
};
/// Structure containing the parameters of the @ref DBG_MEM_READ_CFM message.
struct dbg_mem_read_cfm {
u32 memaddr;
u32 memdata;
};
/// Structure containing the parameters of the @ref DBG_MEM_MASK_WRITE_REQ message.
struct dbg_mem_mask_write_req {
u32 memaddr;
u32 memmask;
u32 memdata;
};
/// Structure containing the parameters of the @ref DBG_MEM_MASK_WRITE_CFM message.
struct dbg_mem_mask_write_cfm {
u32 memaddr;
u32 memdata;
};
/// Structure containing the parameters of the @ref DBG_START_APP_REQ message.
struct dbg_start_app_req {
u32 bootaddr;
u32 boottype;
};
/// Structure containing the parameters of the @ref DBG_START_APP_CFM message.
struct dbg_start_app_cfm {
u32 bootstatus;
};
int aicwf_plat_patch_load_8800dc(struct aic_sdio_dev *sdiodev);
int aicwf_plat_rftest_load_8800dc(struct aic_sdio_dev *sdiodev);
#ifdef CONFIG_DPD
int aicwf_misc_ram_valid_check_8800dc(struct aic_sdio_dev *sdiodev, int *valid_out);
int aicwf_plat_calib_load_8800dc(struct aic_sdio_dev *sdiodev);
#endif
int rwnx_load_firmware(u32 **fw_buf, const char *name, struct device *device);
int aicwf_patch_table_load(struct aic_sdio_dev *rwnx_hw, char *filename);
int rwnx_send_dbg_mem_read_req(struct aic_sdio_dev *sdiodev, u32 mem_addr,
struct dbg_mem_read_cfm *cfm);
int rwnx_send_dbg_mem_block_write_req(struct aic_sdio_dev *sdiodev, u32 mem_addr,
u32 mem_size, u32 *mem_data);
int rwnx_send_dbg_mem_write_req(struct aic_sdio_dev *sdiodev, u32 mem_addr, u32 mem_data);
int rwnx_send_dbg_mem_mask_write_req(struct aic_sdio_dev *sdiodev, u32 mem_addr,
u32 mem_mask, u32 mem_data);
int rwnx_send_dbg_start_app_req(struct aic_sdio_dev *sdiodev, u32 boot_addr, u32 boot_type, struct dbg_start_app_cfm *start_app_cfm);
int rwnx_plat_bin_fw_upload_android(struct aic_sdio_dev *sdiodev, u32 fw_addr, const char *filename);
void rwnx_rx_handle_msg(struct aic_sdio_dev *sdiodev, struct ipc_e2a_msg *msg);
int aicbsp_platform_init(struct aic_sdio_dev *sdiodev);
void aicbsp_platform_deinit(struct aic_sdio_dev *sdiodev);
int aicbsp_driver_fw_init(struct aic_sdio_dev *sdiodev);
#if (defined(CONFIG_DPD) && !defined(CONFIG_FORCE_DPD_CALIB))
int is_file_exist(char* name);
#endif
int aicbsp_resv_mem_init(void);
int aicbsp_resv_mem_deinit(void);
#define AICBSP_FW_PATH CONFIG_AIC_FW_PATH
#define AICBSP_FW_PATH_MAX 200
#define RAM_FMAC_FW_ADDR 0x00120000
#define FW_RAM_ADID_BASE_ADDR 0x00161928
#define FW_RAM_ADID_BASE_ADDR_U03 0x00161928
#define FW_RAM_PATCH_BASE_ADDR 0x00100000
#define RAM_8800DC_U01_ADID_ADDR 0x00101788
#define RAM_8800DC_U02_ADID_ADDR 0x001017d8
#define RAM_8800DC_FW_PATCH_ADDR 0x00184000
#define FW_RESET_START_ADDR 0x40500128
#define FW_RESET_START_VAL 0x40
#define FW_ADID_FLAG_ADDR 0x40500150
#define FW_ADID_FLAG_VAL 0x01
#define FW_RAM_ADID_BASE_ADDR_8800D80 0x002017E0
#define FW_RAM_PATCH_BASE_ADDR_8800D80 0x0020B2B0
#define FW_RAM_ADID_BASE_ADDR_8800D80_U02 0x00201940
#define FW_RAM_PATCH_BASE_ADDR_8800D80_U02 0x0020b43c
#define AICBT_PT_TAG "AICBT_PT_TAG"
/*****************************************************************************
* Addresses within RWNX_ADDR_CPU
*****************************************************************************/
#define RAM_LMAC_FW_ADDR 0x00150000
#define ROM_FMAC_FW_ADDR 0x00010000
#define ROM_FMAC_PATCH_ADDR 0x00180000
#define RWNX_MAC_CALIB_BASE_NAME_8800DC "fmacfw_calib_8800dc"
#define RWNX_MAC_CALIB_NAME_8800DC_U02 RWNX_MAC_CALIB_BASE_NAME_8800DC"_u02.bin"
#ifdef CONFIG_SDIO_BT
#define RWNX_MAC_CALIB_NAME_8800DC_H_U02 RWNX_MAC_CALIB_BASE_NAME_8800DC"_hbt_u02.bin"
#else
#define RWNX_MAC_CALIB_NAME_8800DC_H_U02 RWNX_MAC_CALIB_BASE_NAME_8800DC"_h_u02.bin"
#endif
#ifdef CONFIG_DPD
#define ROM_FMAC_CALIB_ADDR 0x00130000
#ifndef CONFIG_FORCE_DPD_CALIB
#define FW_DPDRESULT_NAME_8800DC "aic_dpdresult_lite_8800dc.bin"
#endif
#endif
#define RWNX_MAC_FW_RF_BASE_NAME_8800DC "lmacfw_rf_8800dc.bin"
#ifdef CONFIG_FOR_IPCOM
#define RWNX_MAC_PATCH_BASE_NAME_8800DC "fmacfw_patch_8800dc_ipc"
#define RWNX_MAC_PATCH_NAME2_8800DC RWNX_MAC_PATCH_BASE_NAME_8800DC".bin"
#else
#define RWNX_MAC_PATCH_BASE_NAME_8800DC "fmacfw_patch_8800dc"
#define RWNX_MAC_PATCH_NAME2_8800DC RWNX_MAC_PATCH_BASE_NAME_8800DC".bin"
#define RWNX_MAC_PATCH_NAME2_8800DC_U02 RWNX_MAC_PATCH_BASE_NAME_8800DC"_u02.bin"
#ifdef CONFIG_SDIO_BT
#define RWNX_MAC_PATCH_NAME2_8800DC_H_U02 RWNX_MAC_PATCH_BASE_NAME_8800DC"_hbt_u02.bin"
#else
#define RWNX_MAC_PATCH_NAME2_8800DC_H_U02 RWNX_MAC_PATCH_BASE_NAME_8800DC"_h_u02.bin"
#endif
#endif
#define RWNX_MAC_PATCH_TABLE_NAME_8800DC "fmacfw_patch_tbl_8800dc"
#define RWNX_MAC_PATCH_TABLE_8800DC RWNX_MAC_PATCH_TABLE_NAME_8800DC ".bin"
#define RWNX_MAC_PATCH_TABLE_8800DC_U02 RWNX_MAC_PATCH_TABLE_NAME_8800DC "_u02.bin"
#ifdef CONFIG_SDIO_BT
#define RWNX_MAC_PATCH_TABLE_8800DC_H_U02 RWNX_MAC_PATCH_TABLE_NAME_8800DC "_hbt_u02.bin"
#else
#define RWNX_MAC_PATCH_TABLE_8800DC_H_U02 RWNX_MAC_PATCH_TABLE_NAME_8800DC "_h_u02.bin"
#endif
#define RWNX_MAC_RF_PATCH_BASE_NAME_8800DC "fmacfw_rf_patch_8800dc"
#define RWNX_MAC_RF_PATCH_NAME_8800DC RWNX_MAC_RF_PATCH_BASE_NAME_8800DC".bin"
#define FW_USERCONFIG_NAME_8800DC "aic_userconfig_8800dc.txt"
enum {
FW_NORMAL_MODE = 0,
FW_RFTEST_MODE = 1,
FW_BLE_SCAN_WAKEUP_MODE = 2,
FW_M2D_OTA_MODE = 3,
FW_DPDCALIB_MODE = 4,
FW_BLE_SCAN_AD_FILTER_MODE = 5,
};
enum aicbt_patch_table_type {
AICBT_PT_INF = 0x00,
AICBT_PT_TRAP = 0x1,
AICBT_PT_B4,
AICBT_PT_BTMODE,
AICBT_PT_PWRON,
AICBT_PT_AF,
AICBT_PT_VER,
};
enum aicbt_btport_type {
AICBT_BTPORT_NULL,
AICBT_BTPORT_MB,
AICBT_BTPORT_UART,
};
/* btmode
* used for force bt mode,if not AICBSP_MODE_NULL
* efuse valid and vendor_info will be invalid, even has beed set valid
*/
enum aicbt_btmode_type {
AICBT_BTMODE_BT_ONLY_SW = 0x0, // bt only mode with switch
AICBT_BTMODE_BT_WIFI_COMBO, // wifi/bt combo mode
AICBT_BTMODE_BT_ONLY, // bt only mode without switch
AICBT_BTMODE_BT_ONLY_TEST, // bt only test mode
AICBT_BTMODE_BT_WIFI_COMBO_TEST, // wifi/bt combo test mode
AICBT_BTMODE_BT_ONLY_COANT, // bt only mode with no external switch
AICBT_MODE_NULL = 0xFF, // invalid value
};
/* uart_baud
* used for config uart baud when btport set to uart,
* otherwise meaningless
*/
enum aicbt_uart_baud_type {
AICBT_UART_BAUD_115200 = 115200,
AICBT_UART_BAUD_921600 = 921600,
AICBT_UART_BAUD_1_5M = 1500000,
AICBT_UART_BAUD_3_25M = 3250000,
};
enum aicbt_uart_flowctrl_type {
AICBT_UART_FLOWCTRL_DISABLE = 0x0, // uart without flow ctrl
AICBT_UART_FLOWCTRL_ENABLE, // uart with flow ctrl
};
enum aicbsp_cpmode_type {
AICBSP_CPMODE_WORK,
AICBSP_CPMODE_TEST,
AICBSP_CPMODE_MAX,
};
enum chip_rev {
CHIP_REV_U01 = 1,
CHIP_REV_U02 = 3,
CHIP_REV_U03 = 7,
CHIP_REV_U04 = 7,
};
#define AIC_M2D_OTA_INFO_ADDR 0x88000020
#define AIC_M2D_OTA_DATA_ADDR 0x88000040
#if !defined(CONFIG_M2D_OTA_LZMA_SUPPORT)
#define AIC_M2D_OTA_FLASH_ADDR 0x08004000
#define AIC_M2D_OTA_CODE_START_ADDR (AIC_M2D_OTA_FLASH_ADDR + 0x0188)
#define AIC_M2D_OTA_VER_ADDR (AIC_M2D_OTA_FLASH_ADDR + 0x018C)
#else
#define AIC_M2D_OTA_FLASH_ADDR 0x08005000
#define AIC_M2D_OTA_CODE_START_ADDR (AIC_M2D_OTA_FLASH_ADDR + 0x1188)
#define AIC_M2D_OTA_VER_ADDR (AIC_M2D_OTA_FLASH_ADDR + 0x0010)
#endif
///aic bt tx pwr lvl :lsb->msb: first byte, min pwr lvl; second byte, max pwr lvl;
///pwr lvl:20(min), 30 , 40 , 50 , 60(max)
#define AICBT_TXPWR_LVL 0x00006020
#define AICBT_TXPWR_LVL_8800dc 0x00006f2f
#define AICBT_TXPWR_LVL_8800d80 0x00006f2f
#define AICBSP_HWINFO_DEFAULT (-1)
#define AICBSP_CPMODE_DEFAULT AICBSP_CPMODE_WORK
#define AICBSP_FWLOG_EN_DEFAULT 0
#define AICBT_BTMODE_DEFAULT_8800d80 AICBT_BTMODE_BT_ONLY_COANT
#define AICBT_BTMODE_DEFAULT AICBT_BTMODE_BT_ONLY_SW
#ifdef CONFIG_SDIO_BT
#define AICBT_BTPORT_DEFAULT AICBT_BTPORT_MB
#else
#define AICBT_BTPORT_DEFAULT AICBT_BTPORT_UART
#endif
#define AICBT_UART_BAUD_DEFAULT AICBT_UART_BAUD_1_5M
#define AICBT_UART_FC_DEFAULT AICBT_UART_FLOWCTRL_ENABLE
#define AICBT_LPM_ENABLE_DEFAULT 0
#define AICBT_TXPWR_LVL_DEFAULT AICBT_TXPWR_LVL
#define AICBT_TXPWR_LVL_DEFAULT_8800dc AICBT_TXPWR_LVL_8800dc
#define AICBT_TXPWR_LVL_DEFAULT_8800d80 AICBT_TXPWR_LVL_8800d80
#define FEATURE_SDIO_CLOCK 50000000 // 0: default, other: target clock rate
#define FEATURE_SDIO_CLOCK_V3 150000000 // 0: default, other: target clock rate
#define FEATURE_SDIO_PHASE 2 // 0: default, 2: 180°
struct aicbt_patch_table {
char *name;
uint32_t type;
uint32_t *data;
uint32_t len;
struct aicbt_patch_table *next;
};
struct aicbt_info_t {
uint32_t btmode;
uint32_t btport;
uint32_t uart_baud;
uint32_t uart_flowctrl;
uint32_t lpm_enable;
uint32_t txpwr_lvl;
};
struct aicbt_patch_info_t {
uint32_t info_len;
uint32_t adid_addrinf;
uint32_t addr_adid;
uint32_t patch_addrinf;
uint32_t addr_patch;
uint32_t reset_addr;
uint32_t reset_val;
uint32_t adid_flag_addr;
uint32_t adid_flag;
};
struct aicbsp_firmware {
const char *desc;
const char *bt_adid;
const char *bt_patch;
const char *bt_table;
const char *wl_fw;
};
struct aicbsp_info_t {
int hwinfo;
int hwinfo_r;
uint32_t cpmode;
uint32_t chip_rev;
bool fwlog_en;
uint8_t irqf;
};
extern struct aicbsp_info_t aicbsp_info;
extern struct mutex aicbsp_power_lock;
extern const struct aicbsp_firmware *aicbsp_firmware_list;
extern const struct aicbsp_firmware fw_u02[];
extern const struct aicbsp_firmware fw_u03[];
extern const struct aicbsp_firmware fw_8800dc_u01[];
extern const struct aicbsp_firmware fw_8800dc_u02[];
extern const struct aicbsp_firmware fw_8800dc_h_u02[];
extern const struct aicbsp_firmware fw_8800d80_u01[];
extern const struct aicbsp_firmware fw_8800d80_u02[];
#endif

View File

@ -0,0 +1,65 @@
#ifndef __AIC_BSP_EXPORT_H
#define __AIC_BSP_EXPORT_H
enum aicbsp_subsys {
AIC_BLUETOOTH,
AIC_WIFI,
};
enum aicbsp_pwr_state {
AIC_PWR_OFF,
AIC_PWR_ON,
};
enum skb_buff_id {
AIC_RESV_MEM_TXDATA,
};
struct skb_buff_pool {
uint32_t id;
uint32_t size;
const char *name;
uint8_t used;
struct sk_buff *skb;
};
struct aicbsp_feature_t {
int hwinfo;
uint32_t sdio_clock;
uint8_t sdio_phase;
bool fwlog_en;
uint8_t irqf;
};
#ifdef CONFIG_DPD
typedef struct {
uint32_t bit_mask[3];
uint32_t reserved;
uint32_t dpd_high[96];
uint32_t dpd_11b[96];
uint32_t dpd_low[96];
uint32_t idac_11b[48];
uint32_t idac_high[48];
uint32_t idac_low[48];
uint32_t loft_res[18];
uint32_t rx_iqim_res[16];
} rf_misc_ram_t;
typedef struct {
uint32_t bit_mask[4];
uint32_t dpd_high[96];
uint32_t loft_res[18];
} rf_misc_ram_lite_t;
#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
#define DPD_RESULT_SIZE_8800DC sizeof(rf_misc_ram_lite_t)
extern rf_misc_ram_lite_t dpd_res;
#endif
int aicbsp_set_subsys(int, int);
int aicbsp_get_feature(struct aicbsp_feature_t *feature, char *fw_path);
struct sk_buff *aicbsp_resv_mem_alloc_skb(unsigned int length, uint32_t id);
void aicbsp_resv_mem_kfree_skb(struct sk_buff *skb, uint32_t id);
#endif

View File

@ -0,0 +1,393 @@
#include <linux/module.h>
#include <linux/inetdevice.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/platform_device.h>
#include "aic_bsp_driver.h"
#include "rwnx_version_gen.h"
#include "aicwf_txq_prealloc.h"
#define DRV_DESCRIPTION "AIC BSP"
#define DRV_COPYRIGHT "Copyright(c) 2015-2020 AICSemi"
#define DRV_AUTHOR "AICSemi"
#define DRV_VERS_MOD "1.0"
int aicwf_dbg_level_bsp = LOGERROR|LOGINFO|LOGDEBUG|LOGTRACE;
static struct platform_device *aicbsp_pdev;
const struct aicbsp_firmware *aicbsp_firmware_list = fw_u02;
const struct aicbsp_firmware fw_u02[] = {
[AICBSP_CPMODE_WORK] = {
.desc = "normal work mode(sdio u02)",
.bt_adid = "fw_adid.bin",
.bt_patch = "fw_patch.bin",
.bt_table = "fw_patch_table.bin",
#ifdef CONFIG_SDIO_BT
.wl_fw = "fmacfwbt.bin"
#else
.wl_fw = "fmacfw.bin"
#endif
},
[AICBSP_CPMODE_TEST] = {
.desc = "rf test mode(sdio u02)",
.bt_adid = "fw_adid.bin",
.bt_patch = "fw_patch.bin",
.bt_table = "fw_patch_table.bin",
.wl_fw = "fmacfw_rf.bin"
},
};
const struct aicbsp_firmware fw_u03[] = {
[AICBSP_CPMODE_WORK] = {
.desc = "normal work mode(sdio u03/u04)",
.bt_adid = "fw_adid_u03.bin",
.bt_patch = "fw_patch_u03.bin",
.bt_table = "fw_patch_table_u03.bin",
#ifdef CONFIG_MCU_MESSAGE
.wl_fw = "fmacfw_8800m_custmsg.bin"
#elif defined(CONFIG_SDIO_BT)
.wl_fw = "fmacfwbt.bin"
#else
.wl_fw = "fmacfw.bin"
#endif
},
[AICBSP_CPMODE_TEST] = {
.desc = "rf test mode(sdio u03/u04)",
.bt_adid = "fw_adid_u03.bin",
.bt_patch = "fw_patch_u03.bin",
.bt_table = "fw_patch_table_u03.bin",
.wl_fw = "fmacfw_rf.bin"
},
};
const struct aicbsp_firmware fw_8800dc_u01[] = {
[AICBSP_CPMODE_WORK] = {
.desc = "normal work mode(sdio u01)",
.bt_adid = "fw_adid_8800dc.bin",
.bt_patch = "fw_patch_8800dc.bin",
.bt_table = "fw_patch_table_8800dc.bin",
.wl_fw = "fmacfw_8800dc.bin"
},
[AICBSP_CPMODE_TEST] = {
.desc = "rf test mode(sdio u01)",
.bt_adid = "fw_adid_8800dc.bin",
.bt_patch = "fw_patch_8800dc.bin",
.bt_table = "fw_patch_table_8800dc.bin",
.wl_fw = "fmacfw_rf_8800dc.bin"
},
};
const struct aicbsp_firmware fw_8800dc_u02[] = {
[AICBSP_CPMODE_WORK] = {
.desc = "normal work mode(8800dc sdio u02)",
.bt_adid = "fw_adid_8800dc_u02.bin",
.bt_patch = "fw_patch_8800dc_u02.bin",
.bt_table = "fw_patch_table_8800dc_u02.bin",
.wl_fw = "fmacfw_patch_8800dc_u02.bin"
},
[AICBSP_CPMODE_TEST] = {
.desc = "rf test mode(8800dc sdio u02)",
.bt_adid = "fw_adid_8800dc_u02.bin",
.bt_patch = "fw_patch_8800dc_u02.bin",
.bt_table = "fw_patch_table_8800dc_u02.bin",
.wl_fw = "lmacfw_rf_8800dc.bin" //u01,u02 lmacfw load same bin
},
};
const struct aicbsp_firmware fw_8800dc_h_u02[] = {
[AICBSP_CPMODE_WORK] = {
.desc = "normal work mode(8800dc_h sdio u02)",
.bt_adid = "fw_adid_8800dc_u02h.bin",
.bt_patch = "fw_patch_8800dc_u02h.bin",
.bt_table = "fw_patch_table_8800dc_u02h.bin",
.wl_fw = "fmacfw_patch_8800dc_h_u02.bin"
},
[AICBSP_CPMODE_TEST] = {
.desc = "rf test mode(8800dc_h sdio u02)",
.bt_adid = "fw_adid_8800dc_u02h.bin",
.bt_patch = "fw_patch_8800dc_u02h.bin",
.bt_table = "fw_patch_table_8800dc_u02h.bin",
.wl_fw = "lmacfw_rf_8800dc.bin" //u01,u02 lmacfw load same bin
},
};
const struct aicbsp_firmware fw_8800d80_u01[] = {
[AICBSP_CPMODE_WORK] = {
.desc = "normal work mode(8800d80 sdio u01)",
.bt_adid = "fw_adid_8800d80.bin",
.bt_patch = "fw_patch_8800d80.bin",
.bt_table = "fw_patch_table_8800d80.bin",
.wl_fw = "fmacfw_8800d80.bin"
},
[AICBSP_CPMODE_TEST] = {
.desc = "rf test mode(8800d80 sdio u01)",
.bt_adid = "fw_adid_8800d80.bin",
.bt_patch = "fw_patch_8800d80.bin",
.bt_table = "fw_patch_table_8800d80.bin",
.wl_fw = "lmacfw_rf_8800d80.bin"
},
};
const struct aicbsp_firmware fw_8800d80_u02[] = {
[AICBSP_CPMODE_WORK] = {
.desc = "normal work mode(8800d80 sdio u02)",
.bt_adid = "fw_adid_8800d80_u02.bin",
.bt_patch = "fw_patch_8800d80_u02.bin",
.bt_table = "fw_patch_table_8800d80_u02.bin",
#ifdef CONFIG_SDIO_BT
.wl_fw = "fmacfwbt_8800d80_u02.bin"
#else
.wl_fw = "fmacfw_8800d80_u02.bin"
#endif
},
[AICBSP_CPMODE_TEST] = {
.desc = "rf test mode(8800d80 sdio u02)",
.bt_adid = "fw_adid_8800d80_u02.bin",
.bt_patch = "fw_patch_8800d80_u02.bin",
.bt_table = "fw_patch_table_8800d80_u02.bin",
.wl_fw = "lmacfw_rf_8800d80_u02.bin"
},
};
struct aicbsp_info_t aicbsp_info = {
.hwinfo_r = AICBSP_HWINFO_DEFAULT,
.hwinfo = AICBSP_HWINFO_DEFAULT,
.cpmode = AICBSP_CPMODE_DEFAULT,
.fwlog_en = AICBSP_FWLOG_EN_DEFAULT,
#ifdef CONFIG_IRQ_FALL
.irqf = 1,
#else
.irqf = 0,
#endif
};
struct mutex aicbsp_power_lock;
static struct platform_driver aicbsp_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "aic_bsp",
},
//.probe = aicbsp_probe,
//.remove = aicbsp_remove,
};
static ssize_t cpmode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t count = 0;
uint8_t i = 0;
count += sprintf(&buf[count], "Support mode value:\n");
for (i = 0; i < AICBSP_CPMODE_MAX; i++) {
if (aicbsp_firmware_list[i].desc)
count += sprintf(&buf[count], " %2d: %s\n", i, aicbsp_firmware_list[i].desc);
}
count += sprintf(&buf[count], "Current: %d, firmware info:\n", aicbsp_info.cpmode);
count += sprintf(&buf[count], " BT ADID : %s\n", aicbsp_firmware_list[aicbsp_info.cpmode].bt_adid);
count += sprintf(&buf[count], " BT PATCH: %s\n", aicbsp_firmware_list[aicbsp_info.cpmode].bt_patch);
count += sprintf(&buf[count], " BT TABLE: %s\n", aicbsp_firmware_list[aicbsp_info.cpmode].bt_table);
count += sprintf(&buf[count], " WIFI FW : %s\n", aicbsp_firmware_list[aicbsp_info.cpmode].wl_fw);
return count;
}
static ssize_t cpmode_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long val;
int err = kstrtoul(buf, 0, &val);
if (err)
return err;
if (val >= AICBSP_CPMODE_MAX) {
pr_err("mode value must less than %d\n", AICBSP_CPMODE_MAX);
return -EINVAL;
}
aicbsp_info.cpmode = val;
printk("%s, set mode to: %lu[%s] done\n", __func__, val, aicbsp_firmware_list[val].desc);
return count;
}
static ssize_t hwinfo_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t count = 0;
count += sprintf(&buf[count], "chip hw rev: ");
if (aicbsp_info.hwinfo_r < 0)
count += sprintf(&buf[count], "-1(not avalible)\n");
else
count += sprintf(&buf[count], "0x%02X\n", aicbsp_info.chip_rev);
count += sprintf(&buf[count], "hwinfo read: ");
if (aicbsp_info.hwinfo_r < 0)
count += sprintf(&buf[count], "%d(not avalible), ", aicbsp_info.hwinfo_r);
else
count += sprintf(&buf[count], "0x%02X, ", aicbsp_info.hwinfo_r);
if (aicbsp_info.hwinfo < 0)
count += sprintf(&buf[count], "set: %d(not avalible)\n", aicbsp_info.hwinfo);
else
count += sprintf(&buf[count], "set: 0x%02X\n", aicbsp_info.hwinfo);
return count;
}
static ssize_t hwinfo_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
long val;
int err = kstrtol(buf, 0, &val);
if (err) {
pr_err("invalid input\n");
return err;
}
if ((val == -1) || (val >= 0 && val <= 0xFF)) {
aicbsp_info.hwinfo = val;
} else {
pr_err("invalid values\n");
return -EINVAL;
}
return count;
}
static ssize_t fwdebug_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t count = 0;
count += sprintf(&buf[count], "fw log status: %s\n",
aicbsp_info.fwlog_en ? "on" : "off");
return count;
}
static ssize_t fwdebug_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
long val;
int err = kstrtol(buf, 0, &val);
if (err) {
pr_err("invalid input\n");
return err;
}
if (val > 1 || val < 0) {
pr_err("must be 0 or 1\n");
return -EINVAL;
}
aicbsp_info.fwlog_en = val;
return count;
}
static DEVICE_ATTR(cpmode, S_IRUGO | S_IWUSR,
cpmode_show, cpmode_store);
static DEVICE_ATTR(hwinfo, S_IRUGO | S_IWUSR,
hwinfo_show, hwinfo_store);
static DEVICE_ATTR(fwdebug, S_IRUGO | S_IWUSR,
fwdebug_show, fwdebug_store);
static struct attribute *aicbsp_attributes[] = {
&dev_attr_cpmode.attr,
&dev_attr_hwinfo.attr,
&dev_attr_fwdebug.attr,
NULL,
};
static struct attribute_group aicbsp_attribute_group = {
.name = "aicbsp_info",
.attrs = aicbsp_attributes,
};
int testmode = AICBSP_CPMODE_DEFAULT;
int adap_test = 0;
module_param(testmode, int, 0660);
module_param(adap_test, int, 0660);
static int __init aicbsp_init(void)
{
int ret;
printk("%s\n", __func__);
printk("RELEASE_DATE:%s\r\n", RELEASE_DATE);
aicbsp_info.cpmode = testmode;
aicbsp_resv_mem_init();
ret = platform_driver_register(&aicbsp_driver);
if (ret) {
pr_err("register platform driver failed: %d\n", ret);
return ret;
}
aicbsp_pdev = platform_device_alloc("aic-bsp", -1);
ret = platform_device_add(aicbsp_pdev);
if (ret) {
pr_err("register platform device failed: %d\n", ret);
return ret;
}
ret = sysfs_create_group(&(aicbsp_pdev->dev.kobj), &aicbsp_attribute_group);
if (ret) {
pr_err("register sysfs create group failed!\n");
return ret;
}
mutex_init(&aicbsp_power_lock);
#if defined CONFIG_PLATFORM_ROCKCHIP || defined CONFIG_PLATFORM_ROCKCHIP2
aicbsp_set_subsys(AIC_BLUETOOTH, AIC_PWR_ON);
#endif
return 0;
}
void aicbsp_sdio_exit(void);
extern struct aic_sdio_dev *aicbsp_sdiodev;
static void __exit aicbsp_exit(void)
{
#if defined CONFIG_PLATFORM_ROCKCHIP || defined CONFIG_PLATFORM_ROCKCHIP2
if(aicbsp_sdiodev){
aicbsp_sdio_exit();
}
#endif
sysfs_remove_group(&(aicbsp_pdev->dev.kobj), &aicbsp_attribute_group);
platform_device_del(aicbsp_pdev);
platform_driver_unregister(&aicbsp_driver);
mutex_destroy(&aicbsp_power_lock);
aicbsp_resv_mem_deinit();
#ifdef CONFIG_PREALLOC_TXQ
aicwf_prealloc_txq_free();
#endif
printk("%s\n", __func__);
}
module_init(aicbsp_init);
module_exit(aicbsp_exit);
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERS_MOD);
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,148 @@
/**
* aicwf_sdio.h
*
* SDIO function declarations
*
* Copyright (C) AICSemi 2018-2020
*/
#ifndef _AICWF_SDMMC_H_
#define _AICWF_SDMMC_H_
#ifdef AICWF_SDIO_SUPPORT
#include <linux/skbuff.h>
#include <linux/if_ether.h>
#include <linux/ieee80211.h>
#include <linux/semaphore.h>
#include "aic_bsp_driver.h"
#define AICBSP_SDIO_NAME "aicbsp_sdio"
#define SDIOWIFI_FUNC_BLOCKSIZE 512
#define SDIO_VENDOR_ID_AIC 0x8800
#define SDIO_DEVICE_ID_AIC 0x0001
#define SDIOWIFI_BYTEMODE_LEN_REG 0x02
#define SDIOWIFI_INTR_CONFIG_REG 0x04
#define SDIOWIFI_SLEEP_REG 0x05
#define SDIOWIFI_WAKEUP_REG 0x09
#define SDIOWIFI_FLOW_CTRL_REG 0x0A
#define SDIOWIFI_REGISTER_BLOCK 0x0B
#define SDIOWIFI_BYTEMODE_ENABLE_REG 0x11
#define SDIOWIFI_BLOCK_CNT_REG 0x12
#define SDIOWIFI_FLOWCTRL_MASK_REG 0x7F
#define SDIOWIFI_WR_FIFO_ADDR 0x07
#define SDIOWIFI_RD_FIFO_ADDR 0x08
#define SDIOWIFI_INTR_ENABLE_REG_V3 0x00
#define SDIOWIFI_INTR_PENDING_REG_V3 0x01
#define SDIOWIFI_INTR_TO_DEVICE_REG_V3 0x02
#define SDIOWIFI_FLOW_CTRL_Q1_REG_V3 0x03
#define SDIOWIFI_MISC_INT_STATUS_REG_V3 0x04
#define SDIOWIFI_BYTEMODE_LEN_REG_V3 0x05
#define SDIOWIFI_BYTEMODE_LEN_MSB_REG_V3 0x06
#define SDIOWIFI_BYTEMODE_ENABLE_REG_V3 0x07
#define SDIOWIFI_MISC_CTRL_REG_V3 0x08
#define SDIOWIFI_FLOW_CTRL_Q2_REG_V3 0x09
#define SDIOWIFI_CLK_TEST_RESULT_REG_V3 0x0A
#define SDIOWIFI_RD_FIFO_ADDR_V3 0x0F
#define SDIOWIFI_WR_FIFO_ADDR_V3 0x10
#define SDIOCLK_FREE_RUNNING_BIT (1 << 6)
#define SDIOWIFI_PWR_CTRL_INTERVAL 30
#define FLOW_CTRL_RETRY_COUNT 50
#define BUFFER_SIZE 1536
#define TAIL_LEN 4
#define TXQLEN (2048*4)
#define SDIO_SLEEP_ST 0
#define SDIO_ACTIVE_ST 1
typedef enum {
SDIO_TYPE_DATA = 0X00,
SDIO_TYPE_CFG = 0X10,
SDIO_TYPE_CFG_CMD_RSP = 0X11,
SDIO_TYPE_CFG_DATA_CFM = 0X12
} sdio_type;
enum AICWF_IC{
PRODUCT_ID_AIC8801 = 0,
PRODUCT_ID_AIC8800DC,
PRODUCT_ID_AIC8800DW,
PRODUCT_ID_AIC8800D80
};
struct aic_sdio_reg {
u8 bytemode_len_reg;
u8 intr_config_reg;
u8 sleep_reg;
u8 wakeup_reg;
u8 flow_ctrl_reg;
u8 flowctrl_mask_reg;
u8 register_block;
u8 bytemode_enable_reg;
u8 block_cnt_reg;
u8 misc_int_status_reg;
u8 rd_fifo_addr;
u8 wr_fifo_addr;
};
struct aic_sdio_dev {
struct rwnx_cmd_mgr cmd_mgr;
struct sdio_func *func;
struct sdio_func *func_msg;
struct device *dev;
struct aicwf_bus *bus_if;
struct aicwf_rx_priv *rx_priv;
struct aicwf_tx_priv *tx_priv;
u32 state;
#if defined(CONFIG_SDIO_PWRCTRL)
//for sdio pwr ctrl
struct timer_list timer;
uint active_duration;
struct completion pwrctrl_trgg;
struct task_struct *pwrctl_tsk;
spinlock_t pwrctl_lock;
struct semaphore pwrctl_wakeup_sema;
#endif
u16 chipid;
u32 fw_version_uint;
struct aic_sdio_reg sdio_reg;
void (*sdio_hal_irqhandler) (struct sdio_func *func);
};
void *aicbsp_get_drvdata(void *args);
int aicwf_sdio_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val);
void aicwf_sdio_hal_irqhandler(struct sdio_func *func);
void aicwf_sdio_hal_irqhandler_func2(struct sdio_func *func);
#if defined(CONFIG_SDIO_PWRCTRL)
void aicwf_sdio_pwrctl_timer(struct aic_sdio_dev *sdiodev, uint duration);
int aicwf_sdio_pwr_stctl(struct aic_sdio_dev *sdiodev, uint target);
#endif
void aicwf_sdio_reg_init(struct aic_sdio_dev *sdiodev);
int aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev);
int aicwf_sdiov3_func_init(struct aic_sdio_dev *sdiodev);
void aicwf_sdio_func_deinit(struct aic_sdio_dev *sdiodev);
int aicwf_sdio_flow_ctrl(struct aic_sdio_dev *sdiodev);
int aicwf_sdio_recv_pkt(struct aic_sdio_dev *sdiodev, struct sk_buff *skbbuf, u32 size, u8 msg);
int aicwf_sdio_send_pkt(struct aic_sdio_dev *sdiodev, u8 *buf, uint count);
void *aicwf_sdio_bus_init(struct aic_sdio_dev *sdiodev);
void aicwf_sdio_release(struct aic_sdio_dev *sdiodev);
void aicbsp_sdio_exit(void);
int aicbsp_sdio_init(void);
void aicbsp_sdio_release(struct aic_sdio_dev *sdiodev);
int aicwf_sdio_txpkt(struct aic_sdio_dev *sdiodev, struct sk_buff *pkt);
int aicwf_sdio_bustx_thread(void *data);
int aicwf_sdio_busrx_thread(void *data);
int aicwf_sdio_aggr(struct aicwf_tx_priv *tx_priv, struct sk_buff *pkt);
int aicwf_sdio_send(struct aicwf_tx_priv *tx_priv);
void aicwf_sdio_aggr_send(struct aicwf_tx_priv *tx_priv);
void aicwf_sdio_aggrbuf_reset(struct aicwf_tx_priv *tx_priv);
extern void aicwf_hostif_ready(void);
int aicwf_process_rxframes(struct aicwf_rx_priv *rx_priv);
uint8_t crc8_ponl_107(uint8_t *p_buffer, uint16_t cal_size);
#endif /* AICWF_SDIO_SUPPORT */
#endif /*_AICWF_SDMMC_H_*/

View File

@ -0,0 +1,465 @@
/**
* aicwf_bus.c
*
* bus function declarations
*
* Copyright (C) AICSemi 2018-2020
*/
#include <linux/kthread.h>
#include <linux/netdevice.h>
#include <linux/printk.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/semaphore.h>
#include <linux/debugfs.h>
#include <linux/atomic.h>
#include <linux/vmalloc.h>
#include "aicsdio_txrxif.h"
#include "aic_bsp_driver.h"
int aicwf_bus_init(uint bus_hdrlen, struct device *dev)
{
int ret = 0;
struct aicwf_bus *bus_if;
if (!dev) {
txrx_err("device not found\n");
return -1;
}
bus_if = dev_get_drvdata(dev);
bus_if->cmd_buf = kzalloc(CMD_BUF_MAX, GFP_KERNEL);
if (!bus_if->cmd_buf) {
ret = -ENOMEM;
txrx_err("proto_attach failed\n");
goto fail;
}
memset(bus_if->cmd_buf, '\0', CMD_BUF_MAX);
init_completion(&bus_if->bustx_trgg);
init_completion(&bus_if->busrx_trgg);
#ifdef AICWF_SDIO_SUPPORT
bus_if->bustx_thread = kthread_run(aicwf_sdio_bustx_thread, (void *)bus_if, "aicwf_bustx_thread");
bus_if->busrx_thread = kthread_run(aicwf_sdio_busrx_thread, (void *)bus_if->bus_priv.sdio->rx_priv, "aicwf_busrx_thread");
#endif
if (IS_ERR(bus_if->bustx_thread)) {
bus_if->bustx_thread = NULL;
txrx_err("aicwf_bustx_thread run fail\n");
ret = -1;
goto fail;
}
if (IS_ERR(bus_if->busrx_thread)) {
bus_if->busrx_thread = NULL;
txrx_err("aicwf_bustx_thread run fail\n");
ret = -1;
goto fail;
}
return ret;
fail:
aicwf_bus_deinit(dev);
return ret;
}
void aicwf_bus_deinit(struct device *dev)
{
struct aicwf_bus *bus_if;
struct aic_sdio_dev *sdiodev;
if (!dev) {
txrx_err("device not found\n");
return;
}
sdio_dbg("%s", __func__);
bus_if = aicbsp_get_drvdata(dev);
aicwf_bus_stop(bus_if);
sdiodev = bus_if->bus_priv.sdio;
if (bus_if->cmd_buf) {
kfree(bus_if->cmd_buf);
bus_if->cmd_buf = NULL;
}
if (bus_if->bustx_thread) {
complete_all(&bus_if->bustx_trgg);
kthread_stop(bus_if->bustx_thread);
bus_if->bustx_thread = NULL;
}
}
void aicwf_frame_tx(void *dev, struct sk_buff *skb)
{
struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *)dev;
aicwf_bus_txdata(sdiodev->bus_if, skb);
}
struct aicwf_tx_priv *aicwf_tx_init(void *arg)
{
struct aicwf_tx_priv *tx_priv;
tx_priv = kzalloc(sizeof(struct aicwf_tx_priv), GFP_KERNEL);
if (!tx_priv)
return NULL;
tx_priv->sdiodev = (struct aic_sdio_dev *)arg;
atomic_set(&tx_priv->aggr_count, 0);
tx_priv->aggr_buf = dev_alloc_skb(MAX_AGGR_TXPKT_LEN);
if (!tx_priv->aggr_buf) {
txrx_err("Alloc bus->txdata_buf failed!\n");
kfree(tx_priv);
return NULL;
}
tx_priv->head = tx_priv->aggr_buf->data;
tx_priv->tail = tx_priv->aggr_buf->data;
return tx_priv;
}
void aicwf_tx_deinit(struct aicwf_tx_priv *tx_priv)
{
if (tx_priv && tx_priv->aggr_buf)
dev_kfree_skb(tx_priv->aggr_buf);
kfree(tx_priv);
//tx_priv = NULL;
}
static bool aicwf_another_ptk(struct sk_buff *skb)
{
u8 *data;
u16 aggr_len = 0;
if (skb->data == NULL || skb->len == 0) {
return false;
}
data = skb->data;
aggr_len = (*skb->data | (*(skb->data + 1) << 8));
if (aggr_len == 0) {
return false;
}
return true;
}
int aicwf_process_rxframes(struct aicwf_rx_priv *rx_priv)
{
int ret = 0;
unsigned long flags = 0;
struct sk_buff *skb = NULL;
u16 pkt_len = 0;
struct sk_buff *skb_inblock = NULL;
u16 aggr_len = 0, adjust_len = 0;
u8 *data = NULL;
while (1) {
spin_lock_irqsave(&rx_priv->rxqlock, flags);
if (aicwf_is_framequeue_empty(&rx_priv->rxq)) {
spin_unlock_irqrestore(&rx_priv->rxqlock, flags);
break;
}
skb = aicwf_frame_dequeue(&rx_priv->rxq);
spin_unlock_irqrestore(&rx_priv->rxqlock, flags);
if (skb == NULL) {
txrx_err("skb_error\r\n");
break;
}
while (aicwf_another_ptk(skb)) {
data = skb->data;
pkt_len = (*skb->data | (*(skb->data + 1) << 8));
if ((skb->data[2] & SDIO_TYPE_CFG) != SDIO_TYPE_CFG) { // type : data
aggr_len = pkt_len + RX_HWHRD_LEN;
if (aggr_len & (RX_ALIGNMENT - 1))
adjust_len = roundup(aggr_len, RX_ALIGNMENT);
else
adjust_len = aggr_len;
skb_inblock = __dev_alloc_skb(aggr_len + CCMP_OR_WEP_INFO, GFP_KERNEL);//8 is for ccmp mic or wep icv
if (skb_inblock == NULL) {
txrx_err("no more space!\n");
aicwf_dev_skb_free(skb);
return -EBADE;
}
skb_put(skb_inblock, aggr_len);
memcpy(skb_inblock->data, data, aggr_len);
#if 0
rwnx_rxdataind_aicwf(rx_priv->sdiodev->rwnx_hw, skb_inblock, (void *)rx_priv);
#endif
skb_pull(skb, adjust_len);
} else { // type : config
aggr_len = pkt_len;
if (aggr_len & (RX_ALIGNMENT - 1))
adjust_len = roundup(aggr_len, RX_ALIGNMENT);
else
adjust_len = aggr_len;
skb_inblock = __dev_alloc_skb(aggr_len+4, GFP_KERNEL);
if (skb_inblock == NULL) {
txrx_err("no more space!\n");
aicwf_dev_skb_free(skb);
return -EBADE;
}
skb_put(skb_inblock, aggr_len+4);
memcpy(skb_inblock->data, data, aggr_len+4);
if ((*(skb_inblock->data + 2) & 0x7f) == SDIO_TYPE_CFG_CMD_RSP)
rwnx_rx_handle_msg(rx_priv->sdiodev, (struct ipc_e2a_msg *)(skb_inblock->data + 4));
#if 0
if ((*(skb_inblock->data + 2) & 0x7f) == SDIO_TYPE_CFG_DATA_CFM)
aicwf_sdio_host_tx_cfm_handler(&(rx_priv->sdiodev->rwnx_hw->sdio_env), (u32 *)(skb_inblock->data + 4));
#endif
skb_pull(skb, adjust_len+4);
}
}
/* skb_inblock no used currently, just free it! */
dev_kfree_skb(skb_inblock);
dev_kfree_skb(skb);
atomic_dec(&rx_priv->rx_cnt);
}
#if defined(CONFIG_SDIO_PWRCTRL)
aicwf_sdio_pwr_stctl(rx_priv->sdiodev, SDIO_ACTIVE_ST);
#endif
return ret;
}
static struct recv_msdu *aicwf_rxframe_queue_init(struct list_head *q, int qsize)
{
int i;
struct recv_msdu *req, *reqs;
reqs = vmalloc(qsize*sizeof(struct recv_msdu));
if (reqs == NULL)
return NULL;
req = reqs;
for (i = 0; i < qsize; i++) {
INIT_LIST_HEAD(&req->rxframe_list);
list_add(&req->rxframe_list, q);
req->len = 0;
req++;
}
return reqs;
}
struct aicwf_rx_priv *aicwf_rx_init(void *arg)
{
struct aicwf_rx_priv *rx_priv;
rx_priv = kzalloc(sizeof(struct aicwf_rx_priv), GFP_KERNEL);
if (!rx_priv)
return NULL;
rx_priv->sdiodev = (struct aic_sdio_dev *)arg;
aicwf_frame_queue_init(&rx_priv->rxq, 1, MAX_RXQLEN);
spin_lock_init(&rx_priv->rxqlock);
atomic_set(&rx_priv->rx_cnt, 0);
INIT_LIST_HEAD(&rx_priv->rxframes_freequeue);
spin_lock_init(&rx_priv->freeq_lock);
rx_priv->recv_frames = aicwf_rxframe_queue_init(&rx_priv->rxframes_freequeue, MAX_REORD_RXFRAME);
if (!rx_priv->recv_frames) {
txrx_err("no enough buffer for free recv frame queue!\n");
kfree(rx_priv);
return NULL;
}
spin_lock_init(&rx_priv->stas_reord_lock);
INIT_LIST_HEAD(&rx_priv->stas_reord_list);
return rx_priv;
}
static void aicwf_recvframe_queue_deinit(struct list_head *q)
{
struct recv_msdu *req, *next;
list_for_each_entry_safe(req, next, q, rxframe_list) {
list_del_init(&req->rxframe_list);
}
}
void aicwf_rx_deinit(struct aicwf_rx_priv *rx_priv)
{
if (rx_priv->sdiodev->bus_if->busrx_thread) {
complete_all(&rx_priv->sdiodev->bus_if->busrx_trgg);
kthread_stop(rx_priv->sdiodev->bus_if->busrx_thread);
rx_priv->sdiodev->bus_if->busrx_thread = NULL;
}
aicwf_frame_queue_flush(&rx_priv->rxq);
aicwf_recvframe_queue_deinit(&rx_priv->rxframes_freequeue);
if (rx_priv->recv_frames)
vfree(rx_priv->recv_frames);
kfree(rx_priv);
//rx_priv = NULL;
}
bool aicwf_rxframe_enqueue(struct device *dev, struct frame_queue *q, struct sk_buff *pkt)
{
return aicwf_frame_enq(dev, q, pkt, 0);
}
void aicwf_dev_skb_free(struct sk_buff *skb)
{
if (!skb)
return;
dev_kfree_skb_any(skb);
}
static struct sk_buff *aicwf_frame_queue_penq(struct frame_queue *pq, int prio, struct sk_buff *p)
{
struct sk_buff_head *q;
if (pq->queuelist[prio].qlen >= pq->qmax)
return NULL;
q = &pq->queuelist[prio];
__skb_queue_tail(q, p);
pq->qcnt++;
if (pq->hi_prio < prio)
pq->hi_prio = (u16)prio;
return p;
}
void aicwf_frame_queue_flush(struct frame_queue *pq)
{
int prio;
struct sk_buff_head *q;
struct sk_buff *p, *next;
for (prio = 0; prio < pq->num_prio; prio++) {
q = &pq->queuelist[prio];
skb_queue_walk_safe(q, p, next) {
skb_unlink(p, q);
aicwf_dev_skb_free(p);
pq->qcnt--;
}
}
}
void aicwf_frame_queue_init(struct frame_queue *pq, int num_prio, int max_len)
{
int prio;
memset(pq, 0, offsetof(struct frame_queue, queuelist) + (sizeof(struct sk_buff_head) * num_prio));
pq->num_prio = (u16)num_prio;
pq->qmax = (u16)max_len;
for (prio = 0; prio < num_prio; prio++) {
skb_queue_head_init(&pq->queuelist[prio]);
}
}
struct sk_buff *aicwf_frame_queue_peek_tail(struct frame_queue *pq, int *prio_out)
{
int prio;
if (pq->qcnt == 0)
return NULL;
for (prio = 0; prio < pq->hi_prio; prio++)
if (!skb_queue_empty(&pq->queuelist[prio]))
break;
if (prio_out)
*prio_out = prio;
return skb_peek_tail(&pq->queuelist[prio]);
}
bool aicwf_is_framequeue_empty(struct frame_queue *pq)
{
int prio, len = 0;
for (prio = 0; prio <= pq->hi_prio; prio++)
len += pq->queuelist[prio].qlen;
if (len > 0)
return false;
else
return true;
}
struct sk_buff *aicwf_frame_dequeue(struct frame_queue *pq)
{
struct sk_buff_head *q;
struct sk_buff *p;
int prio;
if (pq->qcnt == 0)
return NULL;
while ((prio = pq->hi_prio) > 0 && skb_queue_empty(&pq->queuelist[prio]))
pq->hi_prio--;
q = &pq->queuelist[prio];
p = __skb_dequeue(q);
if (p == NULL)
return NULL;
pq->qcnt--;
return p;
}
static struct sk_buff *aicwf_skb_dequeue_tail(struct frame_queue *pq, int prio)
{
struct sk_buff_head *q = &pq->queuelist[prio];
struct sk_buff *p = skb_dequeue_tail(q);
if (!p)
return NULL;
pq->qcnt--;
return p;
}
bool aicwf_frame_enq(struct device *dev, struct frame_queue *q, struct sk_buff *pkt, int prio)
{
struct sk_buff *p = NULL;
int prio_modified = -1;
if (q->queuelist[prio].qlen < q->qmax && q->qcnt < q->qmax) {
aicwf_frame_queue_penq(q, prio, pkt);
return true;
}
if (q->queuelist[prio].qlen >= q->qmax) {
prio_modified = prio;
} else if (q->qcnt >= q->qmax) {
p = aicwf_frame_queue_peek_tail(q, &prio_modified);
if (prio_modified > prio)
return false;
}
if (prio_modified >= 0) {
if (prio_modified == prio)
return false;
p = aicwf_skb_dequeue_tail(q, prio_modified);
aicwf_dev_skb_free(p);
p = aicwf_frame_queue_penq(q, prio_modified, pkt);
if (p == NULL)
txrx_err("failed\n");
}
return p != NULL;
}

View File

@ -0,0 +1,214 @@
/**
* aicwf_txrxif.h
*
* bus function declarations
*
* Copyright (C) AICSemi 2018-2020
*/
#ifndef _AICWF_TXRXIF_H_
#define _AICWF_TXRXIF_H_
#include <linux/skbuff.h>
#include <linux/sched.h>
#include "aicsdio.h"
#define CMD_BUF_MAX 1536
#define TXPKT_BLOCKSIZE 512
#define MAX_AGGR_TXPKT_LEN (1536*4)
#define CMD_TX_TIMEOUT 5000
#define TX_ALIGNMENT 4
#define RX_HWHRD_LEN 60 //58->60 word allined
#define CCMP_OR_WEP_INFO 8
#define MAX_RXQLEN 2000
#define RX_ALIGNMENT 4
#define DEBUG_ERROR_LEVEL 0
#define DEBUG_DEBUG_LEVEL 1
#define DEBUG_INFO_LEVEL 2
#define DBG_LEVEL DEBUG_DEBUG_LEVEL
#define txrx_err(fmt, ...) pr_err("aicbsp: txrx_err:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__)
#define sdio_err(fmt, ...) pr_err("aicbsp: sdio_err:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__)
#define usb_err(fmt, ...) pr_err("aicbsp: usb_err:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__)
#if DBG_LEVEL >= DEBUG_DEBUG_LEVEL
#define sdio_dbg(fmt, ...) printk("aicbsp: " fmt, ##__VA_ARGS__)
#define usb_dbg(fmt, ...) printk("aicbsp: " fmt, ##__VA_ARGS__)
#else
#define sdio_dbg(fmt, ...)
#define usb_dbg(fmt, ...)
#endif
#if DBG_LEVEL >= DEBUG_INFO_LEVEL
#define sdio_info(fmt, ...) printk("aicbsp: " fmt, ##__VA_ARGS__)
#define usb_info(fmt, ...) printk("aicbsp: " fmt, ##__VA_ARGS__)
#else
#define sdio_info(fmt, ...)
#define usb_info(fmt, ...)
#endif
enum aicwf_bus_state {
BUS_DOWN_ST,
BUS_UP_ST
};
struct aicwf_bus_ops {
int (*start) (struct device *dev);
void (*stop) (struct device *dev);
int (*txdata) (struct device *dev, struct sk_buff *skb);
int (*txmsg) (struct device *dev, u8 *msg, uint len);
};
struct frame_queue {
u16 num_prio;
u16 hi_prio;
u16 qmax; /* max number of queued frames */
u16 qcnt;
struct sk_buff_head queuelist[8];
};
struct aicwf_bus {
union {
struct aic_sdio_dev *sdio;
struct aic_usb_dev *usb;
} bus_priv;
struct device *dev;
struct aicwf_bus_ops *ops;
enum aicwf_bus_state state;
u8 *cmd_buf;
struct completion bustx_trgg;
struct completion busrx_trgg;
struct task_struct *bustx_thread;
struct task_struct *busrx_thread;
};
struct aicwf_tx_priv {
#ifdef AICWF_SDIO_SUPPORT
struct aic_sdio_dev *sdiodev;
int fw_avail_bufcnt;
//for cmd tx
u8 *cmd_buf;
uint cmd_len;
bool cmd_txstate;
bool cmd_tx_succ;
struct semaphore cmd_txsema;
wait_queue_head_t cmd_txdone_wait;
//for data tx
atomic_t tx_pktcnt;
struct frame_queue txq;
spinlock_t txqlock;
struct semaphore txctl_sema;
#endif
#ifdef AICWF_USB_SUPPORT
struct aic_usb_dev *usbdev;
#endif
struct sk_buff *aggr_buf;
atomic_t aggr_count;
u8 *head;
u8 *tail;
};
#define MAX_REORD_RXFRAME 250
#define REORDER_UPDATE_TIME 50
#define AICWF_REORDER_WINSIZE 64
#define SN_LESS(a, b) (((a-b)&0x800) != 0)
#define SN_EQUAL(a, b) (a == b)
struct reord_ctrl {
struct aicwf_rx_priv *rx_priv;
u8 enable;
u16 ind_sn;
u8 wsize_b;
spinlock_t reord_list_lock;
struct list_head reord_list;
struct timer_list reord_timer;
struct work_struct reord_timer_work;
};
struct reord_ctrl_info {
u8 mac_addr[6];
struct reord_ctrl preorder_ctrl[8];
struct list_head list;
};
struct recv_msdu {
struct sk_buff *pkt;
u8 tid;
u16 seq_num;
uint len;
u8 *rx_data;
//for pending rx reorder list
struct list_head reord_pending_list;
//for total frame list, when rxframe from busif, dequeue, when submit frame to net, enqueue
struct list_head rxframe_list;
struct reord_ctrl *preorder_ctrl;
};
struct aicwf_rx_priv {
struct aic_sdio_dev *sdiodev;
void *rwnx_vif;
atomic_t rx_cnt;
u32 data_len;
spinlock_t rxqlock;
struct frame_queue rxq;
spinlock_t freeq_lock;
struct list_head rxframes_freequeue;
struct list_head stas_reord_list;
spinlock_t stas_reord_lock;
struct recv_msdu *recv_frames;
};
static inline int aicwf_bus_start(struct aicwf_bus *bus)
{
return bus->ops->start(bus->dev);
}
static inline void aicwf_bus_stop(struct aicwf_bus *bus)
{
bus->ops->stop(bus->dev);
}
static inline int aicwf_bus_txdata(struct aicwf_bus *bus, struct sk_buff *skb)
{
return bus->ops->txdata(bus->dev, skb);
}
static inline int aicwf_bus_txmsg(struct aicwf_bus *bus, u8 *msg, uint len)
{
return bus->ops->txmsg(bus->dev, msg, len);
}
static inline void aicwf_sched_timeout(u32 millisec)
{
ulong timeout = 0, expires = 0;
expires = jiffies + msecs_to_jiffies(millisec);
timeout = millisec;
while (timeout) {
timeout = schedule_timeout(timeout);
if (time_after(jiffies, expires))
break;
}
}
int aicwf_bus_init(uint bus_hdrlen, struct device *dev);
void aicwf_bus_deinit(struct device *dev);
void aicwf_tx_deinit(struct aicwf_tx_priv *tx_priv);
void aicwf_rx_deinit(struct aicwf_rx_priv *rx_priv);
struct aicwf_tx_priv *aicwf_tx_init(void *arg);
struct aicwf_rx_priv *aicwf_rx_init(void *arg);
void aicwf_frame_queue_init(struct frame_queue *pq, int num_prio, int max_len);
void aicwf_frame_queue_flush(struct frame_queue *pq);
bool aicwf_frame_enq(struct device *dev, struct frame_queue *q, struct sk_buff *pkt, int prio);
bool aicwf_rxframe_enqueue(struct device *dev, struct frame_queue *q, struct sk_buff *pkt);
bool aicwf_is_framequeue_empty(struct frame_queue *pq);
void aicwf_frame_tx(void *dev, struct sk_buff *skb);
void aicwf_dev_skb_free(struct sk_buff *skb);
struct sk_buff *aicwf_frame_dequeue(struct frame_queue *pq);
struct sk_buff *aicwf_frame_queue_peek_tail(struct frame_queue *pq, int *prio_out);
#endif /* _AICWF_TXRXIF_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
int aicwf_get_firmware_array(char* fw_name, u32 **fw_buf);

View File

@ -0,0 +1,62 @@
#include <linux/slab.h>
#include "aicsdio_txrxif.h"
#include "aic_bsp_driver.h"
struct prealloc_txq{
int prealloced;
void *txq;
size_t size;
};
struct prealloc_txq prealloc_txq;
#define MAX_TXQ_SIZE 100 * 1024
void *aicwf_prealloc_txq_alloc(size_t size)
{
BUG_ON(size > MAX_TXQ_SIZE);
//check prealloc_txq.size
if((int)prealloc_txq.size != (int)size)
{
AICWFDBG(LOGINFO, "%s size is diff will to be kzalloc \r\n", __func__);
if(prealloc_txq.txq != NULL)
{
AICWFDBG(LOGINFO, "%s txq to kfree \r\n", __func__);
kfree(prealloc_txq.txq);
prealloc_txq.txq = NULL;
}
prealloc_txq.size = size;
prealloc_txq.prealloced = 0;
}
//check prealloc or not
if(!prealloc_txq.prealloced)
{
prealloc_txq.txq = kzalloc(size, GFP_KERNEL);
if(!prealloc_txq.txq){
AICWFDBG(LOGERROR, "%s txq kzalloc fail \r\n", __func__);
}else{
AICWFDBG(LOGINFO, "%s txq kzalloc successful \r\n", __func__);
prealloc_txq.prealloced = 1;
}
}else{
AICWFDBG(LOGINFO, "%s txq not need to kzalloc \r\n", __func__);
}
return prealloc_txq.txq;
}
void aicwf_prealloc_txq_free(void)
{
if(prealloc_txq.txq != NULL)
{
AICWFDBG(LOGINFO, "%s txq to kfree \r\n", __func__);
kfree(prealloc_txq.txq);
prealloc_txq.txq = NULL;
}
}
EXPORT_SYMBOL(aicwf_prealloc_txq_alloc);

View File

@ -0,0 +1,4 @@
void aicwf_prealloc_txq_free(void);

View File

@ -0,0 +1,161 @@
#include <linux/memory.h>
#include "md5.h"
unsigned char PADDING[]={0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
void MD5Init(MD5_CTX *context)
{
context->count[0] = 0;
context->count[1] = 0;
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
}
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen)
{
unsigned int i = 0,index = 0,partlen = 0;
index = (context->count[0] >> 3) & 0x3F;
partlen = 64 - index;
context->count[0] += inputlen << 3;
if(context->count[0] < (inputlen << 3))
context->count[1]++;
context->count[1] += inputlen >> 29;
if(inputlen >= partlen)
{
memcpy(&context->buffer[index],input,partlen);
MD5Transform(context->state,context->buffer);
for(i = partlen;i+64 <= inputlen;i+=64)
MD5Transform(context->state,&input[i]);
index = 0;
}
else
{
i = 0;
}
memcpy(&context->buffer[index],&input[i],inputlen-i);
}
void MD5Final(MD5_CTX *context,unsigned char digest[16])
{
unsigned int index = 0,padlen = 0;
unsigned char bits[8];
index = (context->count[0] >> 3) & 0x3F;
padlen = (index < 56)?(56-index):(120-index);
MD5Encode(bits,context->count,8);
MD5Update(context,PADDING,padlen);
MD5Update(context,bits,8);
MD5Encode(digest,context->state,16);
}
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)
{
unsigned int i = 0,j = 0;
while(j < len)
{
output[j] = input[i] & 0xFF;
output[j+1] = (input[i] >> 8) & 0xFF;
output[j+2] = (input[i] >> 16) & 0xFF;
output[j+3] = (input[i] >> 24) & 0xFF;
i++;
j+=4;
}
}
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)
{
unsigned int i = 0,j = 0;
while(j < len)
{
output[i] = (input[j]) |
(input[j+1] << 8) |
(input[j+2] << 16) |
(input[j+3] << 24);
i++;
j+=4;
}
}
void MD5Transform(unsigned int state[4],unsigned char block[64])
{
unsigned int a = state[0];
unsigned int b = state[1];
unsigned int c = state[2];
unsigned int d = state[3];
unsigned int x[64];
MD5Decode(x,block,64);
FF(a, b, c, d, x[ 0], 7, 0xd76aa478); /* 1 */
FF(d, a, b, c, x[ 1], 12, 0xe8c7b756); /* 2 */
FF(c, d, a, b, x[ 2], 17, 0x242070db); /* 3 */
FF(b, c, d, a, x[ 3], 22, 0xc1bdceee); /* 4 */
FF(a, b, c, d, x[ 4], 7, 0xf57c0faf); /* 5 */
FF(d, a, b, c, x[ 5], 12, 0x4787c62a); /* 6 */
FF(c, d, a, b, x[ 6], 17, 0xa8304613); /* 7 */
FF(b, c, d, a, x[ 7], 22, 0xfd469501); /* 8 */
FF(a, b, c, d, x[ 8], 7, 0x698098d8); /* 9 */
FF(d, a, b, c, x[ 9], 12, 0x8b44f7af); /* 10 */
FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
/* Round 2 */
GG(a, b, c, d, x[ 1], 5, 0xf61e2562); /* 17 */
GG(d, a, b, c, x[ 6], 9, 0xc040b340); /* 18 */
GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa); /* 20 */
GG(a, b, c, d, x[ 5], 5, 0xd62f105d); /* 21 */
GG(d, a, b, c, x[10], 9, 0x2441453); /* 22 */
GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8); /* 24 */
GG(a, b, c, d, x[ 9], 5, 0x21e1cde6); /* 25 */
GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
GG(c, d, a, b, x[ 3], 14, 0xf4d50d87); /* 27 */
GG(b, c, d, a, x[ 8], 20, 0x455a14ed); /* 28 */
GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8); /* 30 */
GG(c, d, a, b, x[ 7], 14, 0x676f02d9); /* 31 */
GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH(a, b, c, d, x[ 5], 4, 0xfffa3942); /* 33 */
HH(d, a, b, c, x[ 8], 11, 0x8771f681); /* 34 */
HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
HH(a, b, c, d, x[ 1], 4, 0xa4beea44); /* 37 */
HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9); /* 38 */
HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60); /* 39 */
HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
HH(d, a, b, c, x[ 0], 11, 0xeaa127fa); /* 42 */
HH(c, d, a, b, x[ 3], 16, 0xd4ef3085); /* 43 */
HH(b, c, d, a, x[ 6], 23, 0x4881d05); /* 44 */
HH(a, b, c, d, x[ 9], 4, 0xd9d4d039); /* 45 */
HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
HH(b, c, d, a, x[ 2], 23, 0xc4ac5665); /* 48 */
/* Round 4 */
II(a, b, c, d, x[ 0], 6, 0xf4292244); /* 49 */
II(d, a, b, c, x[ 7], 10, 0x432aff97); /* 50 */
II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
II(b, c, d, a, x[ 5], 21, 0xfc93a039); /* 52 */
II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
II(d, a, b, c, x[ 3], 10, 0x8f0ccc92); /* 54 */
II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
II(b, c, d, a, x[ 1], 21, 0x85845dd1); /* 56 */
II(a, b, c, d, x[ 8], 6, 0x6fa87e4f); /* 57 */
II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
II(c, d, a, b, x[ 6], 15, 0xa3014314); /* 59 */
II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
II(a, b, c, d, x[ 4], 6, 0xf7537e82); /* 61 */
II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb); /* 63 */
II(b, c, d, a, x[ 9], 21, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}

View File

@ -0,0 +1,48 @@
#ifndef MD5_H
#define MD5_H
typedef struct
{
unsigned int count[2];
unsigned int state[4];
unsigned char buffer[64];
}MD5_CTX;
#define F(x,y,z) ((x & y) | (~x & z))
#define G(x,y,z) ((x & z) | (y & ~z))
#define H(x,y,z) (x^y^z)
#define I(x,y,z) (y ^ (x | ~z))
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))
#define FF(a,b,c,d,x,s,ac) \
{ \
a += F(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define GG(a,b,c,d,x,s,ac) \
{ \
a += G(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define HH(a,b,c,d,x,s,ac) \
{ \
a += H(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define II(a,b,c,d,x,s,ac) \
{ \
a += I(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
void MD5Init(MD5_CTX *context);
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen);
void MD5Final(MD5_CTX *context,unsigned char digest[16]);
void MD5Transform(unsigned int state[4],unsigned char block[64]);
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len);
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len);
#endif

View File

@ -0,0 +1,4 @@
#define RWNX_VERS_REV "241c091M (master)"
#define RWNX_VERS_MOD "6.4.3.0"
#define RWNX_VERS_BANNER "rwnx v6.4.3.0 - - 241c091M (master)"
#define RELEASE_DATE "2024_0327_3561b08f"

View File

@ -0,0 +1,10 @@
*.o
*.ko
*.order
*.symvers
*.o.d
*.o.cmd
*.ko.cmd
*.mod
*.mod.c
*.mod.cmd

View File

@ -0,0 +1,5 @@
config AIC8800_BTLPM_SUPPORT
tristate "AIC8800 bluetooth Support"
help
This is support for aic bluetooh driver.

View File

@ -0,0 +1,83 @@
CONFIG_AIC8800_BTLPM_SUPPORT = m
obj-$(CONFIG_AIC8800_BTLPM_SUPPORT) := aic8800_btlpm.o
ccflags-y += -I$(srctree)/$(src)/../aic8800_bsp
# Platform support list
CONFIG_PLATFORM_ROCKCHIP ?= n
CONFIG_PLATFORM_ROCKCHIP2 ?= n
CONFIG_PLATFORM_ALLWINNER ?= n
CONFIG_PLATFORM_AMLOGIC ?= n
CONFIG_PLATFORM_UBUNTU ?= y
CONFIG_SUPPORT_LPM ?= n
CONFIG_AUTO_PM ?= n
aic8800_btlpm-y := \
aic_bluetooth_main.o \
rfkill.o \
aic8800_btlpm-$(CONFIG_SUPPORT_LPM) += lpm.o
ccflags-y += -DAIC_TRACE_INCLUDE_PATH=$(src)
ccflags-$(CONFIG_AUTO_PM) += -DCONFIG_AUTO_PM
ifeq ($(CONFIG_PLATFORM_ROCKCHIP), y)
ARCH = arm64
KDIR = /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/kernel
CROSS_COMPILE = /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
ccflags-$(CONFIG_PLATFORM_ROCKCHIP) += -DCONFIG_PLATFORM_ROCKCHIP
ccflags-y += -DANDROID_PLATFORM
endif
ifeq ($(CONFIG_PLATFORM_ROCKCHIP2), y)
ARCH = arm64
KDIR = /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/kernel
CROSS_COMPILE = /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
ccflags-$(CONFIG_PLATFORM_ROCKCHIP2) += -DCONFIG_PLATFORM_ROCKCHIP2
ccflags-y += -DANDROID_PLATFORM
endif
ifeq ($(CONFIG_PLATFORM_ALLWINNER), y)
ccflags-$(CONFIG_PLATFORM_ALLWINNER) += -DCONFIG_PLATFORM_ALLWINNER
KDIR ?= /home/yaya/E/Allwinner/R818/R818/AndroidQ/lichee/kernel/linux-4.9/
ARCH ?= arm64
CROSS_COMPILE ?= /home/yaya/E/Allwinner/R818/R818/AndroidQ/android/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-
ccflags-y += -DANDROID_PLATFORM
endif
ifeq ($(CONFIG_PLATFORM_AMLOGIC), y)
ccflags-$(CONFIG_PLATFORM_NANOPI) += -DCONFIG_PLATFORM_NANOPI
ccflags-y += -DANDROID_PLATFORM
endif
ifeq ($(CONFIG_PLATFORM_UBUNTU), y)
KDIR ?= /lib/modules/$(shell uname -r)/build
PWD ?= $(shell pwd)
KVER ?= $(shell uname -r)
MODDESTDIR ?= /lib/modules/$(KVER)/kernel/drivers/net/wireless/
ARCH ?= x86_64
CROSS_COMPILE ?=
endif
all: modules
modules:
make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
install:
mkdir -p $(MODDESTDIR)
install -p -m 644 $(MODULE_NAME).ko $(MODDESTDIR)
/sbin/depmod -a ${KVER}
uninstall:
rm -rfv $(MODDESTDIR)/$(MODULE_NAME).ko
/sbin/depmod -a ${KVER}
clean:
rm -rf *.o *.ko *.o.* *.mod.* modules.* Module.* .a* .o* .*.o.* *.mod .tmp* .cache.mk

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,88 @@
#include <linux/module.h>
#include <linux/inetdevice.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/platform_device.h>
#include "lpm.h"
#include "rfkill.h"
#define DRV_CONFIG_FW_NAME "fw.bin"
#define DRV_DESCRIPTION "AIC BLUETOOTH"
#define DRV_COPYRIGHT "Copyright(c) 2015-2020 AICSemi"
#define DRV_AUTHOR "AICSemi"
#define DRV_VERS_MOD "1.0"
static struct platform_device *aicbt_pdev;
static struct platform_driver aicbt_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "aic_bt",
},
//.probe = aicbt_probe,
//.remove = aicbt_remove,
};
static int __init aic_bluetooth_mod_init(void)
{
int ret;
printk("%s\n", __func__);
ret = platform_driver_register(&aicbt_driver);
if (ret) {
pr_err("register platform driver failed: %d\n", ret);
return ret;
}
aicbt_pdev = platform_device_alloc("aic-bt", -1);
ret = platform_device_add(aicbt_pdev);
if (ret) {
pr_err("register platform device failed: %d\n", ret);
goto err0;
}
ret = rfkill_bluetooth_init(aicbt_pdev);
if (ret) {
pr_err("rfkill init fail\n");
goto err1;
}
#if defined(ANDROID_PLATFORM) && !defined(CONFIG_PLATFORM_ROCKCHIP) && !defined(CONFIG_PLATFORM_ROCKCHIP2)
ret = bluesleep_init(aicbt_pdev);
if (ret) {
pr_err("bluesleep init fail\n");
goto err2;
}
#endif
return 0;
#if defined(ANDROID_PLATFORM) && !defined(CONFIG_PLATFORM_ROCKCHIP) && !defined(CONFIG_PLATFORM_ROCKCHIP2)
err2:
#endif
rfkill_bluetooth_remove(aicbt_pdev);
err1:
platform_device_del(aicbt_pdev);
err0:
platform_driver_unregister(&aicbt_driver);
return ret;
}
static void __exit aic_bluetooth_mod_exit(void)
{
printk("%s\n", __func__);
#if defined(ANDROID_PLATFORM) && !defined(CONFIG_PLATFORM_ROCKCHIP) && !defined(CONFIG_PLATFORM_ROCKCHIP2)
bluesleep_exit(aicbt_pdev);
#endif
rfkill_bluetooth_remove(aicbt_pdev);
platform_device_del(aicbt_pdev);
platform_driver_unregister(&aicbt_driver);
}
module_init(aic_bluetooth_mod_init);
module_exit(aic_bluetooth_mod_exit);
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERS_MOD);
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,19 @@
#ifndef __AIC_BSP_EXPORT_H
#define __AIC_BSP_EXPORT_H
#define AIC_BLUETOOTH 0
#define AIC_WIFI 1
#define AIC_PWR_OFF 0
#define AIC_PWR_ON 1
struct aicbsp_feature_t {
bool band_5g_support;
uint32_t sdio_clock;
uint8_t sdio_phase;
uint8_t irqf;
};
int aicbsp_set_subsys(int, int);
int aicbsp_get_feature(struct aicbsp_feature_t *feature);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
/*
* Copyright (C) 2015 Spreadtrum Communications Inc.
*
* 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 __LPM_H
#define __LPM_H
int bluesleep_init(struct platform_device *pdev);
int bluesleep_exit(struct platform_device *dev);
#endif

View File

@ -0,0 +1,81 @@
/*
* 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.
*/
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/rfkill.h>
#include <linux/gpio.h>
#include <linux/ioport.h>
#include <linux/clk.h>
#include <linux/of_gpio.h>
#include <linux/version.h>
#include "aic_bsp_export.h"
static struct rfkill *bt_rfk;
static const char bt_name[] = "bluetooth";
static int bluetooth_set_power(void *data, bool blocked)
{
pr_info("%s: start_block=%d\n", __func__, blocked);
if (!blocked) {
aicbsp_set_subsys(AIC_BLUETOOTH, AIC_PWR_ON);
} else {
aicbsp_set_subsys(AIC_BLUETOOTH, AIC_PWR_OFF);
}
pr_info("%s: end_block=%d\n", __func__, blocked);
return 0;
}
static struct rfkill_ops rfkill_bluetooth_ops = {
.set_block = bluetooth_set_power,
};
int rfkill_bluetooth_init(struct platform_device *pdev)
{
int rc = 0;
pr_info("-->%s\n", __func__);
bt_rfk = rfkill_alloc(bt_name, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
&rfkill_bluetooth_ops, NULL);
if (!bt_rfk) {
rc = -ENOMEM;
goto err_rfkill_alloc;
}
/* userspace cannot take exclusive control */
rfkill_init_sw_state(bt_rfk, true);
rc = rfkill_register(bt_rfk);
if (rc)
goto err_rfkill_reg;
pr_info("<--%s\n", __func__);
return 0;
err_rfkill_reg:
rfkill_destroy(bt_rfk);
err_rfkill_alloc:
return rc;
}
int rfkill_bluetooth_remove(struct platform_device *dev)
{
pr_info("-->%s\n", __func__);
rfkill_unregister(bt_rfk);
rfkill_destroy(bt_rfk);
pr_info("<--%s\n", __func__);
return 0;
}

View File

@ -0,0 +1,17 @@
/*
* 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 __RFKILL_H__
#define __RFKILL_H__
int rfkill_bluetooth_init(struct platform_device *pdev);
int rfkill_bluetooth_remove(struct platform_device *pdev);
#endif

View File

@ -0,0 +1,10 @@
*.o
*.ko
*.order
*.symvers
*.o.d
*.o.cmd
*.ko.cmd
*.mod
*.mod.c
*.mod.cmd

View File

@ -0,0 +1,5 @@
config AIC8800_WLAN_SUPPORT
tristate "AIC8800 wlan Support"
help
This is support for aic wifi driver.

View File

@ -0,0 +1,380 @@
EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS)
EXTRA_CFLAGS += -Wno-implicit-fallthrough
#EXTRA_CFLAGS += -Wno-unused-function
#EXTRA_CFLAGS += -Wno-maybe-uninitialized
#EXTRA_CFLAGS += -Wno-unused-variable
RWNX_VERS_NUM := 6.4.3.0
CONFIG_COUNTRY_CODE = "00"
MODULE_NAME = aic8800_fdrv
CONFIG_AIC8800_WLAN_SUPPORT = m
# Support of bootrom start
CONFIG_START_FROM_BOOTROM = y
# Support of pmic setting, new version bootrom avaliable
CONFIG_PMIC_SETTING ?=y
# Select 8800DC/DW DCDC_VRF mode, check your board
CONFIG_VRF_DCDC_MODE = y
# ROM patch enabled option
CONFIG_ROM_PATCH_EN ?=y
# Support chip with mcu
CONFIG_MCU_INTEGRATED ?= n
CONFIG_MCU_MESSAGE ?= n
ifeq ($(CONFIG_MCU_INTEGRATED), y)
CONFIG_PMIC_SETTING = n
else
CONFIG_MCU_MESSAGE ?= n
endif
#
# WAITING FOR KCONFIG {
#
CONFIG_RWNX_FULLMAC ?= y
CONFIG_RWNX_FHOST ?= n
#
# DEBUG OPTIONS
CONFIG_RWNX_UM_HELPER_DFLT ?= "/dini/dini_bin/rwnx_umh.sh"
#
# FW ARCH:
CONFIG_RWNX_SDM ?= n
CONFIG_RWNX_TL4 ?= n
# IPC version
CONFIG_RWNX_OLD_IPC ?= n
# Support of P2P DebugFS for enabling/disabling NoA and OppPS
CONFIG_RWNX_P2P_DEBUGFS := n
#
# } // WAITING FOR KCONFIG
#
# Enable A-MSDU support (need FW support)
## Select this if FW is compiled with AMSDU support
CONFIG_RWNX_SPLIT_TX_BUF ?= n
## Select this TO send AMSDU
CONFIG_RWNX_AMSDUS_TX ?= n
# Enable BFMER support (need FW support)
CONFIG_RWNX_BFMER ?= n
CONFIG_SDIO_SUPPORT =y
CONFIG_USB_SUPPORT =n
CONFIG_RX_REORDER ?=y
CONFIG_ARP_OFFLOAD =y
CONFIG_RADAR_OR_IR_DETECT =n
CONFIG_DOWNLOAD_FW =n
CONFIG_RFTEST=y
CONFIG_USB_BT =y
CONFIG_SDIO_BT=n
CONFIG_USE_5G ?= y
CONFIG_SDIO_PWRCTRL ?= y
CONFIG_CREATE_TRACE_POINTS = n
CONFIG_TXRX_THREAD_PRIO = y
# CONFIG_COEX = n for BT_ONLY, CONFIG_COEX =y for combo and sw
CONFIG_COEX = y
CONFIG_RX_NETIF_RECV_SKB = y
CONFIG_GPIO_WAKEUP ?= n
CONFIG_SET_VENDOR_EXTENSION_IE = n
CONFIG_SUPPORT_REALTIME_CHANGE_MAC = y
CONFIG_WPA3_FOR_OLD_KERNEL ?= n
CONFIG_VHT_FOR_OLD_KERNEL ?= n
CONFIG_HE_FOR_OLD_KERNEL ?= n
CONFIG_PREALLOC_RX_SKB = n
CONFIG_WIFI_SUSPEND_FOR_LINUX = n
# Need to set fw path in BOARD_KERNEL_CMDLINE
CONFIG_USE_FW_REQUEST = n
CONFIG_USE_P2P0=n
CONFIG_TX_NETIF_FLOWCTRL = n
CONFIG_ONE_TXQ = n
CONFIG_BR_SUPPORT =n
BR_NAME = br0
CONFIG_FDRV_NO_REG_SDIO=n
CONFIG_SCHED_SCAN = n
CONFIG_OOB ?= n
CONFIG_USE_CUSTOMER_MAC = n
CONFIG_PREALLOC_TXQ ?= y
CONFIG_DPD = y
CONFIG_FORCE_DPD_CALIB = y
CONFIG_FILTER_TCP_ACK =n
CONFIG_RESV_MEM_SUPPORT ?= y
CONFIG_GKI = n
CONFIG_TEMP_COMP = n
# CONFIG_MCC = n for sta and p2p concurrent in same channel.
CONFIG_MCC = y
ifneq ($(CONFIG_WIRELESS_EXT), y)
CONFIG_USE_WIRELESS_EXT = n
endif
# Support of MU-MIMO transmission (need FW support)
ifeq ($(CONFIG_RWNX_BFMER), y)
CONFIG_RWNX_MUMIMO_TX ?= n
else
CONFIG_RWNX_MUMIMO_TX = n
endif
# Enable handling of radar event
CONFIG_RWNX_RADAR ?= y
# Enable HW queue for Broadcast/Multicast traffic (need FW support)
CONFIG_RWNX_BCMC ?= y
# Enable Monitor+Data interface support (need FW support)
CONFIG_RWNX_MON_DATA =y
# extra DEBUG config
CONFIG_RWNX_SW_PROFILING ?= n
CONFIG_RWNX_DBG ?= y
CONFIG_DEBUG_FS ?= n
obj-$(CONFIG_AIC8800_WLAN_SUPPORT) := $(MODULE_NAME).o
$(MODULE_NAME)-y := \
rwnx_msg_tx.o \
rwnx_msg_rx.o \
rwnx_utils.o \
rwnx_cmds.o \
rwnx_irqs.o \
rwnx_cfgfile.o \
rwnx_strs.o \
rwnx_rx.o \
rwnx_tx.o \
rwnx_txq.o \
rwnx_main.o \
rwnx_mod_params.o \
rwnx_mesh.o \
rwnx_platform.o \
rwnx_pci.o \
rwnx_dini.o \
rwnx_v7.o \
ipc_host.o \
rwnx_tdls.o \
aic_vendor.o \
md5.o \
aicwf_compat_8800dc.o \
aicwf_compat_8800d80.o \
rwnx_wakelock.o \
regdb.o \
aicwf_rx_prealloc.o
$(MODULE_NAME)-$(CONFIG_BR_SUPPORT) += aic_br_ext.o
$(MODULE_NAME)-$(CONFIG_RWNX_RADAR) += rwnx_radar.o
$(MODULE_NAME)-$(CONFIG_DEBUG_FS) += rwnx_debugfs.o
$(MODULE_NAME)-$(CONFIG_DEBUG_FS) += rwnx_fw_trace.o
$(MODULE_NAME)-$(CONFIG_NL80211_TESTMODE) += rwnx_testmode.o
$(MODULE_NAME)-$(CONFIG_RWNX_BFMER) += rwnx_bfmer.o
$(MODULE_NAME)-$(CONFIG_RWNX_MUMIMO_TX) += rwnx_mu_group.o
$(MODULE_NAME)-$(CONFIG_SDIO_SUPPORT) += sdio_host.o
$(MODULE_NAME)-$(CONFIG_SDIO_SUPPORT) += aicwf_txrxif.o
$(MODULE_NAME)-$(CONFIG_SDIO_SUPPORT) += aicwf_sdio.o
$(MODULE_NAME)-$(CONFIG_FILTER_TCP_ACK) += aicwf_tcp_ack.o
$(MODULE_NAME)-$(CONFIG_SDIO_BT) += aic_btsdio.o
$(MODULE_NAME)-$(CONFIG_USB_SUPPORT) += usb_host.o
$(MODULE_NAME)-$(CONFIG_USB_SUPPORT) += aicwf_txrxif.o
$(MODULE_NAME)-$(CONFIG_USB_SUPPORT) += aicwf_usb.o
$(MODULE_NAME)-$(CONFIG_GKI) += rwnx_gki.o
ccflags-$(CONFIG_DEBUG_FS) += -DCONFIG_RWNX_DEBUGFS
ccflags-$(CONFIG_DEBUG_FS) += -DCONFIG_RWNX_UM_HELPER_DFLT=\"$(CONFIG_RWNX_UM_HELPER_DFLT)\"
ccflags-$(CONFIG_RWNX_P2P_DEBUGFS) += -DCONFIG_RWNX_P2P_DEBUGFS
# FW VARS
ccflags-y += -DNX_VIRT_DEV_MAX=4
#for 8800D and DCDW u01
#ccflags-y += -DNX_REMOTE_STA_MAX=10
#for 8800DCDW u02
ccflags-y += -DNX_REMOTE_STA_MAX_FOR_OLD_IC=10
ccflags-y += -DNX_REMOTE_STA_MAX=32
ccflags-y += -DNX_MU_GROUP_MAX=62
ccflags-y += -DNX_TXDESC_CNT=64
ccflags-y += -DNX_TX_MAX_RATES=4
ccflags-y += -DNX_CHAN_CTXT_CNT=3
# FW ARCH:
ccflags-$(CONFIG_RWNX_SDM) += -DCONFIG_RWNX_SDM
ccflags-$(CONFIG_RWNX_TL4) += -DCONFIG_RWNX_TL4
ccflags-$(CONFIG_RWNX_OLD_IPC) += -DCONFIG_RWNX_OLD_IPC
ccflags-$(CONFIG_PLATFORM_NANOPI_M4) += -DCONFIG_NANOPI_M4
ccflags-$(CONFIG_PLATFORM_INGENIC_T20) += -DCONFIG_INGENIC_T20
ccflags-$(CONFIG_PLATFORM_ALLWINNER) += -DCONFIG_PLATFORM_ALLWINNER
ccflags-$(CONFIG_START_FROM_BOOTROM) += -DCONFIG_START_FROM_BOOTROM
ccflags-$(CONFIG_PMIC_SETTING) += -DCONFIG_PMIC_SETTING
ccflags-$(CONFIG_VRF_DCDC_MODE) += -DCONFIG_VRF_DCDC_MODE
ccflags-$(CONFIG_ROM_PATCH_EN) += -DCONFIG_ROM_PATCH_EN
ccflags-$(CONFIG_HE_FOR_OLD_KERNEL) += -DCONFIG_HE_FOR_OLD_KERNEL
ccflags-$(CONFIG_MCU_INTEGRATED) += -DCONFIG_MCU_INTEGRATED
ccflags-$(CONFIG_MCU_MESSAGE) += -DCONFIG_MCU_MESSAGE
ccflags-$(CONFIG_COEX) += -DCONFIG_COEX
ccflags-y += -DCONFIG_RWNX_FULLMAC
ccflags-y += -I$(srctree)
ccflags-y += -I$(srctree)/$(src)
ccflags-y += -I$(srctree)/$(src)/../aic8800_bsp
ccflags-y += -DCONFIG_AIC_FW_PATH=\"$(CONFIG_AIC_FW_PATH)\"
ccflags-$(CONFIG_RWNX_RADAR) += -DCONFIG_RWNX_RADAR
ccflags-$(CONFIG_RWNX_MON_DATA) += -DCONFIG_RWNX_MON_DATA
ccflags-$(CONFIG_RWNX_BFMER) += -DCONFIG_RWNX_BFMER
ccflags-$(CONFIG_RWNX_SPLIT_TX_BUF) += -DCONFIG_RWNX_SPLIT_TX_BUF
ifeq ($(CONFIG_RWNX_SPLIT_TX_BUF), y)
ccflags-$(CONFIG_RWNX_AMSDUS_TX) += -DCONFIG_RWNX_AMSDUS_TX
endif
ccflags-$(CONFIG_RWNX_DBG) += -DCONFIG_RWNX_DBG
ccflags-$(CONFIG_RWNX_SW_PROFILING) += -DCONFIG_RWNX_SW_PROFILING
ccflags-$(CONFIG_RWNX_MUMIMO_TX) += -DCONFIG_RWNX_MUMIMO_TX
ccflags-$(CONFIG_RFTEST) += -DCONFIG_RFTEST
ccflags-y += -DDEFAULT_COUNTRY_CODE=""\$(CONFIG_COUNTRY_CODE)"\"
ccflags-$(CONFIG_USE_5G) += -DUSE_5G
ccflags-$(CONFIG_CREATE_TRACE_POINTS) += -DCREATE_TRACE_POINTS
ccflags-$(CONFIG_TXRX_THREAD_PRIO) += -DCONFIG_TXRX_THREAD_PRIO
ccflags-$(CONFIG_GPIO_WAKEUP) += -DCONFIG_GPIO_WAKEUP
ccflags-$(CONFIG_SET_VENDOR_EXTENSION_IE) += -DCONFIG_SET_VENDOR_EXTENSION_IE
ccflags-$(CONFIG_SUPPORT_REALTIME_CHANGE_MAC) += -DCONFIG_SUPPORT_REALTIME_CHANGE_MAC
ccflags-$(CONFIG_WPA3_FOR_OLD_KERNEL) += -DCONFIG_WPA3_FOR_OLD_KERNEL
ccflags-$(CONFIG_VHT_FOR_OLD_KERNEL) += -DCONFIG_VHT_FOR_OLD_KERNEL
ccflags-$(CONFIG_PREALLOC_RX_SKB) += -DCONFIG_PREALLOC_RX_SKB
ccflags-$(CONFIG_WIFI_SUSPEND_FOR_LINUX) += -DCONFIG_WIFI_SUSPEND_FOR_LINUX
ccflags-$(CONFIG_USE_FW_REQUEST) += -DCONFIG_USE_FW_REQUEST
ccflags-$(CONFIG_USE_P2P0) += -DCONFIG_USE_P2P0
ccflags-$(CONFIG_FDRV_NO_REG_SDIO) += -DCONFIG_FDRV_NO_REG_SDIO
ccflags-$(CONFIG_SCHED_SCAN) += -DCONFIG_SCHED_SCAN
ccflags-$(CONFIG_OOB) += -DCONFIG_OOB
ccflags-$(CONFIG_USE_CUSTOMER_MAC) += -DCONFIG_USE_CUSTOMER_MAC
ccflags-$(CONFIG_PREALLOC_TXQ) += -DCONFIG_PREALLOC_TXQ
ccflags-$(CONFIG_DPD) += -DCONFIG_DPD
ccflags-$(CONFIG_FORCE_DPD_CALIB) += -DCONFIG_FORCE_DPD_CALIB -DCONFIG_DPD
ccflags-$(CONFIG_FILTER_TCP_ACK) += -DCONFIG_FILTER_TCP_ACK
ccflags-$(CONFIG_SDIO_BT) += -DCONFIG_SDIO_BT
ccflags-$(CONFIG_RESV_MEM_SUPPORT) += -DCONFIG_RESV_MEM_SUPPORT
ccflags-$(CONFIG_GKI) += -DCONFIG_GKI
ccflags-$(CONFIG_TEMP_COMP) += -DCONFIG_TEMP_COMP
ccflags-$(CONFIG_MCC) += -DCONFIG_MCC
ifeq ($(CONFIG_SDIO_SUPPORT), y)
ccflags-y += -DAICWF_SDIO_SUPPORT
ccflags-$(CONFIG_SDIO_PWRCTRL) += -DCONFIG_SDIO_PWRCTRL
endif
ifeq ($(CONFIG_USB_SUPPORT), y)
ccflags-y += -DAICWF_USB_SUPPORT
endif
ifeq ($(CONFIG_BR_SUPPORT), y)
ccflags-y += -DCONFIG_BR_SUPPORT
ccflags-y += '-DCONFIG_BR_SUPPORT_BRNAME="'$(BR_NAME)'"'
endif
ifeq ($(CONFIG_RWNX_MUMIMO_TX), y)
ccflags-y += -DCONFIG_USER_MAX=2
else
ccflags-y += -DCONFIG_USER_MAX=1
endif
ifeq ($(CONFIG_RWNX_BCMC), y)
ccflags-y += -DNX_TXQ_CNT=5
else
ccflags-y += -DNX_TXQ_CNT=4
endif
# For old kernel (<=3.19)
ifeq ($(shell test $(VERSION) -lt 4 -a "$(CONFIG_VENDOR_RWNX)" = y ; echo $$?),0)
ccflags-y += -DCONFIG_VENDOR_RWNX_VHT_NO80
endif
ccflags-$(CONFIG_RX_REORDER) += -DAICWF_RX_REORDER
ccflags-$(CONFIG_ARP_OFFLOAD) += -DAICWF_ARP_OFFLOAD
ccflags-$(CONFIG_RADAR_DETECT) += -DRADAR_OR_IR_DETECT
ccflags-$(CONFIG_DOWNLOAD_FW) += -DCONFIG_DOWNLOAD_FW
ccflags-$(CONFIG_RX_NETIF_RECV_SKB) += -DCONFIG_RX_NETIF_RECV_SKB
ccflags-$(CONFIG_ONE_TXQ) += -DCONFIG_ONE_TXQ
ccflags-$(CONFIG_TX_NETIF_FLOWCTRL) += -DCONFIG_TX_NETIF_FLOWCTRL
ccflags-y += -DAIC_TRACE_INCLUDE_PATH=$(src)
MAKEFLAGS +=-j$(shell nproc)
########## Platform support list ##########
CONFIG_PLATFORM_ROCKCHIP ?= n
CONFIG_PLATFORM_ROCKCHIP2 ?= n
CONFIG_PLATFORM_ALLWINNER ?= n
CONFIG_PLATFORM_INGENIC_T20 ?= n
CONFIG_PLATFORM_AMLOGIC ?= n
CONFIG_PLATFORM_UBUNTU ?= y
ifeq ($(CONFIG_PLATFORM_ROCKCHIP), y)
ARCH := arm64
KDIR ?= /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/kernel
CROSS_COMPILE := /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
ccflags-$(CONFIG_PLATFORM_ROCKCHIP) += -DCONFIG_PLATFORM_ROCKCHIP
ccflags-y += -DANDROID_PLATFORM
endif
ifeq ($(CONFIG_PLATFORM_ROCKCHIP2), y)
ARCH := arm64
KDIR ?= /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/kernel
CROSS_COMPILE := /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
ccflags-$(CONFIG_PLATFORM_ROCKCHIP2) += -DCONFIG_PLATFORM_ROCKCHIP2
ccflags-y += -DANDROID_PLATFORM
endif
ifeq ($(CONFIG_PLATFORM_ALLWINNER), y)
ccflags-$(CONFIG_PLATFORM_ALLWINNER) += -DCONFIG_PLATFORM_ALLWINNER
ccflags-y += -DANDROID_PLATFORM
KDIR ?= /home/yaya/E/Allwinner/r818/Android10/lichee/kernel/linux-4.9/
ARCH ?= arm64
CROSS_COMPILE ?= /home/yaya/E/Allwinner/r818/Android10/android/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/aarch64-linux-android-
endif
ifeq ($(CONFIG_PLATFORM_INGENIC_T20), y)
KDIR ?= /home/yaya/E/T40/kernel
ARCH ?= mips
CROSS_COMPILE ?= /home/yaya/E/T40/mips-linux-gnu-ingenic-gcc7.2.0-glibc2.29-fp64/bin/mips-linux-gnu-
endif
ifeq ($(CONFIG_PLATFORM_AMLOGIC), y)
ccflags-$(CONFIG_PLATFORM_AMLOGIC) += -DCONFIG_PLATFORM_AMLOGIC
ccflags-y += -DANDROID_PLATFORM
endif
ifeq ($(CONFIG_PLATFORM_UBUNTU), y)
KDIR ?= /lib/modules/$(shell uname -r)/build
PWD ?= $(shell pwd)
KVER ?= $(shell uname -r)
MODDESTDIR ?= /lib/modules/$(KVER)/kernel/drivers/net/wireless/
ARCH ?= x86_64
CROSS_COMPILE ?=
endif
###########################################
all: modules
modules:
make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
install:
mkdir -p $(MODDESTDIR)
install -p -m 644 $(MODULE_NAME).ko $(MODDESTDIR)
/sbin/depmod -a ${KVER}
uninstall:
rm -rfv $(MODDESTDIR)/$(MODULE_NAME).ko
/sbin/depmod -a ${KVER}
clean:
rm -rf *.o *.ko *.o.* *.mod.* modules.* Module.* .a* .o* .*.o.* *.mod .tmp* .cache.mk

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,73 @@
/******************************************************************************
*
* Copyright(c) 2007 - 2017 Realtek Corporation.
*
* 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 the GNU General Public License for
* more details.
*
*****************************************************************************/
#ifndef _AIC_BR_EXT_H_
#define _AIC_BR_EXT_H_
#define CL_IPV6_PASS 1
#define MACADDRLEN 6
#define WLAN_ETHHDR_LEN 14
#define NAT25_HASH_BITS 4
#define NAT25_HASH_SIZE (1 << NAT25_HASH_BITS)
#define NAT25_AGEING_TIME 300
#define NDEV_FMT "%s"
#define NDEV_ARG(ndev) ndev->name
#define ADPT_FMT "%s"
//#define ADPT_ARG(adapter) (adapter->pnetdev ? adapter->pnetdev->name : NULL)
#define FUNC_NDEV_FMT "%s(%s)"
#define FUNC_NDEV_ARG(ndev) __func__, ndev->name
#define FUNC_ADPT_FMT "%s(%s)"
//#define FUNC_ADPT_ARG(adapter) __func__, (adapter->pnetdev ? adapter->pnetdev->name : NULL)
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
#define MAC_ARG(x) ((u8 *)(x))[0], ((u8 *)(x))[1], ((u8 *)(x))[2], ((u8 *)(x))[3], ((u8 *)(x))[4], ((u8 *)(x))[5]
#ifdef CL_IPV6_PASS
#define MAX_NETWORK_ADDR_LEN 17
#else
#define MAX_NETWORK_ADDR_LEN 11
#endif
struct nat25_network_db_entry {
struct nat25_network_db_entry *next_hash;
struct nat25_network_db_entry **pprev_hash;
atomic_t use_count;
unsigned char macAddr[6];
unsigned long ageing_timer;
unsigned char networkAddr[MAX_NETWORK_ADDR_LEN];
};
enum NAT25_METHOD {
NAT25_MIN,
NAT25_CHECK,
NAT25_INSERT,
NAT25_LOOKUP,
NAT25_PARSE,
NAT25_MAX
};
struct br_ext_info {
unsigned int nat25_disable;
unsigned int macclone_enable;
unsigned int dhcp_bcst_disable;
int addPPPoETag; /* 1: Add PPPoE relay-SID, 0: disable */
unsigned char nat25_dmzMac[MACADDRLEN];
unsigned int nat25sc_disable;
};
void nat25_db_cleanup(struct rwnx_vif *vif);
#endif /* _AIC_BR_EXT_H_ */

View File

@ -0,0 +1,58 @@
#ifndef __AIC_BSP_EXPORT_H
#define __AIC_BSP_EXPORT_H
enum aicbsp_subsys {
AIC_BLUETOOTH,
AIC_WIFI,
};
enum aicbsp_pwr_state {
AIC_PWR_OFF,
AIC_PWR_ON,
};
struct aicbsp_feature_t {
int hwinfo;
uint32_t sdio_clock;
uint8_t sdio_phase;
int fwlog_en;
uint8_t irqf;
};
enum skb_buff_id {
AIC_RESV_MEM_TXDATA,
};
#ifdef CONFIG_DPD
typedef struct {
uint32_t bit_mask[3];
uint32_t reserved;
uint32_t dpd_high[96];
uint32_t dpd_11b[96];
uint32_t dpd_low[96];
uint32_t idac_11b[48];
uint32_t idac_high[48];
uint32_t idac_low[48];
uint32_t loft_res[18];
uint32_t rx_iqim_res[16];
} rf_misc_ram_t;
typedef struct {
uint32_t bit_mask[4];
uint32_t dpd_high[96];
uint32_t loft_res[18];
} rf_misc_ram_lite_t;
#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
#define DPD_RESULT_SIZE_8800DC sizeof(rf_misc_ram_lite_t)
extern rf_misc_ram_lite_t dpd_res;
#endif
int aicbsp_set_subsys(int, int);
int aicbsp_get_feature(struct aicbsp_feature_t *feature, char *fw_path);
bool aicbsp_get_load_fw_in_fdrv(void);
struct sk_buff *aicbsp_resv_mem_alloc_skb(unsigned int length, uint32_t id);
void aicbsp_resv_mem_kfree_skb(struct sk_buff *skb, uint32_t id);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,549 @@
#ifndef _AICWF_SDIO_BT_H_
#define _AICWF_SDIO_BT_H_
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/poll.h>
#include <linux/version.h>
#include <linux/pm_runtime.h>
#include <linux/firmware.h>
#include <linux/suspend.h>
#ifdef CONFIG_PLATFORM_UBUNTU
#define CONFIG_BLUEDROID 1 /* bleuz 0, bluedroid 1 */
#else
#define CONFIG_BLUEDROID 1 /* bleuz 0, bluedroid 1 */
#endif
/* #define HCI_VERSION_CODE KERNEL_VERSION(3, 14, 41) */
#define HCI_VERSION_CODE LINUX_VERSION_CODE
#define PRINT_CMD_EVENT 1
#define PRINT_ACL_DATA 1
#define PRINT_SCO_DATA 1
#define AICBT_DBG_FLAG 1
#if AICBT_DBG_FLAG
#define AICBT_DBG(fmt, arg...) printk( "aic_btsdio: " fmt "\n" , ## arg)
#else
#define AICBT_DBG(fmt, arg...)
#endif
#define AICBT_INFO(fmt, arg...) printk("aic_btsdio: " fmt "\n" , ## arg)
#define AICBT_WARN(fmt, arg...) printk("aic_btsdio: " fmt "\n" , ## arg)
#define AICBT_ERR(fmt, arg...) printk("aic_btsdio: " fmt "\n" , ## arg)
#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 4, 0)
#define GET_DRV_DATA(x) hci_get_drvdata(x)
#else
#define GET_DRV_DATA(x) x->driver_data
#endif
struct btusb_data {
struct hci_dev *hdev;
//struct usb_device *udev;
//struct usb_interface *intf;
//struct usb_interface *isoc;
spinlock_t lock;
unsigned long flags;
struct work_struct work;
struct work_struct waker;
/*struct usb_anchor tx_anchor;
struct usb_anchor intr_anchor;
struct usb_anchor bulk_anchor;
struct usb_anchor isoc_anchor;
struct usb_anchor deferred;*/
int tx_in_flight;
spinlock_t txlock;
#if (CONFIG_BLUEDROID == 0)
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
spinlock_t rxlock;
struct sk_buff *evt_skb;
struct sk_buff *acl_skb;
struct sk_buff *sco_skb;
#endif
#endif
/*struct usb_endpoint_descriptor *intr_ep;
struct usb_endpoint_descriptor *bulk_tx_ep;
struct usb_endpoint_descriptor *bulk_rx_ep;
struct usb_endpoint_descriptor *isoc_tx_ep;
struct usb_endpoint_descriptor *isoc_rx_ep;*/
__u8 cmdreq_type;
unsigned int sco_num;
int isoc_altsetting;
int suspend_count;
uint16_t sco_handle;
#if (CONFIG_BLUEDROID == 0)
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
int (*recv_bulk) (struct btusb_data * data, void *buffer, int count);
#endif
#endif
//#ifdef CONFIG_HAS_EARLYSUSPEND
#if 0
struct early_suspend early_suspend;
#else
struct notifier_block pm_notifier;
struct notifier_block reboot_notifier;
#endif
//firmware_info *fw_info;
#ifdef CONFIG_SCO_OVER_HCI
AIC_sco_card_t *pSCOSnd;
#endif
};
#define QUEUE_SIZE 500
/***************************************
** AicSemi - Integrate from bluetooth.h **
*****************************************/
/* Reserv for core and drivers use */
#define BT_SKB_RESERVE 8
/* BD Address */
typedef struct {
__u8 b[6];
} __packed bdaddr_t;
/* Skb helpers */
struct bt_skb_cb {
__u8 pkt_type;
__u8 incoming;
__u16 expect;
__u16 tx_seq;
__u8 retries;
__u8 sar;
__u8 force_active;
};
#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
/***********************************
** AicSemi - Integrate from hci.h **
***********************************/
#define HCI_MAX_ACL_SIZE 1024
#define HCI_MAX_SCO_SIZE 255
#define HCI_MAX_EVENT_SIZE 260
#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4)
/* HCI bus types */
#define HCI_VIRTUAL 0
#define HCI_USB 1
#define HCI_PCCARD 2
#define HCI_UART 3
#define HCI_RS232 4
#define HCI_PCI 5
#define HCI_SDIO 6
/* HCI controller types */
#define HCI_BREDR 0x00
#define HCI_AMP 0x01
/* HCI device flags */
enum {
HCI_UP,
HCI_INIT,
HCI_RUNNING,
HCI_PSCAN,
HCI_ISCAN,
HCI_AUTH,
HCI_ENCRYPT,
HCI_INQUIRY,
HCI_RAW,
HCI_RESET,
};
/*
* BR/EDR and/or LE controller flags: the flags defined here should represent
* states from the controller.
*/
enum {
HCI_SETUP,
HCI_AUTO_OFF,
HCI_MGMT,
HCI_PAIRABLE,
HCI_SERVICE_CACHE,
HCI_LINK_KEYS,
HCI_DEBUG_KEYS,
HCI_UNREGISTER,
HCI_LE_SCAN,
HCI_SSP_ENABLED,
HCI_HS_ENABLED,
HCI_LE_ENABLED,
HCI_CONNECTABLE,
HCI_DISCOVERABLE,
HCI_LINK_SECURITY,
HCI_PENDING_CLASS,
};
/* HCI data types */
#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
#define HCI_MAX_NAME_LENGTH 248
#define HCI_MAX_EIR_LENGTH 240
#define HCI_OP_READ_LOCAL_VERSION 0x1001
struct hci_rp_read_local_version {
__u8 status;
__u8 hci_ver;
__le16 hci_rev;
__u8 lmp_ver;
__le16 manufacturer;
__le16 lmp_subver;
} __packed;
#define HCI_EV_CMD_COMPLETE 0x0e
struct hci_ev_cmd_complete {
__u8 ncmd;
__le16 opcode;
} __packed;
/* ---- HCI Packet structures ---- */
#define HCI_COMMAND_HDR_SIZE 3
#define HCI_EVENT_HDR_SIZE 2
#define HCI_ACL_HDR_SIZE 4
#define HCI_SCO_HDR_SIZE 3
struct hci_command_hdr {
__le16 opcode; /* OCF & OGF */
__u8 plen;
} __packed;
struct hci_event_hdr {
__u8 evt;
__u8 plen;
} __packed;
struct hci_acl_hdr {
__le16 handle; /* Handle & Flags(PB, BC) */
__le16 dlen;
} __packed;
struct hci_sco_hdr {
__le16 handle;
__u8 dlen;
} __packed;
static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb)
{
return (struct hci_event_hdr *) skb->data;
}
static inline struct hci_acl_hdr *hci_acl_hdr(const struct sk_buff *skb)
{
return (struct hci_acl_hdr *) skb->data;
}
static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
{
return (struct hci_sco_hdr *) skb->data;
}
/* ---- HCI Ioctl requests structures ---- */
struct hci_dev_stats {
__u32 err_rx;
__u32 err_tx;
__u32 cmd_tx;
__u32 evt_rx;
__u32 acl_tx;
__u32 acl_rx;
__u32 sco_tx;
__u32 sco_rx;
__u32 byte_rx;
__u32 byte_tx;
};
/* AicSemi - Integrate from hci.h end */
/*****************************************
** AicSemi - Integrate from hci_core.h **
*****************************************/
struct hci_conn_hash {
struct list_head list;
unsigned int acl_num;
unsigned int sco_num;
unsigned int le_num;
};
#define HCI_MAX_SHORT_NAME_LENGTH 10
#define NUM_REASSEMBLY 4
struct hci_dev {
struct mutex lock;
char name[8];
unsigned long flags;
__u16 id;
__u8 bus;
__u8 dev_type;
struct sk_buff *reassembly[NUM_REASSEMBLY];
struct hci_conn_hash conn_hash;
struct hci_dev_stats stat;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 4, 0)
atomic_t refcnt;
struct module *owner;
void *driver_data;
#endif
atomic_t promisc;
struct device *parent;
struct device dev;
unsigned long dev_flags;
int (*open)(struct hci_dev *hdev);
int (*close)(struct hci_dev *hdev);
int (*flush)(struct hci_dev *hdev);
int (*send)(struct sk_buff *skb);
#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 4, 0)
void (*destruct)(struct hci_dev *hdev);
#endif
#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 7, 1)
__u16 voice_setting;
#endif
void (*notify)(struct hci_dev *hdev, unsigned int evt);
int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
u8 *align_data;
};
#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 4, 0)
static inline struct hci_dev *__hci_dev_hold(struct hci_dev *d)
{
atomic_inc(&d->refcnt);
return d;
}
static inline void __hci_dev_put(struct hci_dev *d)
{
if (atomic_dec_and_test(&d->refcnt))
d->destruct(d);
}
#endif
static inline void *hci_get_drvdata(struct hci_dev *hdev)
{
return dev_get_drvdata(&hdev->dev);
}
static inline void hci_set_drvdata(struct hci_dev *hdev, void *data)
{
dev_set_drvdata(&hdev->dev, data);
}
#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev))
/* ---- HCI Packet structures ---- */
#define HCI_COMMAND_HDR_SIZE 3
#define HCI_EVENT_HDR_SIZE 2
#define HCI_ACL_HDR_SIZE 4
#define HCI_SCO_HDR_SIZE 3
/* ----- HCI Commands ---- */
#define HCI_OP_INQUIRY 0x0401
#define HCI_OP_INQUIRY_CANCEL 0x0402
#define HCI_OP_EXIT_PERIODIC_INQ 0x0404
#define HCI_OP_CREATE_CONN 0x0405
#define HCI_OP_DISCONNECT 0x0406
#define HCI_OP_ADD_SCO 0x0407
#define HCI_OP_CREATE_CONN_CANCEL 0x0408
#define HCI_OP_ACCEPT_CONN_REQ 0x0409
#define HCI_OP_REJECT_CONN_REQ 0x040a
#define HCI_OP_LINK_KEY_REPLY 0x040b
#define HCI_OP_LINK_KEY_NEG_REPLY 0x040c
#define HCI_OP_PIN_CODE_REPLY 0x040d
#define HCI_OP_PIN_CODE_NEG_REPLY 0x040e
#define HCI_OP_CHANGE_CONN_PTYPE 0x040f
#define HCI_OP_AUTH_REQUESTED 0x0411
#define HCI_OP_SET_CONN_ENCRYPT 0x0413
#define HCI_OP_CHANGE_CONN_LINK_KEY 0x0415
#define HCI_OP_REMOTE_NAME_REQ 0x0419
#define HCI_OP_REMOTE_NAME_REQ_CANCEL 0x041a
#define HCI_OP_READ_REMOTE_FEATURES 0x041b
#define HCI_OP_READ_REMOTE_EXT_FEATURES 0x041c
#define HCI_OP_READ_REMOTE_VERSION 0x041d
#define HCI_OP_SETUP_SYNC_CONN 0x0428
#define HCI_OP_ACCEPT_SYNC_CONN_REQ 0x0429
#define HCI_OP_REJECT_SYNC_CONN_REQ 0x042a
#define HCI_OP_SNIFF_MODE 0x0803
#define HCI_OP_EXIT_SNIFF_MODE 0x0804
#define HCI_OP_ROLE_DISCOVERY 0x0809
#define HCI_OP_SWITCH_ROLE 0x080b
#define HCI_OP_READ_LINK_POLICY 0x080c
#define HCI_OP_WRITE_LINK_POLICY 0x080d
#define HCI_OP_READ_DEF_LINK_POLICY 0x080e
#define HCI_OP_WRITE_DEF_LINK_POLICY 0x080f
#define HCI_OP_SNIFF_SUBRATE 0x0811
#define HCI_OP_Write_Link_Policy_Settings 0x080d
#define HCI_OP_SET_EVENT_MASK 0x0c01
#define HCI_OP_RESET 0x0c03
#define HCI_OP_SET_EVENT_FLT 0x0c05
#define HCI_OP_Write_Extended_Inquiry_Response 0x0c52
#define HCI_OP_Write_Simple_Pairing_Mode 0x0c56
#define HCI_OP_Read_Buffer_Size 0x1005
#define HCI_OP_Host_Buffer_Size 0x0c33
#define HCI_OP_Read_Local_Version_Information 0x1001
#define HCI_OP_Read_BD_ADDR 0x1009
#define HCI_OP_Read_Local_Supported_Commands 0x1002
#define HCI_OP_Write_Scan_Enable 0x0c1a
#define HCI_OP_Write_Current_IAC_LAP 0x0c3a
#define HCI_OP_Write_Inquiry_Scan_Activity 0x0c1e
#define HCI_OP_Write_Class_of_Device 0x0c24
#define HCI_OP_LE_Rand 0x2018
#define HCI_OP_LE_Set_Random_Address 0x2005
#define HCI_OP_LE_Set_Extended_Scan_Enable 0x2042
#define HCI_OP_LE_Set_Extended_Scan_Parameters 0x2041
#define HCI_OP_Set_Event_Filter 0x0c05
#define HCI_OP_Write_Voice_Setting 0x0c26
#define HCI_OP_Change_Local_Name 0x0c13
#define HCI_OP_Read_Local_Name 0x0c14
#define HCI_OP_Wirte_Page_Timeout 0x0c18
#define HCI_OP_LE_Clear_Resolving_List 0x0c29
#define HCI_OP_LE_Set_Addres_Resolution_Enable_Command 0x0c2e
#define HCI_OP_Write_Inquiry_mode 0x0c45
#define HCI_OP_Write_Page_Scan_Type 0x0c47
#define HCI_OP_Write_Inquiry_Scan_Type 0x0c43
#define HCI_OP_Delete_Stored_Link_Key 0x0c12
#define HCI_OP_LE_Read_Local_Resolvable_Address 0x202d
#define HCI_OP_LE_Extended_Create_Connection 0x2043
#define HCI_OP_Read_Remote_Version_Information 0x041d
#define HCI_OP_LE_Start_Encryption 0x2019
#define HCI_OP_LE_Add_Device_to_Resolving_List 0x2027
#define HCI_OP_LE_Set_Privacy_Mode 0x204e
#define HCI_OP_LE_Connection_Update 0x2013
/* ----- HCI events---- */
#define HCI_OP_DISCONNECT 0x0406
#define HCI_EV_INQUIRY_COMPLETE 0x01
#define HCI_EV_INQUIRY_RESULT 0x02
#define HCI_EV_CONN_COMPLETE 0x03
#define HCI_EV_CONN_REQUEST 0x04
#define HCI_EV_DISCONN_COMPLETE 0x05
#define HCI_EV_AUTH_COMPLETE 0x06
#define HCI_EV_REMOTE_NAME 0x07
#define HCI_EV_ENCRYPT_CHANGE 0x08
#define HCI_EV_CHANGE_LINK_KEY_COMPLETE 0x09
#define HCI_EV_REMOTE_FEATURES 0x0b
#define HCI_EV_REMOTE_VERSION 0x0c
#define HCI_EV_QOS_SETUP_COMPLETE 0x0d
#define HCI_EV_CMD_COMPLETE 0x0e
#define HCI_EV_CMD_STATUS 0x0f
#define HCI_EV_ROLE_CHANGE 0x12
#define HCI_EV_NUM_COMP_PKTS 0x13
#define HCI_EV_MODE_CHANGE 0x14
#define HCI_EV_PIN_CODE_REQ 0x16
#define HCI_EV_LINK_KEY_REQ 0x17
#define HCI_EV_LINK_KEY_NOTIFY 0x18
#define HCI_EV_CLOCK_OFFSET 0x1c
#define HCI_EV_PKT_TYPE_CHANGE 0x1d
#define HCI_EV_PSCAN_REP_MODE 0x20
#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22
#define HCI_EV_REMOTE_EXT_FEATURES 0x23
#define HCI_EV_SYNC_CONN_COMPLETE 0x2c
#define HCI_EV_SYNC_CONN_CHANGED 0x2d
#define HCI_EV_SNIFF_SUBRATE 0x2e
#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2f
#define HCI_EV_IO_CAPA_REQUEST 0x31
#define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36
#define HCI_EV_REMOTE_HOST_FEATURES 0x3d
#define HCI_EV_LE_Meta 0x3e
/* ULP Event sub code */
#define HCI_BLE_CONN_COMPLETE_EVT 0x01
#define HCI_BLE_ADV_PKT_RPT_EVT 0x02
#define HCI_BLE_LL_CONN_PARAM_UPD_EVT 0x03
#define HCI_BLE_READ_REMOTE_FEAT_CMPL_EVT 0x04
#define HCI_BLE_LTK_REQ_EVT 0x05
#define HCI_BLE_RC_PARAM_REQ_EVT 0x06
#define HCI_BLE_DATA_LENGTH_CHANGE_EVT 0x07
#define HCI_BLE_ENHANCED_CONN_COMPLETE_EVT 0x0a
#define HCI_BLE_DIRECT_ADV_EVT 0x0b
#define HCI_BLE_PHY_UPDATE_COMPLETE_EVT 0x0c
#define HCI_LE_EXTENDED_ADVERTISING_REPORT_EVT 0x0D
#define HCI_BLE_PERIODIC_ADV_SYNC_EST_EVT 0x0E
#define HCI_BLE_PERIODIC_ADV_REPORT_EVT 0x0F
#define HCI_BLE_PERIODIC_ADV_SYNC_LOST_EVT 0x10
#define HCI_BLE_SCAN_TIMEOUT_EVT 0x11
#define HCI_LE_ADVERTISING_SET_TERMINATED_EVT 0x12
#define HCI_BLE_SCAN_REQ_RX_EVT 0x13
#define HCI_BLE_CIS_EST_EVT 0x19
#define HCI_BLE_CIS_REQ_EVT 0x1a
#define HCI_BLE_CREATE_BIG_CPL_EVT 0x1b
#define HCI_BLE_TERM_BIG_CPL_EVT 0x1c
#define HCI_BLE_BIG_SYNC_EST_EVT 0x1d
#define HCI_BLE_BIG_SYNC_LOST_EVT 0x1e
#define HCI_BLE_REQ_PEER_SCA_CPL_EVT 0x1f
#define HCI_VENDOR_SPECIFIC_EVT 0xFF /* Vendor specific events */
#define CONFIG_MAC_OFFSET_GEN_1_2 (0x3C) //MAC's OFFSET in config/efuse for aic generation 1~2 bluetooth chip
#define CONFIG_MAC_OFFSET_GEN_3PLUS (0x44) //MAC's OFFSET in config/efuse for aic generation 3+ bluetooth chip
//Define ioctl cmd the same as HCIDEVUP in the kernel
#define DOWN_FW_CFG _IOW('E', 176, int)
//#ifdef CONFIG_SCO_OVER_HCI
//#define SET_ISO_CFG _IOW('H', 202, int)
//#else
#define SET_ISO_CFG _IOW('E', 177, int)
//#endif
#define RESET_CONTROLLER _IOW('E', 178, int)
#define DWFW_CMPLT _IOW('E', 179, int)
#define GET_USB_INFO _IOR('E', 180, int)
void bt_data_dump(char* tag, void* data, unsigned long len);
int aic_enqueue(struct sk_buff *skb);
int aic_queue_cnt(void);
int bt_sdio_recv(u8 *data,u32 data_len);
int btchr_init(void);
void btchr_exit(void);
int hdev_init(void);
void hdev_exit(void);
struct hci_dev *hci_dev_get(int index);
int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count);
#endif//_AICWF_SDIO_BT_H_

View File

@ -0,0 +1,909 @@
#include "aic_vendor.h"
#include "rwnx_defs.h"
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/rtnetlink.h>
#include <net/netlink.h>
#include "rwnx_version_gen.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
static struct wifi_ring_buffer_status ring_buffer[] = {
{
.name = "aicwf_ring_buffer0",
.flags = 0,
.ring_id = 0,
.verbose_level = 0,
.written_bytes = 0,
.read_bytes = 0,
.written_records = 0,
},
};
static struct wlan_driver_wake_reason_cnt_t wake_reason_cnt = {
.total_cmd_event_wake = 10,
};
#endif
int aic_dev_start_mkeep_alive(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
u8 mkeep_alive_id, u8 *ip_pkt, u16 ip_pkt_len, u8 *src_mac, u8 *dst_mac, u32 period_msec)
{
u8 *data, *pos;
data = kzalloc(ip_pkt_len + 14, GFP_KERNEL);
if (!data)
return -ENOMEM;
pos = data;
memcpy(pos, dst_mac, 6);
pos += 6;
memcpy(pos, src_mac, 6);
pos += 6;
/* Mapping Ethernet type (ETHERTYPE_IP: 0x0800) */
*(pos++) = 0x08;
*(pos++) = 0x00;
/* Mapping IP pkt */
memcpy(pos, ip_pkt, ip_pkt_len);
pos += ip_pkt_len;
//add send 802.3 pkt(raw data)
kfree(data);
return 0;
}
int aic_dev_stop_mkeep_alive(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, u8 mkeep_alive_id)
{
int res = -1;
/*
* The mkeep_alive packet is for STA interface only; if the bss is configured as AP,
* dongle shall reject a mkeep_alive request.
*/
if (rwnx_vif->wdev.iftype != NL80211_IFTYPE_STATION)
return res;
printk("%s execution\n", __func__);
//add send stop keep alive
res = 0;
return res;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
static int aicwf_vendor_start_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int len)
{
/* max size of IP packet for keep alive */
const int MKEEP_ALIVE_IP_PKT_MAX = 256;
int ret = 0, rem, type;
u8 mkeep_alive_id = 0;
u8 *ip_pkt = NULL;
u16 ip_pkt_len = 0;
u8 src_mac[6];
u8 dst_mac[6];
u32 period_msec = 0;
const struct nlattr *iter;
struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
struct rwnx_vif *rwnx_vif = container_of(wdev, struct rwnx_vif, wdev);
gfp_t kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
printk("%s\n", __func__);
nla_for_each_attr(iter, data, len, rem) {
type = nla_type(iter);
switch (type) {
case MKEEP_ALIVE_ATTRIBUTE_ID:
mkeep_alive_id = nla_get_u8(iter);
break;
case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN:
ip_pkt_len = nla_get_u16(iter);
if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) {
ret = -EINVAL;
goto exit;
}
break;
case MKEEP_ALIVE_ATTRIBUTE_IP_PKT:
if (!ip_pkt_len) {
ret = -EINVAL;
printk("ip packet length is 0\n");
goto exit;
}
ip_pkt = (u8 *)kzalloc(ip_pkt_len, kflags);
if (ip_pkt == NULL) {
ret = -ENOMEM;
printk("Failed to allocate mem for ip packet\n");
goto exit;
}
memcpy(ip_pkt, (u8 *)nla_data(iter), ip_pkt_len);
break;
case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR:
memcpy(src_mac, nla_data(iter), 6);
break;
case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR:
memcpy(dst_mac, nla_data(iter), 6);
break;
case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC:
period_msec = nla_get_u32(iter);
break;
default:
pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, type);
ret = -EINVAL;
goto exit;
}
}
if (ip_pkt == NULL) {
ret = -EINVAL;
printk("ip packet is NULL\n");
goto exit;
}
ret = aic_dev_start_mkeep_alive(rwnx_hw, rwnx_vif, mkeep_alive_id, ip_pkt, ip_pkt_len, src_mac,
dst_mac, period_msec);
if (ret < 0) {
printk("start_mkeep_alive is failed ret: %d\n", ret);
}
exit:
if (ip_pkt) {
kfree(ip_pkt);
}
return ret;
}
static int aicwf_vendor_stop_mkeep_alive(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int len)
{
int ret = 0, rem, type;
u8 mkeep_alive_id = 0;
const struct nlattr *iter;
struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
struct rwnx_vif *rwnx_vif = container_of(wdev, struct rwnx_vif, wdev);
printk("%s\n", __func__);
nla_for_each_attr(iter, data, len, rem) {
type = nla_type(iter);
switch (type) {
case MKEEP_ALIVE_ATTRIBUTE_ID:
mkeep_alive_id = nla_get_u8(iter);
break;
default:
pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, type);
ret = -EINVAL;
break;
}
}
ret = aic_dev_stop_mkeep_alive(rwnx_hw, rwnx_vif, mkeep_alive_id);
if (ret < 0) {
printk("stop_mkeep_alive is failed ret: %d\n", ret);
}
return ret;
}
static int aicwf_vendor_get_ver(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int len)
{
int ret = 0, rem, type;
const struct nlattr *iter;
int payload = 0;
char version[128];
int attr = -1;
struct sk_buff *reply;
nla_for_each_attr(iter, data, len, rem) {
type = nla_type(iter);
switch (type) {
case LOGGER_ATTRIBUTE_DRIVER_VER:
memcpy(version, RWNX_VERS_BANNER, sizeof(RWNX_VERS_BANNER));
payload = strlen(version);
attr = LOGGER_ATTRIBUTE_DRIVER_VER;
break;
case LOGGER_ATTRIBUTE_FW_VER:
memcpy(version, wiphy->fw_version, sizeof(wiphy->fw_version));
payload = strlen(version);
attr = LOGGER_ATTRIBUTE_FW_VER;
break;
default:
AICWFDBG(LOGERROR, "%s(%d), Unknown type: %d\n", __func__, __LINE__, type);
return -EINVAL;
}
}
if (attr < 0)
return -EINVAL;
reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
if (!reply)
return -ENOMEM;
if (nla_put(reply, attr,
payload, version)) {
wiphy_err(wiphy, "%s put version error\n", __func__);
goto out_put_fail;
}
ret = cfg80211_vendor_cmd_reply(reply);
if (ret)
wiphy_err(wiphy, "%s reply cmd error\n", __func__);
return ret;
out_put_fail:
kfree_skb(reply);
return -EMSGSIZE;
}
static int aicwf_vendor_subcmd_get_channel_list(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int len)
{
int ret = 0, rem, type;
const struct nlattr *iter;
struct sk_buff *reply;
int num_channels = 0;
int *channel_list = NULL;
int payload;
int i = 0;
struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
struct ieee80211_supported_band *rwnx_band_2GHz = rwnx_hw->wiphy->bands[NL80211_BAND_2GHZ];
struct ieee80211_supported_band *rwnx_band_5GHz = rwnx_hw->wiphy->bands[NL80211_BAND_5GHZ];
num_channels += rwnx_band_2GHz->n_channels;
num_channels += (rwnx_hw->band_5g_support) ? rwnx_band_5GHz->n_channels : 0;
channel_list = (int *)kzalloc(sizeof(int) * num_channels, GFP_KERNEL);
if (!channel_list)
return -ENOMEM;
for (i = 0; i < rwnx_band_2GHz->n_channels; i++)
channel_list[i] = rwnx_band_2GHz->channels[i].center_freq;
for (; rwnx_hw->band_5g_support && i < num_channels; i++)
channel_list[i] = rwnx_band_5GHz->channels[i].center_freq;
payload = sizeof(num_channels) + sizeof(int) * num_channels + 4;
nla_for_each_attr(iter, data, len, rem) {
type = nla_type(iter);
switch (type) {
case GSCAN_ATTRIBUTE_BAND:
reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
if (!reply)
return -ENOMEM;
if (nla_put_u32(reply, GSCAN_ATTRIBUTE_NUM_CHANNELS, num_channels))
goto out_put_fail;
if (nla_put(reply, GSCAN_ATTRIBUTE_CHANNEL_LIST, sizeof(int) * num_channels, channel_list))
goto out_put_fail;
ret = cfg80211_vendor_cmd_reply(reply);
if (ret)
wiphy_err(wiphy, "%s reply cmd error\n", __func__);
break;
default:
pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, type);
return -EINVAL;
}
}
kfree(channel_list);
return ret;
out_put_fail:
kfree(channel_list);
kfree_skb(reply);
return -EMSGSIZE;
}
static int aicwf_vendor_subcmd_set_country_code(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int len)
{
int ret = 0, rem, type;
const struct nlattr *iter;
nla_for_each_attr(iter, data, len, rem) {
type = nla_type(iter);
switch (type) {
case ANDR_WIFI_ATTRIBUTE_COUNTRY:
printk("%s(%d), ANDR_WIFI_ATTRIBUTE_COUNTRY: %s\n", __func__, __LINE__, (char *)nla_data(iter));
break;
default:
pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, type);
return -EINVAL;
}
}
/* TODO
* Add handle in the future!
*/
return ret;
}
static int aicwf_vendor_logger_trigger_memory_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int len)
{
/* TODO
* Add handle in the future!
*/
return 0;
}
static int aicwf_vendor_subcmd_get_feature_set(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int len)
{
int ret;
struct sk_buff *reply;
uint32_t feature = 0, payload;
struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
payload = sizeof(feature);
reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
if (!reply)
return -ENOMEM;
/* TODO
* Add handle in the future!
*/
/*bit 1:Basic infrastructure mode*/
if (wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION))
feature |= WIFI_FEATURE_INFRA;
/*bit 2:Support for 5 GHz Band*/
if (rwnx_hw->band_5g_support)
feature |= WIFI_FEATURE_INFRA_5G;
/*bit3:HOTSPOT is a supplicant feature, enable it by default*/
feature |= WIFI_FEATURE_HOTSPOT;
/*bit 4:P2P*/
if ((wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) &&
(wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_GO)))
feature |= WIFI_FEATURE_P2P;
/*bit 5:soft AP feature supported*/
if (wiphy->interface_modes & BIT(NL80211_IFTYPE_AP))
feature |= WIFI_FEATURE_SOFT_AP;
/*bit 18:WiFi Logger*/
feature |= WIFI_FEATURE_LOGGER;
/*bit 21:WiFi mkeep_alive*/
feature |= WIFI_FEATURE_MKEEP_ALIVE;
if (nla_put_u32(reply, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, feature)) {
wiphy_err(wiphy, "%s put u32 error\n", __func__);
goto out_put_fail;
}
ret = cfg80211_vendor_cmd_reply(reply);
if (ret)
wiphy_err(wiphy, "%s reply cmd error\n", __func__);
return ret;
out_put_fail:
kfree_skb(reply);
return -EMSGSIZE;
}
static int aicwf_vendor_logger_get_feature(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int len)
{
int ret;
struct sk_buff *reply;
uint32_t feature = 0, payload;
payload = sizeof(feature);
reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
if (!reply)
return -ENOMEM;
feature |= WIFI_LOGGER_MEMORY_DUMP_SUPPORTED;
feature |= WIFI_LOGGER_CONNECT_EVENT_SUPPORTED;
/*vts will test wake reason state function*/
feature |= WIFI_LOGGER_WAKE_LOCK_SUPPORTED;
if (nla_put_u32(reply, ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET, feature)) {
wiphy_err(wiphy, "put skb u32 failed\n");
goto out_put_fail;
}
ret = cfg80211_vendor_cmd_reply(reply);
if (ret)
wiphy_err(wiphy, "reply cmd error\n");
return ret;
out_put_fail:
kfree_skb(reply);
return -EMSGSIZE;
}
static int aicwf_vendor_logger_get_ring_status(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int len)
{
int ret;
struct sk_buff *reply;
uint32_t payload;
uint32_t ring_buffer_nums = sizeof(ring_buffer) / sizeof(ring_buffer[0]);
payload = sizeof(ring_buffer_nums) + sizeof(ring_buffer);
reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
if (!reply)
return -ENOMEM;
if (nla_put_u32(reply, LOGGER_ATTRIBUTE_RING_NUM, ring_buffer_nums)) {
wiphy_err(wiphy, "put skb u32 failed\n");
goto out_put_fail;
}
if (nla_put(reply, LOGGER_ATTRIBUTE_RING_STATUS, sizeof(ring_buffer), ring_buffer)) {
wiphy_err(wiphy, "put skb failed\n");
goto out_put_fail;
}
ret = cfg80211_vendor_cmd_reply(reply);
if (ret)
wiphy_err(wiphy, "reply cmd error\n");
return ret;
out_put_fail:
kfree_skb(reply);
return -EMSGSIZE;
}
static int aicwf_vendor_logger_start_logging(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int len)
{
int ret = 0, rem, type, intval, size, i;
const struct nlattr *iter;
struct wifi_ring_buffer_status rb;
nla_for_each_attr(iter, data, len, rem) {
type = nla_type(iter);
switch (type) {
case LOGGER_ATTRIBUTE_LOG_LEVEL:
rb.verbose_level = nla_get_u32(iter);
break;
case LOGGER_ATTRIBUTE_RING_FLAGS:
rb.flags = nla_get_u32(iter);
break;
case LOGGER_ATTRIBUTE_LOG_TIME_INTVAL:
intval = nla_get_u32(iter);
break;
case LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE:
size = nla_get_u32(iter);
break;
case LOGGER_ATTRIBUTE_RING_NAME:
strcpy(rb.name, nla_data(iter));
break;
default:
AICWFDBG(LOGERROR, "%s(%d), Unknown type: %d\n", __func__, __LINE__, type);
return -EINVAL;
}
}
ret = -EINVAL;
for (i = 0; i < sizeof(ring_buffer) / sizeof(ring_buffer[0]); i++) {
if (strcmp(rb.name, ring_buffer[i].name) == 0) {
ret = 0;
break;
}
}
/* TODO
* Add handle in the future
*/
return ret;
}
static int aicwf_vendor_logger_get_ring_data(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int len)
{
int ret = 0, rem, type, i;
const struct nlattr *iter;
struct wifi_ring_buffer_status rb;
nla_for_each_attr(iter, data, len, rem) {
type = nla_type(iter);
switch (type) {
case LOGGER_ATTRIBUTE_RING_NAME:
strcpy(rb.name, nla_data(iter));
break;
default:
pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, type);
return -EINVAL;
}
}
ret = -EINVAL;
for (i = 0; i < sizeof(ring_buffer) / sizeof(ring_buffer[0]); i++) {
if (strcmp(rb.name, ring_buffer[i].name) == 0) {
ret = 0;
break;
}
}
/* TODO
* Add handle in the future
*/
return ret;
}
static int aicwf_vendor_logger_get_wake_reason_stats(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int len)
{
int ret;
struct sk_buff *reply;
uint32_t payload;
payload = sizeof(wake_reason_cnt.total_cmd_event_wake);
reply = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, payload);
if (!reply)
return -ENOMEM;
/* TODO
* Add handle in the future
*/
if (nla_put_u32(reply, WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT, wake_reason_cnt.total_cmd_event_wake))
goto out_put_fail;
ret = cfg80211_vendor_cmd_reply(reply);
if (ret)
wiphy_err(wiphy, "reply cmd error\n");
return ret;
out_put_fail:
kfree_skb(reply);
return -EMSGSIZE;
}
static int aicwf_vendor_apf_subcmd_get_capabilities(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int len)
{
/* TODO
* Add handle in the future
*/
return 0;
}
static int aicwf_vendor_sub_cmd_set_mac(struct wiphy *wiphy, struct wireless_dev *wdev,
const void *data, int len)
{
int ret = 0, rem, type;
const struct nlattr *iter;
u8 mac[ETH_ALEN];
nla_for_each_attr(iter, data, len, rem) {
type = nla_type(iter);
switch (type) {
case WIFI_VENDOR_ATTR_DRIVER_MAC_ADDR:
memcpy(mac, nla_data(iter), ETH_ALEN);
printk("%s, %02X:%02X:%02X:%02X:%02X:%02X\n", __func__,
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
break;
default:
pr_err("%s(%d), Unknown type: %d\n", __func__, __LINE__, type);
return -EINVAL;
}
}
/* TODO
* Add handle in the future
*/
return ret;
}
#endif
static const struct nla_policy
aicwf_cfg80211_mkeep_alive_policy[MKEEP_ALIVE_ATTRIBUTE_MAX+1] = {
[0] = {.type = NLA_UNSPEC },
[MKEEP_ALIVE_ATTRIBUTE_ID] = { .type = NLA_U8 },
[MKEEP_ALIVE_ATTRIBUTE_IP_PKT] = { .type = NLA_MSECS },
[MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN] = { .type = NLA_U16 },
[MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR] = { .type = NLA_MSECS,
.len = ETH_ALEN },
[MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR] = { .type = NLA_MSECS,
.len = ETH_ALEN },
[MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC] = { .type = NLA_U32 },
};
static const struct nla_policy
aicwf_cfg80211_logger_policy[LOGGER_ATTRIBUTE_MAX + 1] = {
[0] = {.type = NLA_UNSPEC },
[LOGGER_ATTRIBUTE_DRIVER_VER] = { .type = NLA_BINARY },
[LOGGER_ATTRIBUTE_FW_VER] = { .type = NLA_BINARY },
[LOGGER_ATTRIBUTE_LOG_LEVEL] = { .type = NLA_U32 },
[LOGGER_ATTRIBUTE_RING_FLAGS] = { .type = NLA_U32 },
[LOGGER_ATTRIBUTE_LOG_TIME_INTVAL] = { .type = NLA_U32 },
[LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE] = { .type = NLA_U32 },
[LOGGER_ATTRIBUTE_RING_NAME] = { .type = NLA_STRING },
};
static const struct nla_policy
aicwf_cfg80211_subcmd_policy[GSCAN_ATTRIBUTE_MAX + 1] = {
[0] = {.type = NLA_UNSPEC },
[GSCAN_ATTRIBUTE_BAND] = { .type = NLA_U32 },
};
static const struct nla_policy
aicwf_cfg80211_andr_wifi_policy[ANDR_WIFI_ATTRIBUTE_MAX + 1] = {
[0] = {.type = NLA_UNSPEC },
[ANDR_WIFI_ATTRIBUTE_COUNTRY] = { .type = NLA_STRING },
};
static const struct nla_policy
aicwf_cfg80211_subcmd_set_mac_policy[WIFI_VENDOR_ATTR_DRIVER_MAX + 1] = {
[0] = {.type = NLA_UNSPEC },
[WIFI_VENDOR_ATTR_DRIVER_MAC_ADDR] = { .type = NLA_MSECS, .len = ETH_ALEN },
};
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
static int aicwf_dump_interface(struct wiphy *wiphy,
struct wireless_dev *wdev, struct sk_buff *skb,
const void *data, int data_len,
unsigned long *storage)
{
return 0;
}
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
const struct wiphy_vendor_command aicwf_vendor_cmd[] = {
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = aicwf_vendor_start_mkeep_alive,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
.dumpit = aicwf_dump_interface,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
.policy = aicwf_cfg80211_mkeep_alive_policy,
.maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = aicwf_vendor_stop_mkeep_alive,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
.dumpit = aicwf_dump_interface,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
.policy = aicwf_cfg80211_mkeep_alive_policy,
.maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = LOGGER_GET_VER
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = aicwf_vendor_get_ver,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
.dumpit = aicwf_dump_interface,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
.policy = aicwf_cfg80211_logger_policy,
.maxattr = LOGGER_ATTRIBUTE_MAX
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = GSCAN_SUBCMD_GET_CHANNEL_LIST
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = aicwf_vendor_subcmd_get_channel_list,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
.dumpit = aicwf_dump_interface,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
.policy = aicwf_cfg80211_subcmd_policy,
.maxattr = GSCAN_ATTRIBUTE_MAX
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_SUBCMD_SET_COUNTRY_CODE
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = aicwf_vendor_subcmd_set_country_code,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
.dumpit = aicwf_dump_interface,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
.policy = aicwf_cfg80211_andr_wifi_policy,
.maxattr = ANDR_WIFI_ATTRIBUTE_MAX
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = LOGGER_TRIGGER_MEM_DUMP
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = aicwf_vendor_logger_trigger_memory_dump,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
.dumpit = aicwf_dump_interface,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
.policy = VENDOR_CMD_RAW_DATA,
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = WIFI_SUBCMD_GET_FEATURE_SET
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = aicwf_vendor_subcmd_get_feature_set,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
.dumpit = aicwf_dump_interface,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
.policy = VENDOR_CMD_RAW_DATA,
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = LOGGER_GET_FEATURE
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = aicwf_vendor_logger_get_feature,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
.dumpit = aicwf_dump_interface,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
.policy = VENDOR_CMD_RAW_DATA,
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = LOGGER_GET_RING_STATUS
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = aicwf_vendor_logger_get_ring_status,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
.dumpit = aicwf_dump_interface,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
.policy = VENDOR_CMD_RAW_DATA,
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = LOGGER_START_LOGGING
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = aicwf_vendor_logger_start_logging,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
.dumpit = aicwf_dump_interface,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
.policy = aicwf_cfg80211_logger_policy,
.maxattr = LOGGER_ATTRIBUTE_MAX
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = LOGGER_GET_RING_DATA
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = aicwf_vendor_logger_get_ring_data,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
.dumpit = aicwf_dump_interface,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
.policy = aicwf_cfg80211_logger_policy,
.maxattr = LOGGER_ATTRIBUTE_MAX
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = LOGGER_GET_WAKE_REASON_STATS
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = aicwf_vendor_logger_get_wake_reason_stats,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
.dumpit = aicwf_dump_interface,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
.policy = VENDOR_CMD_RAW_DATA,
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = APF_SUBCMD_GET_CAPABILITIES
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
.doit = aicwf_vendor_apf_subcmd_get_capabilities,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
.dumpit = aicwf_dump_interface,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
.policy = VENDOR_CMD_RAW_DATA,
#endif
},
{
{
.vendor_id = GOOGLE_OUI,
.subcmd = VENDOR_NL80211_SUBCMD_SET_MAC
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
.doit = aicwf_vendor_sub_cmd_set_mac,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
.dumpit = aicwf_dump_interface,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
.policy = aicwf_cfg80211_subcmd_set_mac_policy,
.maxattr = WIFI_VENDOR_ATTR_DRIVER_MAX,
#endif
},
{
{
.vendor_id = BRCM_OUI,
.subcmd = VENDOR_NL80211_SUBCMD_SET_MAC
},
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_RUNNING,
.doit = aicwf_vendor_sub_cmd_set_mac,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
.dumpit = aicwf_dump_interface,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
.policy = aicwf_cfg80211_subcmd_set_mac_policy,
.maxattr = WIFI_VENDOR_ATTR_DRIVER_MAX,
#endif
},
};
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
static const struct nl80211_vendor_cmd_info aicwf_vendor_events[] = {
};
#endif
int aicwf_vendor_init(struct wiphy *wiphy)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
wiphy->vendor_commands = aicwf_vendor_cmd;
wiphy->n_vendor_commands = ARRAY_SIZE(aicwf_vendor_cmd);
wiphy->vendor_events = aicwf_vendor_events;
wiphy->n_vendor_events = ARRAY_SIZE(aicwf_vendor_events);
#endif
return 0;
}

View File

@ -0,0 +1,346 @@
#ifndef _AIC_VENDOR_H
#define _AIC_VENDOR_H
#include <linux/types.h>
#define GOOGLE_OUI 0x001A11
#define BRCM_OUI 0x001018
typedef enum {
START_MKEEP_ALIVE,
STOP_MKEEP_ALIVE,
} GetCmdType;
typedef enum {
/* don't use 0 as a valid subcommand */
VENDOR_NL80211_SUBCMD_UNSPECIFIED,
/* define all vendor startup commands between 0x0 and 0x0FFF */
VENDOR_NL80211_SUBCMD_RANGE_START = 0x0001,
VENDOR_NL80211_SUBCMD_RANGE_END = 0x0FFF,
/* define all GScan related commands between 0x1000 and 0x10FF */
ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START = 0x1000,
ANDROID_NL80211_SUBCMD_GSCAN_RANGE_END = 0x10FF,
/* define all NearbyDiscovery related commands between 0x1100 and 0x11FF */
ANDROID_NL80211_SUBCMD_NBD_RANGE_START = 0x1100,
ANDROID_NL80211_SUBCMD_NBD_RANGE_END = 0x11FF,
/* define all RTT related commands between 0x1100 and 0x11FF */
ANDROID_NL80211_SUBCMD_RTT_RANGE_START = 0x1100,
ANDROID_NL80211_SUBCMD_RTT_RANGE_END = 0x11FF,
ANDROID_NL80211_SUBCMD_LSTATS_RANGE_START = 0x1200,
ANDROID_NL80211_SUBCMD_LSTATS_RANGE_END = 0x12FF,
/* define all Logger related commands between 0x1400 and 0x14FF */
ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START = 0x1400,
ANDROID_NL80211_SUBCMD_DEBUG_RANGE_END = 0x14FF,
/* define all wifi offload related commands between 0x1600 and 0x16FF */
ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START = 0x1600,
ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_END = 0x16FF,
/* define all NAN related commands between 0x1700 and 0x17FF */
ANDROID_NL80211_SUBCMD_NAN_RANGE_START = 0x1700,
ANDROID_NL80211_SUBCMD_NAN_RANGE_END = 0x17FF,
/* define all Android Packet Filter related commands between 0x1800 and 0x18FF */
ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START = 0x1800,
ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_END = 0x18FF,
/* This is reserved for future usage */
} ANDROID_VENDOR_SUB_COMMAND;
typedef enum {
WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE = ANDROID_NL80211_SUBCMD_WIFI_OFFLOAD_RANGE_START,
WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE,
} WIFI_OFFLOAD_SUB_COMMAND;
enum mkeep_alive_attributes {
MKEEP_ALIVE_ATTRIBUTE_ID = 0x1,
MKEEP_ALIVE_ATTRIBUTE_IP_PKT,
MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN,
MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR,
MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR,
MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC,
MKEEP_ALIVE_ATTRIBUTE_AFTER_LAST,
MKEEP_ALIVE_ATTRIBUTE_MAX = MKEEP_ALIVE_ATTRIBUTE_AFTER_LAST - 1
};
enum debug_sub_command {
LOGGER_START_LOGGING = ANDROID_NL80211_SUBCMD_DEBUG_RANGE_START,
LOGGER_TRIGGER_MEM_DUMP,
LOGGER_GET_MEM_DUMP,
LOGGER_GET_VER,
LOGGER_GET_RING_STATUS,
LOGGER_GET_RING_DATA,
LOGGER_GET_FEATURE,
LOGGER_RESET_LOGGING,
LOGGER_TRIGGER_DRIVER_MEM_DUMP,
LOGGER_GET_DRIVER_MEM_DUMP,
LOGGER_START_PKT_FATE_MONITORING,
LOGGER_GET_TX_PKT_FATES,
LOGGER_GET_RX_PKT_FATES,
LOGGER_GET_WAKE_REASON_STATS,
LOGGER_DEBUG_GET_DUMP,
LOGGER_FILE_DUMP_DONE_IND,
LOGGER_SET_HAL_START,
LOGGER_HAL_STOP,
LOGGER_SET_HAL_PID,
};
enum logger_attributes {
LOGGER_ATTRIBUTE_INVALID = 0,
LOGGER_ATTRIBUTE_DRIVER_VER,
LOGGER_ATTRIBUTE_FW_VER,
LOGGER_ATTRIBUTE_RING_ID,
LOGGER_ATTRIBUTE_RING_NAME,
LOGGER_ATTRIBUTE_RING_FLAGS,
LOGGER_ATTRIBUTE_LOG_LEVEL,
LOGGER_ATTRIBUTE_LOG_TIME_INTVAL,
LOGGER_ATTRIBUTE_LOG_MIN_DATA_SIZE,
LOGGER_ATTRIBUTE_FW_DUMP_LEN,
LOGGER_ATTRIBUTE_FW_DUMP_DATA,
// LOGGER_ATTRIBUTE_FW_ERR_CODE,
LOGGER_ATTRIBUTE_RING_DATA,
LOGGER_ATTRIBUTE_RING_STATUS,
LOGGER_ATTRIBUTE_RING_NUM,
LOGGER_ATTRIBUTE_DRIVER_DUMP_LEN,
LOGGER_ATTRIBUTE_DRIVER_DUMP_DATA,
LOGGER_ATTRIBUTE_PKT_FATE_NUM,
LOGGER_ATTRIBUTE_PKT_FATE_DATA,
LOGGER_ATTRIBUTE_AFTER_LAST,
LOGGER_ATTRIBUTE_MAX = LOGGER_ATTRIBUTE_AFTER_LAST - 1,
};
enum wifi_sub_command {
GSCAN_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_GSCAN_RANGE_START,
GSCAN_SUBCMD_SET_CONFIG, /* 0x1001 */
GSCAN_SUBCMD_SET_SCAN_CONFIG, /* 0x1002 */
GSCAN_SUBCMD_ENABLE_GSCAN, /* 0x1003 */
GSCAN_SUBCMD_GET_SCAN_RESULTS, /* 0x1004 */
GSCAN_SUBCMD_SCAN_RESULTS, /* 0x1005 */
GSCAN_SUBCMD_SET_HOTLIST, /* 0x1006 */
GSCAN_SUBCMD_SET_SIGNIFICANT_CHANGE_CONFIG, /* 0x1007 */
GSCAN_SUBCMD_ENABLE_FULL_SCAN_RESULTS, /* 0x1008 */
GSCAN_SUBCMD_GET_CHANNEL_LIST, /* 0x1009 */
WIFI_SUBCMD_GET_FEATURE_SET, /* 0x100A */
WIFI_SUBCMD_GET_FEATURE_SET_MATRIX, /* 0x100B */
WIFI_SUBCMD_SET_PNO_RANDOM_MAC_OUI, /* 0x100C */
WIFI_SUBCMD_NODFS_SET, /* 0x100D */
WIFI_SUBCMD_SET_COUNTRY_CODE, /* 0x100E */
/* Add more sub commands here */
GSCAN_SUBCMD_SET_EPNO_SSID, /* 0x100F */
WIFI_SUBCMD_SET_SSID_WHITE_LIST, /* 0x1010 */
WIFI_SUBCMD_SET_ROAM_PARAMS, /* 0x1011 */
WIFI_SUBCMD_ENABLE_LAZY_ROAM, /* 0x1012 */
WIFI_SUBCMD_SET_BSSID_PREF, /* 0x1013 */
WIFI_SUBCMD_SET_BSSID_BLACKLIST, /* 0x1014 */
GSCAN_SUBCMD_ANQPO_CONFIG, /* 0x1015 */
WIFI_SUBCMD_SET_RSSI_MONITOR, /* 0x1016 */
WIFI_SUBCMD_CONFIG_ND_OFFLOAD, /* 0x1017 */
/* Add more sub commands here */
GSCAN_SUBCMD_MAX,
APF_SUBCMD_GET_CAPABILITIES = ANDROID_NL80211_SUBCMD_PKT_FILTER_RANGE_START,
APF_SUBCMD_SET_FILTER,
};
enum gscan_attributes {
GSCAN_ATTRIBUTE_NUM_BUCKETS = 10,
GSCAN_ATTRIBUTE_BASE_PERIOD,
GSCAN_ATTRIBUTE_BUCKETS_BAND,
GSCAN_ATTRIBUTE_BUCKET_ID,
GSCAN_ATTRIBUTE_BUCKET_PERIOD,
GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
GSCAN_ATTRIBUTE_BUCKET_CHANNELS,
GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN,
GSCAN_ATTRIBUTE_REPORT_THRESHOLD,
GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE,
GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND,
GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20,
GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, /* indicates no more results */
GSCAN_ATTRIBUTE_FLUSH_FEATURE, /* Flush all the configs */
GSCAN_ENABLE_FULL_SCAN_RESULTS,
GSCAN_ATTRIBUTE_REPORT_EVENTS,
/* remaining reserved for additional attributes */
GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30,
GSCAN_ATTRIBUTE_FLUSH_RESULTS,
GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */
GSCAN_ATTRIBUTE_SCAN_ID, /* indicates scan number */
GSCAN_ATTRIBUTE_SCAN_FLAGS, /* indicates if scan was aborted */
GSCAN_ATTRIBUTE_AP_FLAGS, /* flags on significant change event */
GSCAN_ATTRIBUTE_NUM_CHANNELS,
GSCAN_ATTRIBUTE_CHANNEL_LIST,
GSCAN_ATTRIBUTE_CH_BUCKET_BITMASK,
GSCAN_ATTRIBUTE_AFTER_LAST,
GSCAN_ATTRIBUTE_MAX = GSCAN_ATTRIBUTE_AFTER_LAST - 1,
};
enum andr_wifi_attributes {
ANDR_WIFI_ATTRIBUTE_NUM_FEATURE_SET,
ANDR_WIFI_ATTRIBUTE_FEATURE_SET,
ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI,
ANDR_WIFI_ATTRIBUTE_NODFS_SET,
ANDR_WIFI_ATTRIBUTE_COUNTRY,
ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_VALUE,
// Add more attribute here
ANDR_WIFI_ATTRIBUTE_AFTER_LAST,
ANDR_WIFI_ATTRIBUTE_MAX = ANDR_WIFI_ATTRIBUTE_AFTER_LAST - 1,
};
enum wifi_support_feature {
/* Feature enums */
WIFI_FEATURE_INFRA = 0x0001, /* Basic infrastructure mode */
WIFI_FEATURE_INFRA_5G = 0x0002, /* Support for 5, GHz Band */
WIFI_FEATURE_HOTSPOT = 0x0004, /* Support for GAS/ANQP */
WIFI_FEATURE_P2P = 0x0008, /* Wifi-Direct */
WIFI_FEATURE_SOFT_AP = 0x0010, /* Soft AP */
WIFI_FEATURE_GSCAN = 0x0020, /* Google-Scan APIs */
WIFI_FEATURE_NAN = 0x0040, /* Neighbor Awareness Networking */
WIFI_FEATURE_D2D_RTT = 0x0080, /* Device-to-device RTT */
WIFI_FEATURE_D2AP_RTT = 0x0100, /* Device-to-AP RTT */
WIFI_FEATURE_BATCH_SCAN = 0x0200, /* Batched Scan (legacy) */
WIFI_FEATURE_PNO = 0x0400, /* Preferred network offload */
WIFI_FEATURE_ADDITIONAL_STA = 0x0800, /* Support for two STAs */
WIFI_FEATURE_TDLS = 0x1000, /* Tunnel directed link setup */
WIFI_FEATURE_TDLS_OFFCHANNEL = 0x2000, /* Support for TDLS off channel */
WIFI_FEATURE_EPR = 0x4000, /* Enhanced power reporting */
WIFI_FEATURE_AP_STA = 0x8000, /* Support for AP STA Concurrency */
WIFI_FEATURE_LINK_LAYER_STATS = 0x10000, /* Support for Linkstats */
WIFI_FEATURE_LOGGER = 0x20000, /* WiFi Logger */
WIFI_FEATURE_HAL_EPNO = 0x40000, /* WiFi PNO enhanced */
WIFI_FEATURE_RSSI_MONITOR = 0x80000, /* RSSI Monitor */
WIFI_FEATURE_MKEEP_ALIVE = 0x100000, /* WiFi mkeep_alive */
WIFI_FEATURE_CONFIG_NDO = 0x200000, /* ND offload configure */
WIFI_FEATURE_TX_TRANSMIT_POWER = 0x400000, /* Capture Tx transmit power levels */
WIFI_FEATURE_CONTROL_ROAMING = 0x800000, /* Enable/Disable firmware roaming */
WIFI_FEATURE_IE_WHITELIST = 0x1000000, /* Support Probe IE white listing */
WIFI_FEATURE_SCAN_RAND = 0x2000000, /* Support MAC & Probe Sequence Number randomization */
WIFI_FEATURE_INVALID = 0xFFFFFFFF, /* Invalid Feature */
};
enum wifi_logger_feature {
WIFI_LOGGER_MEMORY_DUMP_SUPPORTED = (1 << (0)), // Memory dump of FW
WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORTED = (1 << (1)), // PKT status
WIFI_LOGGER_CONNECT_EVENT_SUPPORTED = (1 << (2)), // Connectivity event
WIFI_LOGGER_POWER_EVENT_SUPPORTED = (1 << (3)), // POWER of Driver
WIFI_LOGGER_WAKE_LOCK_SUPPORTED = (1 << (4)), // WAKE LOCK of Driver
WIFI_LOGGER_VERBOSE_SUPPORTED = (1 << (5)), // verbose log of FW
WIFI_LOGGER_WATCHDOG_TIMER_SUPPORTED = (1 << (6)), // monitor the health of FW
WIFI_LOGGER_DRIVER_DUMP_SUPPORTED = (1 << (7)), // dumps driver state
WIFI_LOGGER_PACKET_FATE_SUPPORTED = (1 << (8)), // tracks connection packets' fate
};
enum wake_stats_attributes {
WAKE_STAT_ATTRIBUTE_TOTAL_CMD_EVENT,
WAKE_STAT_ATTRIBUTE_CMD_EVENT_WAKE,
WAKE_STAT_ATTRIBUTE_CMD_EVENT_COUNT,
WAKE_STAT_ATTRIBUTE_CMD_COUNT_USED,
WAKE_STAT_ATTRIBUTE_TOTAL_DRIVER_FW,
WAKE_STAT_ATTRIBUTE_DRIVER_FW_WAKE,
WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT,
WAKE_STAT_ATTRIBUTE_DRIVER_FW_COUNT_USED,
WAKE_STAT_ATTRIBUTE_TOTAL_RX_DATA_WAKE,
WAKE_STAT_ATTRIBUTE_RX_UNICAST_COUNT,
WAKE_STAT_ATTRIBUTE_RX_MULTICAST_COUNT,
WAKE_STAT_ATTRIBUTE_RX_BROADCAST_COUNT,
WAKE_STAT_ATTRIBUTE_RX_ICMP_PKT,
WAKE_STAT_ATTRIBUTE_RX_ICMP6_PKT,
WAKE_STAT_ATTRIBUTE_RX_ICMP6_RA,
WAKE_STAT_ATTRIBUTE_RX_ICMP6_NA,
WAKE_STAT_ATTRIBUTE_RX_ICMP6_NS,
WAKE_STAT_ATTRIBUTE_IPV4_RX_MULTICAST_ADD_CNT,
WAKE_STAT_ATTRIBUTE_IPV6_RX_MULTICAST_ADD_CNT,
WAKE_STAT_ATTRIBUTE_OTHER__RX_MULTICAST_ADD_CNT,
WAKE_STAT_ATTRIBUTE_RX_MULTICAST_PKT_INFO,
WAKE_STAT_ATTRIBUTE_AFTER_LAST,
WAKE_STAT_ATTRIBUTE_MAX = WAKE_STAT_ATTRIBUTE_AFTER_LAST - 1,
};
enum vendor_nl80211_subcmd {
/* copied from wpa_supplicant brcm definations */
VENDOR_NL80211_SUBCMD_UNSPEC = 0,
VENDOR_NL80211_SUBCMD_SET_PMK = 4,
VENDOR_NL80211_SUBCMD_SET_MAC = 6,
VENDOR_NL80211_SCMD_ACS = 9,
VENDOR_NL80211_SCMD_MAX = 10,
};
enum nl80211_vendor_subcmd_attributes {
WIFI_VENDOR_ATTR_DRIVER_CMD = 0,
WIFI_VENDOR_ATTR_DRIVER_KEY_PMK = 1,
WIFI_VENDOR_ATTR_DRIVER_MAC_ADDR = 3,
WIFI_VENDOR_ATTR_DRIVER_AFTER_LAST = 5,
WIFI_VENDOR_ATTR_DRIVER_MAX =
WIFI_VENDOR_ATTR_DRIVER_AFTER_LAST - 1,
};
typedef int wifi_ring_buffer_id;
struct wifi_ring_buffer_status {
u8 name[32];
u32 flags;
wifi_ring_buffer_id ring_id;
u32 ring_buffer_byte_size;
u32 verbose_level;
u32 written_bytes;
u32 read_bytes;
u32 written_records;
};
struct rx_data_cnt_details_t {
int rx_unicast_cnt; /*Total rx unicast packet which woke up host */
int rx_multicast_cnt; /*Total rx multicast packet which woke up host */
int rx_broadcast_cnt; /*Total rx broadcast packet which woke up host */
};
struct rx_wake_pkt_type_classification_t {
int icmp_pkt; /*wake icmp packet count */
int icmp6_pkt; /*wake icmp6 packet count */
int icmp6_ra; /*wake icmp6 RA packet count */
int icmp6_na; /*wake icmp6 NA packet count */
int icmp6_ns; /*wake icmp6 NS packet count */
//ToDo: Any more interesting classification to add?
};
struct rx_multicast_cnt_t{
int ipv4_rx_multicast_addr_cnt; /*Rx wake packet was ipv4 multicast */
int ipv6_rx_multicast_addr_cnt; /*Rx wake packet was ipv6 multicast */
int other_rx_multicast_addr_cnt;/*Rx wake packet was non-ipv4 and non-ipv6*/
};
struct wlan_driver_wake_reason_cnt_t {
int total_cmd_event_wake; /* Total count of cmd event wakes */
int *cmd_event_wake_cnt; /* Individual wake count array, each index a reason */
int cmd_event_wake_cnt_sz; /* Max number of cmd event wake reasons */
int cmd_event_wake_cnt_used; /* Number of cmd event wake reasons specific to the driver */
int total_driver_fw_local_wake; /* Total count of drive/fw wakes, for local reasons */
int *driver_fw_local_wake_cnt; /* Individual wake count array, each index a reason */
int driver_fw_local_wake_cnt_sz; /* Max number of local driver/fw wake reasons */
int driver_fw_local_wake_cnt_used; /* Number of local driver/fw wake reasons specific to the driver */
int total_rx_data_wake; /* total data rx packets, that woke up host */
struct rx_data_cnt_details_t rx_wake_details;
struct rx_wake_pkt_type_classification_t rx_wake_pkt_classification_info;
struct rx_multicast_cnt_t rx_multicast_wake_pkt_info;
};
typedef struct wl_mkeep_alive_pkt {
u16 version; /* Version for mkeep_alive */
u16 length; /* length of fixed parameters in the structure */
u32 period_msec; /* high bit on means immediate send */
u16 len_bytes;
u8 keep_alive_id; /* 0 - 3 for N = 4 */
u8 data[1];
} wl_mkeep_alive_pkt_t;
#endif /* _AIC_VENDOR_H */

View File

@ -0,0 +1,66 @@
#include "rwnx_main.h"
#include "rwnx_msg_tx.h"
#include "reg_access.h"
#include "aicwf_compat_8800d80.h"
#define FW_USERCONFIG_NAME_8800D80 "aic_userconfig_8800d80.txt"
int rwnx_request_firmware_common(struct rwnx_hw *rwnx_hw,
u32** buffer, const char *filename);
void rwnx_plat_userconfig_parsing2(char *buffer, int size);
void rwnx_plat_userconfig_parsing3(char *buffer, int size);
void rwnx_release_firmware_common(u32** buffer);
int aicwf_set_rf_config_8800d80(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm)
{
int ret = 0;
if ((ret = rwnx_send_txpwr_lvl_v3_req(rwnx_hw))) {
return -1;
}
if ((ret = rwnx_send_txpwr_lvl_adj_req(rwnx_hw))) {
return -1;
}
if ((ret = rwnx_send_txpwr_ofst2x_req(rwnx_hw))) {
return -1;
}
if ((ret = rwnx_send_rf_calib_req(rwnx_hw, cfm))) {
return -1;
}
return 0 ;
}
int rwnx_plat_userconfig_load_8800d80(struct rwnx_hw *rwnx_hw)
{
int size;
u32 *dst=NULL;
char *filename = FW_USERCONFIG_NAME_8800D80;
AICWFDBG(LOGINFO, "userconfig file path:%s \r\n", filename);
/* load file */
size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
if (size <= 0) {
AICWFDBG(LOGERROR, "wrong size of firmware file\n");
dst = NULL;
return 0;
}
/* Copy the file on the Embedded side */
AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size);
rwnx_plat_userconfig_parsing3((char *)dst, size);
rwnx_release_firmware_common(&dst);
AICWFDBG(LOGINFO, "userconfig download complete\n\n");
return 0;
}

View File

@ -0,0 +1,9 @@
#ifndef _AICWF_COMPAT_8800D80_H_
#define _AICWF_COMPAT_8800D80_H_
#include <linux/types.h>
int aicwf_set_rf_config_8800d80(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm);
int rwnx_plat_userconfig_load_8800d80(struct rwnx_hw *rwnx_hw);
#endif

View File

@ -0,0 +1,542 @@
#include "rwnx_main.h"
#include "rwnx_msg_tx.h"
#include "reg_access.h"
#include "aic_bsp_export.h"
#define RWNX_MAC_RF_PATCH_BASE_NAME_8800DC "fmacfw_rf_patch_8800dc"
#define RWNX_MAC_RF_PATCH_NAME_8800DC RWNX_MAC_RF_PATCH_BASE_NAME_8800DC".bin"
#define FW_USERCONFIG_NAME_8800DC "aic_userconfig_8800dc.txt"
#define FW_USERCONFIG_NAME_8800DW "aic_userconfig_8800dw.txt"
int rwnx_plat_bin_fw_upload_2(struct rwnx_hw *rwnx_hw, u32 fw_addr,
char *filename);
int rwnx_request_firmware_common(struct rwnx_hw *rwnx_hw,
u32** buffer, const char *filename);
void rwnx_plat_userconfig_parsing2(char *buffer, int size);
void rwnx_release_firmware_common(u32** buffer);
u32 wifi_txgain_table_24g_8800dcdw[32] =
{
0xA4B22189, //index 0
0x00007825,
0xA4B2214B, //index 1
0x00007825,
0xA4B2214F, //index 2
0x00007825,
0xA4B221D5, //index 3
0x00007825,
0xA4B221DC, //index 4
0x00007825,
0xA4B221E5, //index 5
0x00007825,
0xAC9221E5, //index 6
0x00006825,
0xAC9221EF, //index 7
0x00006825,
0xBC9221EE, //index 8
0x00006825,
0xBC9221FF, //index 9
0x00006825,
0xBC9221FF, //index 10
0x00004025,
0xB792203F, //index 11
0x00004026,
0xDC92203F, //index 12
0x00004025,
0xE692203F, //index 13
0x00004025,
0xFF92203F, //index 14
0x00004035,
0xFFFE203F, //index 15
0x00004832
};
u32 wifi_txgain_table_24g_1_8800dcdw[32] =
{
0x096E2011, //index 0
0x00004001,
0x096E2015, //index 1
0x00004001,
0x096E201B, //index 2
0x00004001,
0x116E2018, //index 3
0x00004001,
0x116E201E, //index 4
0x00004001,
0x116E2023, //index 5
0x00004001,
0x196E2021, //index 6
0x00004001,
0x196E202B, //index 7
0x00004001,
0x216E202B, //index 8
0x00004001,
0x236E2027, //index 9
0x00004001,
0x236E2031, //index 10
0x00004001,
0x246E2039, //index 11
0x00004001,
0x26922039, //index 12
0x00004001,
0x2E92203F, //index 13
0x00004001,
0x3692203F, //index 14
0x00004001,
0x3FF2203F, //index 15
0x00004001,
};
u32 wifi_txgain_table_24g_8800dcdw_h[32] =
{
0xA55629C9, //index 0
0x00005825,
0xAE5629C9, //index 1
0x00005825,
0xAD5629CD, //index 2
0x00005825,
0xAD5629D1, //index 3
0x00005825,
0xAD5629D7, //index 4
0x00005825,
0xAD5629DE, //index 5
0x00005825,
0xAD5629E6, //index 6
0x00005825,
0xBD5629E6, //index 7
0x00005825,
0xBD5629F0, //index 8
0x00005825,
0xCD5629F0, //index 9
0x00005825,
0xE55629F0, //index 10
0x00005825,
0xE55629FF, //index 11
0x00005825,
0xE55629FF, //index 12
0x00002825,
0xE75629FF, //index 13
0x00002825,
0xFF5629FF, //index 14
0x00001825,
0xFF5628FF, //index 15
0x00001025,
};
u32 wifi_txgain_table_24g_1_8800dcdw_h[32] =
{
0x941A2048, //index 0
0x00001825,
0x961A2048, //index 1
0x00001825,
0x9D1A2048, //index 2
0x00001825,
0x9A1A204F, //index 3
0x00001825,
0x961A204F, //index 4
0x00001825,
0x9A1A2057, //index 5
0x00001825,
0x9C1A2057, //index 6
0x00001825,
0xA31A205B, //index 7
0x00001825,
0xAB1A205B, //index 8
0x00001825,
0xAD1A205B, //index 9
0x00001825,
0xA71A2064, //index 10
0x00001825,
0xAD1A2070, //index 11
0x00001825,
0xAD72207F, //index 12
0x00001825,
0xBCAE207F, //index 13
0x00001825,
0xBFB2207F, //index 14
0x00001825,
0xD73A207F, //index 15
0x00001825,
};
u32 wifi_rxgain_table_24g_20m_8800dcdw[64] = {
0x82f282d1,//index 0
0x9591a324,
0x80808419,
0x000000f0,
0x42f282d1,//index 1
0x95923524,
0x80808419,
0x000000f0,
0x22f282d1,//index 2
0x9592c724,
0x80808419,
0x000000f0,
0x02f282d1,//index 3
0x9591a324,
0x80808419,
0x000000f0,
0x06f282d1,//index 4
0x9591a324,
0x80808419,
0x000000f0,
0x0ef29ad1,//index 5
0x9591a324,
0x80808419,
0x000000f0,
0x0ef29ad3,//index 6
0x95923524,
0x80808419,
0x000000f0,
0x0ef29ad7,//index 7
0x9595a324,
0x80808419,
0x000000f0,
0x02f282d2,//index 8
0x95951124,
0x80808419,
0x000000f0,
0x02f282f4,//index 9
0x95951124,
0x80808419,
0x000000f0,
0x02f282e6,//index 10
0x9595a324,
0x80808419,
0x000000f0,
0x02f282e6,//index 11
0x9599a324,
0x80808419,
0x000000f0,
0x02f282e6,//index 12
0x959da324,
0x80808419,
0x000000f0,
0x02f282e6,//index 13
0x959f5924,
0x80808419,
0x000000f0,
0x06f282e6,//index 14
0x959f5924,
0x80808419,
0x000000f0,
0x0ef29ae6,//index 15
0x959f5924, //loft [35:34]=3
0x80808419,
0x000000f0
};
u32 wifi_rxgain_table_24g_40m_8800dcdw[64] = {
0x83428151,//index 0
0x9631a328,
0x80808419,
0x000000f0,
0x43428151,//index 1
0x96323528,
0x80808419,
0x000000f0,
0x23428151,//index 2
0x9632c728,
0x80808419,
0x000000f0,
0x03428151,//index 3
0x9631a328,
0x80808419,
0x000000f0,
0x07429951,//index 4
0x9631a328,
0x80808419,
0x000000f0,
0x0f42d151,//index 5
0x9631a328,
0x80808419,
0x000000f0,
0x0f42d153,//index 6
0x96323528,
0x80808419,
0x000000f0,
0x0f42d157,//index 7
0x9635a328,
0x80808419,
0x000000f0,
0x03428152,//index 8
0x96351128,
0x80808419,
0x000000f0,
0x03428174,//index 9
0x96351128,
0x80808419,
0x000000f0,
0x03428166,//index 10
0x9635a328,
0x80808419,
0x000000f0,
0x03428166,//index 11
0x9639a328,
0x80808419,
0x000000f0,
0x03428166,//index 12
0x963da328,
0x80808419,
0x000000f0,
0x03428166,//index 13
0x963f5928,
0x80808419,
0x000000f0,
0x07429966,//index 14
0x963f5928,
0x80808419,
0x000000f0,
0x0f42d166,//index 15
0x963f5928,
0x80808419,
0x000000f0
};
#define RAM_LMAC_FW_ADDR 0x00150000
#ifdef CONFIG_DPD
#if (defined(CONFIG_DPD) && !defined(CONFIG_FORCE_DPD_CALIB))
extern int is_file_exist(char* name);
#endif
extern rf_misc_ram_lite_t dpd_res;
int aicwf_fdrv_dpd_result_apply_8800dc(struct rwnx_hw *rwnx_hw, rf_misc_ram_lite_t *dpd_res)
{
int ret = 0;
uint32_t cfg_base = 0x10164;
struct dbg_mem_read_cfm cfm;
uint32_t misc_ram_addr;
uint32_t ram_base_addr, ram_byte_cnt;
AICWFDBG(LOGINFO, "bit_mask[1]=%x\n", dpd_res->bit_mask[1]);
if (dpd_res->bit_mask[1] == 0) {
AICWFDBG(LOGERROR, "void dpd_res, bypass it.\n");
return 0;
}
if (testmode == 1) {
cfg_base = RAM_LMAC_FW_ADDR + 0x0164;
}
if ((ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 0x14, &cfm))) {
AICWFDBG(LOGERROR, "rf misc ram[0x%x] rd fail: %d\n", cfg_base + 0x14, ret);
return ret;
}
misc_ram_addr = cfm.memdata;
AICWFDBG(LOGINFO, "misc_ram_addr: %x\n", misc_ram_addr);
/* Copy dpd_res on the Embedded side */
// bit_mask
AICWFDBG(LOGINFO, "bit_mask[0]=%x\n", dpd_res->bit_mask[0]);
ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, bit_mask);
ram_byte_cnt = MEMBER_SIZE(rf_misc_ram_t, bit_mask) + MEMBER_SIZE(rf_misc_ram_t, reserved);
ret = rwnx_send_dbg_mem_block_write_req(rwnx_hw, ram_base_addr, ram_byte_cnt, (u32 *)&dpd_res->bit_mask[0]);
if (ret) {
AICWFDBG(LOGERROR, "bit_mask wr fail: %x, ret:%d\r\n", ram_base_addr, ret);
return ret;
}
// dpd_high
AICWFDBG(LOGINFO, "dpd_high[0]=%x\n", dpd_res->dpd_high[0]);
ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, dpd_high);
ram_byte_cnt = MEMBER_SIZE(rf_misc_ram_t, dpd_high);
ret = rwnx_send_dbg_mem_block_write_req(rwnx_hw, ram_base_addr, ram_byte_cnt, (u32 *)&dpd_res->dpd_high[0]);
if (ret) {
AICWFDBG(LOGERROR, "dpd_high wr fail: %x, ret:%d\r\n", ram_base_addr, ret);
return ret;
}
// loft_res
AICWFDBG(LOGINFO, "loft_res[0]=%x\n", dpd_res->loft_res[0]);
ram_base_addr = misc_ram_addr + offsetof(rf_misc_ram_t, loft_res);
ram_byte_cnt = MEMBER_SIZE(rf_misc_ram_t, loft_res);
ret = rwnx_send_dbg_mem_block_write_req(rwnx_hw, ram_base_addr, ram_byte_cnt, (u32 *)&dpd_res->loft_res[0]);
if (ret) {
AICWFDBG(LOGERROR, "loft_res wr fail: %x, ret:%d\r\n", ram_base_addr, ret);
return ret;
}
return ret;
}
#ifndef CONFIG_FORCE_DPD_CALIB
int aicwf_fdrv_dpd_result_load_8800dc(struct rwnx_hw *rwnx_hw, rf_misc_ram_lite_t *dpd_res)
{
int ret = 0;
int size;
u32 *dst=NULL;
char *filename = FW_DPDRESULT_NAME_8800DC;
AICWFDBG(LOGINFO, "dpd_res file path:%s \r\n", filename);
/* load file */
size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
if (size <= 0) {
AICWFDBG(LOGERROR, "wrong size of dpd_res file\n");
dst = NULL;
return -1;
}
AICWFDBG(LOGINFO, "### Load file done: %s, size=%d, dst[0]=%x\n", filename, size, dst[0]);
memcpy((u8 *)dpd_res, (u8 *)dst, sizeof(rf_misc_ram_lite_t));
if (dst) {
rwnx_release_firmware_common(&dst);
}
return ret;
}
#endif
#endif
int aicwf_fdrv_misc_ram_init_8800dc(struct rwnx_hw *rwnx_hw)
{
int ret = 0;
uint32_t cfg_base = 0x10164;
struct dbg_mem_read_cfm cfm;
uint32_t misc_ram_addr;
uint32_t misc_ram_size = 12;
int i;
if (testmode == 1) {
cfg_base = RAM_LMAC_FW_ADDR + 0x0164;
}
// init misc ram
printk("%s\n", __func__);
ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 0x14, &cfm);
if (ret) {
AICWFDBG(LOGERROR, "rf misc ram[0x%x] rd fail: %d\n", cfg_base + 0x14, ret);
return ret;
}
misc_ram_addr = cfm.memdata;
AICWFDBG(LOGERROR, "misc_ram_addr=%x\n", misc_ram_addr);
for (i = 0; i < (misc_ram_size / 4); i++) {
ret = rwnx_send_dbg_mem_write_req(rwnx_hw, misc_ram_addr + i * 4, 0);
if (ret) {
AICWFDBG(LOGERROR, "rf misc ram[0x%x] wr fail: %d\n", misc_ram_addr + i * 4, ret);
return ret;
}
}
return ret;
}
int aicwf_set_rf_config_8800dc(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm){
int ret = 0;
if ((ret = rwnx_send_txpwr_lvl_req(rwnx_hw))) {
return -1;
}
if ((ret = rwnx_send_txpwr_ofst_req(rwnx_hw))) {
return -1;
}
if (testmode == 0) {
if (IS_CHIP_ID_H()) {
if ((ret = rwnx_send_rf_config_req(rwnx_hw, 0, 1, (u8_l *)wifi_txgain_table_24g_8800dcdw_h, 128)))
return -1;
if ((ret = rwnx_send_rf_config_req(rwnx_hw, 16, 1, (u8_l *)wifi_txgain_table_24g_1_8800dcdw_h, 128)))
return -1;
} else {
if ((ret = rwnx_send_rf_config_req(rwnx_hw, 0, 1, (u8_l *)wifi_txgain_table_24g_8800dcdw, 128)))
return -1;
if ((ret = rwnx_send_rf_config_req(rwnx_hw, 16, 1, (u8_l *)wifi_txgain_table_24g_1_8800dcdw, 128)))
return -1;
}
if ((ret = rwnx_send_rf_config_req(rwnx_hw, 0, 0, (u8_l *)wifi_rxgain_table_24g_20m_8800dcdw, 256)))
return -1;
if ((ret = rwnx_send_rf_config_req(rwnx_hw, 32, 0, (u8_l *)wifi_rxgain_table_24g_40m_8800dcdw, 256)))
return -1;
if ((ret = rwnx_send_rf_calib_req(rwnx_hw, cfm))) {
return -1;
}
} else if (testmode == 1) {
if (chip_sub_id >= 1) {
#ifdef CONFIG_DPD
#ifndef CONFIG_FORCE_DPD_CALIB
if (is_file_exist(FW_DPDRESULT_NAME_8800DC) == 1) {
AICWFDBG(LOGINFO, "%s load dpd bin\n", __func__);
ret = aicwf_fdrv_dpd_result_load_8800dc(rwnx_hw, &dpd_res);
if (ret) {
AICWFDBG(LOGINFO, "load dpd bin fail: %d\n", ret);
return ret;
}
}
#endif
if (dpd_res.bit_mask[1]) {
ret = aicwf_fdrv_dpd_result_apply_8800dc(rwnx_hw, &dpd_res);
if (ret) {
AICWFDBG(LOGINFO, "apply dpd bin fail: %d\n", ret);
return ret;
}
}
#else
{
ret = aicwf_fdrv_misc_ram_init_8800dc(rwnx_hw);
if (ret) {
AICWFDBG(LOGINFO, "misc ram init fail: %d\n", ret);
return ret;
}
}
#endif
ret = rwnx_send_rf_calib_req(rwnx_hw, cfm);
if (ret) {
AICWFDBG(LOGINFO, "rf calib req fail: %d\n", ret);
return ret;
}
}
}
return 0 ;
}
int rwnx_plat_userconfig_load_8800dc(struct rwnx_hw *rwnx_hw){
int size;
u32 *dst=NULL;
char *filename = FW_USERCONFIG_NAME_8800DC;
AICWFDBG(LOGINFO, "userconfig file path:%s \r\n", filename);
/* load file */
size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
if (size <= 0) {
AICWFDBG(LOGERROR, "wrong size of firmware file\n");
dst = NULL;
return 0;
}
/* Copy the file on the Embedded side */
AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size);
rwnx_plat_userconfig_parsing2((char *)dst, size);
rwnx_release_firmware_common(&dst);
AICWFDBG(LOGINFO, "userconfig download complete\n\n");
return 0;
}
int rwnx_plat_userconfig_load_8800dw(struct rwnx_hw *rwnx_hw){
int size;
u32 *dst=NULL;
char *filename = FW_USERCONFIG_NAME_8800DC;
AICWFDBG(LOGINFO, "userconfig file path:%s \r\n", filename);
/* load file */
size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
if (size <= 0) {
AICWFDBG(LOGERROR, "wrong size of firmware file\n");
dst = NULL;
return 0;
}
/* Copy the file on the Embedded side */
AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size);
rwnx_plat_userconfig_parsing2((char *)dst, size);
rwnx_release_firmware_common(&dst);
AICWFDBG(LOGINFO, "userconfig download complete\n\n");
return 0;
}

View File

@ -0,0 +1,15 @@
#include <linux/types.h>
#include "aic_bsp_export.h"
#ifdef CONFIG_DPD
int aicwf_fdrv_dpd_result_apply_8800dc(struct rwnx_hw * rwnx_hw, rf_misc_ram_lite_t * dpd_res);
#ifndef CONFIG_FORCE_DPD_CALIB
int aicwf_fdrv_dpd_result_load_8800dc(struct rwnx_hw *rwnx_hw, rf_misc_ram_lite_t *dpd_res);
#endif
#endif
int aicwf_fdrv_misc_ram_init_8800dc(struct rwnx_hw *rwnx_hw);
int aicwf_set_rf_config_8800dc(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm);
int rwnx_plat_userconfig_load_8800dc(struct rwnx_hw *rwnx_hw);
int rwnx_plat_userconfig_load_8800dw(struct rwnx_hw *rwnx_hw);

View File

@ -0,0 +1,56 @@
#define RWNX_FN_ENTRY_STR ">>> %s()\n", __func__
/* message levels */
#define LOGERROR 0x0001
#define LOGINFO 0x0002
#define LOGTRACE 0x0004
#define LOGDEBUG 0x0008
#define LOGDATA 0x0010
#define LOGIRQ 0x0020
#define LOGSDPWRC 0x0040
#define LOGWAKELOCK 0x0080
#define LOGRXPOLL 0x0100
extern int aicwf_dbg_level;
void rwnx_data_dump(char* tag, void* data, unsigned long len);
#define AICWF_LOG "AICWFDBG("
#define AICWFDBG(level, args, arg...) \
do { \
if (aicwf_dbg_level & level) { \
printk(AICWF_LOG#level")\t" args, ##arg); \
} \
} while (0)
#define RWNX_DBG(fmt, ...) \
do { \
if (aicwf_dbg_level & LOGTRACE) { \
printk(AICWF_LOG"LOGTRACE)\t"fmt , ##__VA_ARGS__); \
} \
} while (0)
#if 0
#define RWNX_DBG(fmt, ...) \
do { \
if (aicwf_dbg_level & LOGTRACE) { \
printk(AICWF_LOG"LOGTRACE"")\t" fmt, ##__VA_ARGS__); \
} \
} while (0)
#define AICWFDBG(args, level) \
do { \
if (aicwf_dbg_level & level) { \
printk(AICWF_LOG"(%s)\t" ,#level); \
printf args; \
} \
} while (0)
#endif

View File

@ -0,0 +1,97 @@
#include <linux/version.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include "aicwf_rx_prealloc.h"
#ifdef CONFIG_PREALLOC_RX_SKB
struct aicwf_rx_buff_list aic_rx_buff_list;
int aic_rxbuff_num_max = 30;
int aic_rxbuff_size = (64 * 512);
struct rx_buff *aicwf_prealloc_rxbuff_alloc(spinlock_t *lock)
{
unsigned long flags;
struct rx_buff *rxbuff = NULL;
spin_lock_irqsave(lock, flags);
if (list_empty(&aic_rx_buff_list.rxbuff_list)) {
spin_unlock_irqrestore(lock, flags);
printk("%s %d, rxbuff list is empty\n", __func__, __LINE__);
return NULL;
} else {
rxbuff = list_first_entry(&aic_rx_buff_list.rxbuff_list,
struct rx_buff, queue);
list_del_init(&rxbuff->queue);
atomic_dec(&aic_rx_buff_list.rxbuff_list_len);
}
spin_unlock_irqrestore(lock, flags);
//printk("len:%d\n", aic_rx_buff_list.rxbuff_list_len);
memset(rxbuff->data, 0, aic_rxbuff_size);
rxbuff->len = 0;
rxbuff->start = NULL;
rxbuff->read = NULL;
rxbuff->end = NULL;
return rxbuff;
}
void aicwf_prealloc_rxbuff_free(struct rx_buff *rxbuff, spinlock_t *lock)
{
unsigned long flags;
spin_lock_irqsave(lock, flags);
list_add_tail(&rxbuff->queue, &aic_rx_buff_list.rxbuff_list);
atomic_inc(&aic_rx_buff_list.rxbuff_list_len);
spin_unlock_irqrestore(lock, flags);
}
int aicwf_prealloc_init()
{
struct rx_buff *rxbuff;
int i = 0;
printk("%s enter\n", __func__);
INIT_LIST_HEAD(&aic_rx_buff_list.rxbuff_list);
for (i = 0 ; i < aic_rxbuff_num_max ; i++) {
rxbuff = kzalloc(sizeof(struct rx_buff), GFP_KERNEL);
if (rxbuff) {
rxbuff->data = kzalloc(aic_rxbuff_size, GFP_KERNEL);
if (rxbuff->data == NULL) {
printk("failed to alloc rxbuff data\n");
kfree(rxbuff);
continue;
}
rxbuff->len = 0;
rxbuff->start = NULL;
rxbuff->read = NULL;
rxbuff->end = NULL;
list_add_tail(&rxbuff->queue, &aic_rx_buff_list.rxbuff_list);
atomic_inc(&aic_rx_buff_list.rxbuff_list_len);
}
}
printk("pre alloc rxbuff list len: %d\n", (int)atomic_read(&aic_rx_buff_list.rxbuff_list_len));
return 0;
}
void aicwf_prealloc_exit()
{
struct rx_buff *rxbuff;
struct rx_buff *pos;
printk("%s enter\n", __func__);
printk("free pre alloc rxbuff list %d\n", (int)atomic_read(&aic_rx_buff_list.rxbuff_list_len));
list_for_each_entry_safe(rxbuff, pos, &aic_rx_buff_list.rxbuff_list, queue) {
list_del_init(&rxbuff->queue);
kfree(rxbuff->data);
kfree(rxbuff);
}
}
#endif

View File

@ -0,0 +1,24 @@
#ifndef _AICWF_RX_PREALLOC_H_
#define _AICWF_RX_PREALLOC_H_
#ifdef CONFIG_PREALLOC_RX_SKB
struct rx_buff {
struct list_head queue;
unsigned char *data;
u32 len;
uint8_t *start;
uint8_t *end;
uint8_t *read;
};
struct aicwf_rx_buff_list {
struct list_head rxbuff_list;
atomic_t rxbuff_list_len;
};
struct rx_buff *aicwf_prealloc_rxbuff_alloc(spinlock_t *lock);
void aicwf_prealloc_rxbuff_free(struct rx_buff *rxbuff, spinlock_t *lock);
int aicwf_prealloc_init(void);
void aicwf_prealloc_exit(void);
#endif
#endif /* _AICWF_RX_PREALLOC_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,186 @@
/**
* aicwf_sdio.h
*
* SDIO function declarations
*
* Copyright (C) AICSemi 2018-2020
*/
#ifndef _AICWF_SDMMC_H_
#define _AICWF_SDMMC_H_
#ifdef AICWF_SDIO_SUPPORT
#include <linux/skbuff.h>
#include <linux/if_ether.h>
#include <linux/ieee80211.h>
#include <linux/semaphore.h>
#include "rwnx_cmds.h"
#include "aicwf_rx_prealloc.h"
#define AICWF_SDIO_NAME "aicwf_sdio"
#define SDIOWIFI_FUNC_BLOCKSIZE 512
#define SDIOWIFI_BYTEMODE_LEN_REG 0x02
#define SDIOWIFI_INTR_CONFIG_REG 0x04
#define SDIOWIFI_SLEEP_REG 0x05
#define SDIOWIFI_WAKEUP_REG 0x09
#define SDIOWIFI_FLOW_CTRL_REG 0x0A
#define SDIOWIFI_REGISTER_BLOCK 0x0B
#define SDIOWIFI_BYTEMODE_ENABLE_REG 0x11
#define SDIOWIFI_BLOCK_CNT_REG 0x12
#define SDIOWIFI_FLOWCTRL_MASK_REG 0x7F
#define SDIOWIFI_WR_FIFO_ADDR 0x07
#define SDIOWIFI_RD_FIFO_ADDR 0x08
#define SDIOWIFI_INTR_ENABLE_REG_V3 0x00
#define SDIOWIFI_INTR_PENDING_REG_V3 0x01
#define SDIOWIFI_INTR_TO_DEVICE_REG_V3 0x02
#define SDIOWIFI_FLOW_CTRL_Q1_REG_V3 0x03
#define SDIOWIFI_MISC_INT_STATUS_REG_V3 0x04
#define SDIOWIFI_BYTEMODE_LEN_REG_V3 0x05
#define SDIOWIFI_BYTEMODE_LEN_MSB_REG_V3 0x06
#define SDIOWIFI_BYTEMODE_ENABLE_REG_V3 0x07
#define SDIOWIFI_MISC_CTRL_REG_V3 0x08
#define SDIOWIFI_FLOW_CTRL_Q2_REG_V3 0x09
#define SDIOWIFI_CLK_TEST_RESULT_REG_V3 0x0A
#define SDIOWIFI_RD_FIFO_ADDR_V3 0x0F
#define SDIOWIFI_WR_FIFO_ADDR_V3 0x10
#define SDIOCLK_FREE_RUNNING_BIT (1 << 6)
#define SDIOWIFI_PWR_CTRL_INTERVAL 30
#define FLOW_CTRL_RETRY_COUNT 50
#define BUFFER_SIZE 1536
#define TAIL_LEN 4
#define TXQLEN (2048*4)
#define SDIO_SLEEP_ST 0
#define SDIO_ACTIVE_ST 1
#define DATA_FLOW_CTRL_THRESH 2
#ifdef CONFIG_TX_NETIF_FLOWCTRL
#define AICWF_SDIO_TX_LOW_WATER 100
#define AICWF_SDIO_TX_HIGH_WATER 500
#endif
typedef enum {
SDIO_TYPE_DATA = 0X00,
SDIO_TYPE_CFG = 0X10,
SDIO_TYPE_CFG_CMD_RSP = 0X11,
SDIO_TYPE_CFG_DATA_CFM = 0X12,
SDIO_TYPE_CFG_PRINT = 0X13
} sdio_type;
/* SDIO Device ID */
#define SDIO_VENDOR_ID_AIC8801 0x5449
#define SDIO_VENDOR_ID_AIC8800DC 0xc8a1
#define SDIO_VENDOR_ID_AIC8800D80 0xc8a1
#define SDIO_DEVICE_ID_AIC8801 0x0145
#define SDIO_DEVICE_ID_AIC8800DC 0xc08d
#define SDIO_DEVICE_ID_AIC8800D80 0x0082
enum AICWF_IC{
PRODUCT_ID_AIC8801 = 0,
PRODUCT_ID_AIC8800DC,
PRODUCT_ID_AIC8800DW,
PRODUCT_ID_AIC8800D80
};
struct rwnx_hw;
struct aic_sdio_reg {
u8 bytemode_len_reg;
u8 intr_config_reg;
u8 sleep_reg;
u8 wakeup_reg;
u8 flow_ctrl_reg;
u8 flowctrl_mask_reg;
u8 register_block;
u8 bytemode_enable_reg;
u8 block_cnt_reg;
u8 misc_int_status_reg;
u8 rd_fifo_addr;
u8 wr_fifo_addr;
};
struct aic_sdio_dev {
struct rwnx_hw *rwnx_hw;
struct sdio_func *func;
struct device *dev;
struct aicwf_bus *bus_if;
struct rwnx_cmd_mgr cmd_mgr;
struct aicwf_rx_priv *rx_priv;
struct aicwf_tx_priv *tx_priv;
u32 state;
#ifdef CONFIG_TX_NETIF_FLOWCTRL
u8 flowctrl;
spinlock_t tx_flow_lock;
#endif
#if defined(CONFIG_SDIO_PWRCTRL)
//for sdio pwr ctrl
struct timer_list timer;
uint active_duration;
struct completion pwrctrl_trgg;
struct task_struct *pwrctl_tsk;
spinlock_t pwrctl_lock;
struct semaphore pwrctl_wakeup_sema;
#endif
u16 chipid;
struct aic_sdio_reg sdio_reg;
spinlock_t wslock;//AIDEN test
bool oob_enable;
atomic_t is_bus_suspend;
};
extern struct aicwf_rx_buff_list aic_rx_buff_list;
int aicwf_sdio_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val);
void aicwf_sdio_hal_irqhandler(struct sdio_func *func);
#if defined(CONFIG_SDIO_PWRCTRL)
void aicwf_sdio_pwrctl_timer(struct aic_sdio_dev *sdiodev, uint duration);
int aicwf_sdio_pwr_stctl(struct aic_sdio_dev *sdiodev, uint target);
#endif
void aicwf_sdio_reg_init(struct aic_sdio_dev *sdiodev);
int aicwf_sdio_func_init(struct aic_sdio_dev *sdiodev);
int aicwf_sdiov3_func_init(struct aic_sdio_dev *sdiodev);
void aicwf_sdio_func_deinit(struct aic_sdio_dev *sdiodev);
#ifdef CONFIG_TX_NETIF_FLOWCTRL
void aicwf_sdio_tx_netif_flowctrl(struct rwnx_hw *rwnx_hw, bool state);
#endif
int aicwf_sdio_flow_ctrl(struct aic_sdio_dev *sdiodev);
int aicwf_sdio_flow_ctrl_msg(struct aic_sdio_dev *sdiodev);
#ifdef CONFIG_PREALLOC_RX_SKB
int aicwf_sdio_recv_pkt(struct aic_sdio_dev *sdiodev, struct rx_buff *rxbbuf, u32 size);
#else
int aicwf_sdio_recv_pkt(struct aic_sdio_dev *sdiodev, struct sk_buff *skbbuf, u32 size);
#endif
int aicwf_sdio_send_pkt(struct aic_sdio_dev *sdiodev, u8 *buf, uint count);
void *aicwf_sdio_bus_init(struct aic_sdio_dev *sdiodev);
void aicwf_sdio_release(struct aic_sdio_dev *sdiodev);
void aicwf_sdio_exit(void);
void aicwf_sdio_register(void);
int aicwf_sdio_txpkt(struct aic_sdio_dev *sdiodev, struct sk_buff *pkt);
int sdio_bustx_thread(void *data);
int sdio_busrx_thread(void *data);
#ifdef CONFIG_OOB
//new oob feature
int sdio_busirq_thread(void *data);
#endif //CONFIG_OOB
int aicwf_sdio_aggr(struct aicwf_tx_priv *tx_priv, struct sk_buff *pkt);
int aicwf_sdio_send(struct aicwf_tx_priv *tx_priv, u8 txnow);
void aicwf_sdio_aggr_send(struct aicwf_tx_priv *tx_priv);
void aicwf_sdio_aggrbuf_reset(struct aicwf_tx_priv *tx_priv);
extern void aicwf_hostif_ready(void);
extern void aicwf_hostif_fail(void);
#ifdef CONFIG_PLATFORM_AMLOGIC
extern void extern_wifi_set_enable(int is_on);
extern void sdio_reinit(void);
#endif /*CONFIG_PLATFORM_AMLOGIC*/
uint8_t crc8_ponl_107(uint8_t *p_buffer, uint16_t cal_size);
#endif /* AICWF_SDIO_SUPPORT */
#endif /*_AICWF_SDMMC_H_*/

View File

@ -0,0 +1,633 @@
#include"aicwf_tcp_ack.h"
//#include"rwnx_tx.h"
//#include "aicwf_tcp_ack.h"
#include"rwnx_defs.h"
extern int intf_tx(struct rwnx_hw *priv,struct msg_buf *msg);
struct msg_buf *intf_tcp_alloc_msg(struct msg_buf *msg)
{
//printk("%s \n",__func__);
int len=sizeof(struct msg_buf) ;
msg = kzalloc(len , /*GFP_KERNEL*/GFP_ATOMIC);
if(!msg)
printk("%s: alloc failed \n", __func__);
memset(msg,0,len);
return msg;
}
void intf_tcp_drop_msg(struct rwnx_hw *priv,
struct msg_buf *msg)
{
//printk("%s \n",__func__);
if (msg->skb)
dev_kfree_skb_any(msg->skb);
kfree(msg);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
void tcp_ack_timeout(unsigned long data)
#else
void tcp_ack_timeout(struct timer_list *t)
#endif
{
//printk("%s \n",__func__);
struct tcp_ack_info *ack_info;
struct msg_buf *msg;
struct tcp_ack_manage *ack_m = NULL;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
ack_info = (struct tcp_ack_info *)data;
#else
ack_info = container_of(t,struct tcp_ack_info,timer);
#endif
ack_m = container_of(ack_info, struct tcp_ack_manage,
ack_info[ack_info->ack_info_num]);
write_seqlock_bh(&ack_info->seqlock);
msg = ack_info->msgbuf;
if (ack_info->busy && msg && !ack_info->in_send_msg) {
ack_info->msgbuf = NULL;
ack_info->drop_cnt = 0;
ack_info->in_send_msg = msg;
write_sequnlock_bh(&ack_info->seqlock);
intf_tx(ack_m->priv, msg);//send skb
//ack_info->in_send_msg = NULL;//add by dwx
//write_sequnlock_bh(&ack_info->seqlock);
//intf_tx(ack_m->priv, msg);
return;
}
write_sequnlock_bh(&ack_info->seqlock);
}
void tcp_ack_init(struct rwnx_hw *priv)
{
int i;
struct tcp_ack_info *ack_info;
struct tcp_ack_manage *ack_m = &priv->ack_m;
printk("%s \n",__func__);
memset(ack_m, 0, sizeof(struct tcp_ack_manage));
ack_m->priv = priv;
spin_lock_init(&ack_m->lock);
atomic_set(&ack_m->max_drop_cnt, TCP_ACK_DROP_CNT);
ack_m->last_time = jiffies;
ack_m->timeout = msecs_to_jiffies(ACK_OLD_TIME);
for (i = 0; i < TCP_ACK_NUM; i++) {
ack_info = &ack_m->ack_info[i];
ack_info->ack_info_num = i;
seqlock_init(&ack_info->seqlock);
ack_info->last_time = jiffies;
ack_info->timeout = msecs_to_jiffies(ACK_OLD_TIME);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
setup_timer(&ack_info->timer, tcp_ack_timeout,
(unsigned long)ack_info);
#else
timer_setup(&ack_info->timer,tcp_ack_timeout,0);
#endif
}
atomic_set(&ack_m->enable, 1);
ack_m->ack_winsize = MIN_WIN;
}
void tcp_ack_deinit(struct rwnx_hw *priv)
{
int i;
struct tcp_ack_manage *ack_m = &priv->ack_m;
struct msg_buf *drop_msg = NULL;
printk("%s \n",__func__);
atomic_set(&ack_m->enable, 0);
for (i = 0; i < TCP_ACK_NUM; i++) {
drop_msg = NULL;
write_seqlock_bh(&ack_m->ack_info[i].seqlock);
del_timer(&ack_m->ack_info[i].timer);
drop_msg = ack_m->ack_info[i].msgbuf;
ack_m->ack_info[i].msgbuf = NULL;
write_sequnlock_bh(&ack_m->ack_info[i].seqlock);
if (drop_msg)
intf_tcp_drop_msg(priv, drop_msg);//drop skb
}
}
int tcp_check_quick_ack(unsigned char *buf,
struct tcp_ack_msg *msg)
{
int ip_hdr_len;
unsigned char *temp;
struct ethhdr *ethhdr;
struct iphdr *iphdr;
struct tcphdr *tcphdr;
ethhdr = (struct ethhdr *)buf;
if (ethhdr->h_proto != htons(ETH_P_IP))
return 0;
iphdr = (struct iphdr *)(ethhdr + 1);
if (iphdr->version != 4 || iphdr->protocol != IPPROTO_TCP)
return 0;
ip_hdr_len = iphdr->ihl * 4;
temp = (unsigned char *)(iphdr) + ip_hdr_len;
tcphdr = (struct tcphdr *)temp;
/* TCP_FLAG_ACK */
if (!(temp[13] & 0x10))
return 0;
if (temp[13] & 0x8) {
msg->saddr = iphdr->daddr;
msg->daddr = iphdr->saddr;
msg->source = tcphdr->dest;
msg->dest = tcphdr->source;
msg->seq = ntohl(tcphdr->seq);
return 1;
}
return 0;
}
int is_drop_tcp_ack(struct tcphdr *tcphdr, int tcp_tot_len,
unsigned short *win_scale)
{
//printk("%s \n",__func__);
int drop = 1;
int len = tcphdr->doff * 4;
unsigned char *ptr;
if(tcp_tot_len > len) {
drop = 0;
} else {
len -= sizeof(struct tcphdr);
ptr = (unsigned char *)(tcphdr + 1);
while ((len > 0) && drop) {
int opcode = *ptr++;
int opsize;
switch (opcode) {
case TCPOPT_EOL:
break;
case TCPOPT_NOP:
len--;
continue;
default:
opsize = *ptr++;
if (opsize < 2)
break;
if (opsize > len)
break;
switch (opcode) {
/* TODO: Add other ignore opt */
case TCPOPT_TIMESTAMP:
break;
case TCPOPT_WINDOW:
if (*ptr < 15)
*win_scale = (1 << (*ptr));
printk("%d\n",*win_scale);
break;
default:
drop = 2;
}
ptr += opsize - 2;
len -= opsize;
}
}
}
return drop;
}
/* flag:0 for not tcp ack
* 1 for ack which can be drop
* 2 for other ack whith more info
*/
int tcp_check_ack(unsigned char *buf,
struct tcp_ack_msg *msg,
unsigned short *win_scale)
{
int ret;
int ip_hdr_len;
int tcp_tot_len;
unsigned char *temp;
struct ethhdr *ethhdr;
struct iphdr *iphdr;
struct tcphdr *tcphdr;
ethhdr =(struct ethhdr *)buf;
if (ethhdr->h_proto != htons(ETH_P_IP))
return 0;
iphdr = (struct iphdr *)(ethhdr + 1);
if (iphdr->version != 4 || iphdr->protocol != IPPROTO_TCP)
return 0;
ip_hdr_len = iphdr->ihl * 4;
temp = (unsigned char *)(iphdr) + ip_hdr_len;
tcphdr = (struct tcphdr *)temp;
/* TCP_FLAG_ACK */
if (!(temp[13] & 0x10))
return 0;
tcp_tot_len = ntohs(iphdr->tot_len) - ip_hdr_len;// tcp total len
ret = is_drop_tcp_ack(tcphdr, tcp_tot_len, win_scale);
//printk("is drop:%d \n",ret);
if (ret > 0) {
msg->saddr = iphdr->saddr;
msg->daddr = iphdr->daddr;
msg->source = tcphdr->source;
msg->dest = tcphdr->dest;
msg->seq = ntohl(tcphdr->ack_seq);
msg->win = ntohs(tcphdr->window);
}
return ret;
}
/* return val: -1 for not match, others for match */
int tcp_ack_match(struct tcp_ack_manage *ack_m,
struct tcp_ack_msg *ack_msg)
{
int i, ret = -1;
unsigned start;
struct tcp_ack_info *ack_info;
struct tcp_ack_msg *ack;
for (i = 0; ((ret < 0) && (i < TCP_ACK_NUM)); i++) {
ack_info = &ack_m->ack_info[i];
do {
start = read_seqbegin(&ack_info->seqlock);
ret = -1;
ack = &ack_info->ack_msg;
if (ack_info->busy &&
ack->dest == ack_msg->dest &&
ack->source == ack_msg->source &&
ack->saddr == ack_msg->saddr &&
ack->daddr == ack_msg->daddr)
ret = i;
} while(read_seqretry(&ack_info->seqlock, start));
}
return ret;
}
void tcp_ack_update(struct tcp_ack_manage *ack_m)
{
int i;
struct tcp_ack_info *ack_info;
if (time_after(jiffies, ack_m->last_time + ack_m->timeout)) {
spin_lock_bh(&ack_m->lock);
ack_m->last_time = jiffies;
for (i = TCP_ACK_NUM - 1; i >= 0; i--) {
ack_info = &ack_m->ack_info[i];
write_seqlock_bh(&ack_info->seqlock);
if (ack_info->busy &&
time_after(jiffies, ack_info->last_time +
ack_info->timeout)) {
ack_m->free_index = i;
ack_m->max_num--;
ack_info->busy = 0;
}
write_sequnlock_bh(&ack_info->seqlock);
}
spin_unlock_bh(&ack_m->lock);
}
}
/* return val: -1 for no index, others for index */
int tcp_ack_alloc_index(struct tcp_ack_manage *ack_m)
{
int i, ret = -1;
struct tcp_ack_info *ack_info;
unsigned start;
spin_lock_bh(&ack_m->lock);
if (ack_m->max_num == TCP_ACK_NUM) {
spin_unlock_bh(&ack_m->lock);
return -1;
}
if (ack_m->free_index >= 0) {
i = ack_m->free_index;
ack_m->free_index = -1;
ack_m->max_num++;
spin_unlock_bh(&ack_m->lock);
return i;
}
for (i = 0; ((ret < 0) && (i < TCP_ACK_NUM)); i++) {
ack_info = &ack_m->ack_info[i];
do {
start = read_seqbegin(&ack_info->seqlock);
ret = -1;
if (!ack_info->busy) {
ack_m->free_index = -1;
ack_m->max_num++;
ret = i;
}
} while(read_seqretry(&ack_info->seqlock, start));
}
spin_unlock_bh(&ack_m->lock);
return ret;
}
/* return val: 0 for not handle tx, 1 for handle tx */
int tcp_ack_handle(struct msg_buf *new_msgbuf,
struct tcp_ack_manage *ack_m,
struct tcp_ack_info *ack_info,
struct tcp_ack_msg *ack_msg,
int type)
{
int quick_ack = 0;
struct tcp_ack_msg *ack;
int ret = 0;
struct msg_buf *drop_msg = NULL;
//printk("%s %d",__func__,type);
write_seqlock_bh(&ack_info->seqlock);
ack_info->last_time = jiffies;
ack = &ack_info->ack_msg;
if (type == 2) {
if (U32_BEFORE(ack->seq, ack_msg->seq)) {
ack->seq = ack_msg->seq;
if (ack_info->psh_flag &&
!U32_BEFORE(ack_msg->seq,
ack_info->psh_seq)) {
ack_info->psh_flag = 0;
}
if (ack_info->msgbuf) {
//printk("%lx \n",ack_info->msgbuf);
drop_msg = ack_info->msgbuf;
ack_info->msgbuf = NULL;
del_timer(&ack_info->timer);
}else{
//printk("msgbuf is NULL \n");
}
ack_info->in_send_msg = NULL;
ack_info->drop_cnt = atomic_read(&ack_m->max_drop_cnt);
} else {
printk("%s before abnormal ack: %d, %d\n",
__func__, ack->seq, ack_msg->seq);
drop_msg = new_msgbuf;
ret = 1;
}
} else if (U32_BEFORE(ack->seq, ack_msg->seq)) {
if (ack_info->msgbuf) {
drop_msg = ack_info->msgbuf;
ack_info->msgbuf = NULL;
}
if (ack_info->psh_flag &&
!U32_BEFORE(ack_msg->seq, ack_info->psh_seq)) {
ack_info->psh_flag = 0;
quick_ack = 1;
} else {
ack_info->drop_cnt++;
}
ack->seq = ack_msg->seq;
if (quick_ack || (!ack_info->in_send_msg &&
(ack_info->drop_cnt >=
atomic_read(&ack_m->max_drop_cnt)))) {
ack_info->drop_cnt = 0;
ack_info->in_send_msg = new_msgbuf;
del_timer(&ack_info->timer);
} else {
ret = 1;
ack_info->msgbuf = new_msgbuf;
if (!timer_pending(&ack_info->timer))
mod_timer(&ack_info->timer,
(jiffies + msecs_to_jiffies(5)));
}
} else {
printk("%s before ack: %d, %d\n",
__func__, ack->seq, ack_msg->seq);
drop_msg = new_msgbuf;
ret = 1;
}
write_sequnlock_bh(&ack_info->seqlock);
if (drop_msg)
intf_tcp_drop_msg(ack_m->priv, drop_msg);// drop skb
return ret;
}
int tcp_ack_handle_new(struct msg_buf *new_msgbuf,
struct tcp_ack_manage *ack_m,
struct tcp_ack_info *ack_info,
struct tcp_ack_msg *ack_msg,
int type)
{
int quick_ack = 0;
struct tcp_ack_msg *ack;
int ret = 0;
struct msg_buf *drop_msg = NULL;
struct msg_buf * send_msg = NULL;
//printk("",);
write_seqlock_bh(&ack_info->seqlock);
ack_info->last_time = jiffies;
ack = &ack_info->ack_msg;
if(U32_BEFORE(ack->seq, ack_msg->seq)){
if (ack_info->msgbuf) {
drop_msg = ack_info->msgbuf;
ack_info->msgbuf = NULL;
//ack_info->drop_cnt++;
}
if (ack_info->psh_flag &&
!U32_BEFORE(ack_msg->seq, ack_info->psh_seq)) {
ack_info->psh_flag = 0;
quick_ack = 1;
} else {
ack_info->drop_cnt++;
}
ack->seq = ack_msg->seq;
if(quick_ack || (!ack_info->in_send_msg &&
(ack_info->drop_cnt >=
atomic_read(&ack_m->max_drop_cnt)))){
ack_info->drop_cnt = 0;
send_msg = new_msgbuf;
ack_info->in_send_msg = send_msg;
del_timer(&ack_info->timer);
}else{
ret = 1;
ack_info->msgbuf = new_msgbuf;
if (!timer_pending(&ack_info->timer))
mod_timer(&ack_info->timer,
(jiffies + msecs_to_jiffies(5)));
}
//ret = 1;
}else {
printk("%s before ack: %d, %d\n",
__func__, ack->seq, ack_msg->seq);
drop_msg = new_msgbuf;
ret = 1;
}
/*if(send_msg){
intf_tx(ack_m->priv,send_msg);
ack_info->in_send_msg=NULL;
}*/
//ack_info->in_send_msg=NULL;
write_sequnlock_bh(&ack_info->seqlock);
/*if(send_msg){
intf_tx(ack_m->priv,send_msg);
//ack_info->in_send_msg=NULL;
}*/
if (drop_msg)
intf_tcp_drop_msg(ack_m->priv, drop_msg);// drop skb
return ret;
}
void filter_rx_tcp_ack(struct rwnx_hw *priv,
unsigned char *buf, unsigned plen)
{
int index;
struct tcp_ack_msg ack_msg;
struct tcp_ack_info *ack_info;
struct tcp_ack_manage *ack_m = &priv->ack_m;
if (!atomic_read(&ack_m->enable))
return;
if ((plen > MAX_TCP_ACK) ||
!tcp_check_quick_ack(buf, &ack_msg))
return;
index = tcp_ack_match(ack_m, &ack_msg);
if (index >= 0) {
ack_info = ack_m->ack_info + index;
write_seqlock_bh(&ack_info->seqlock);
ack_info->psh_flag = 1;
ack_info->psh_seq = ack_msg.seq;
write_sequnlock_bh(&ack_info->seqlock);
}
}
/* return val: 0 for not filter, 1 for filter */
int filter_send_tcp_ack(struct rwnx_hw *priv,
struct msg_buf *msgbuf,
unsigned char *buf, unsigned int plen)
{
//printk("%s \n",__func__);
int ret = 0;
int index, drop;
unsigned short win_scale = 0;
unsigned int win = 0;
struct tcp_ack_msg ack_msg;
struct tcp_ack_msg *ack;
struct tcp_ack_info *ack_info;
struct tcp_ack_manage *ack_m = &priv->ack_m;
if (plen > MAX_TCP_ACK)
return 0;
tcp_ack_update(ack_m);
drop = tcp_check_ack(buf, &ack_msg, &win_scale);
//printk("drop:%d win_scale:%d",drop,win_scale);
if (!drop && (0 == win_scale))
return 0;
index = tcp_ack_match(ack_m, &ack_msg);
if (index >= 0) {
ack_info = ack_m->ack_info + index;
if ((0 != win_scale) &&
(ack_info->win_scale != win_scale)) {
write_seqlock_bh(&ack_info->seqlock);
ack_info->win_scale = win_scale;
write_sequnlock_bh(&ack_info->seqlock);
}
if (drop > 0 && atomic_read(&ack_m->enable)) {
win = ack_info->win_scale * ack_msg.win;
if ((win_scale!=0) && (win < (ack_m->ack_winsize * SIZE_KB)))
{
drop = 2;
printk("%d %d %d",win_scale,win,(ack_m->ack_winsize * SIZE_KB));
}
ret = tcp_ack_handle_new(msgbuf, ack_m, ack_info,
&ack_msg, drop);
}
goto out;
}
index = tcp_ack_alloc_index(ack_m);
if (index >= 0) {
write_seqlock_bh(&ack_m->ack_info[index].seqlock);
ack_m->ack_info[index].busy = 1;
ack_m->ack_info[index].psh_flag = 0;
ack_m->ack_info[index].last_time = jiffies;
ack_m->ack_info[index].drop_cnt =
atomic_read(&ack_m->max_drop_cnt);
ack_m->ack_info[index].win_scale =
(win_scale != 0) ? win_scale : 1;
//ack_m->ack_info[index].msgbuf = NULL;
//ack_m->ack_info[index].in_send_msg = NULL;
ack = &ack_m->ack_info[index].ack_msg;
ack->dest = ack_msg.dest;
ack->source = ack_msg.source;
ack->saddr = ack_msg.saddr;
ack->daddr = ack_msg.daddr;
ack->seq = ack_msg.seq;
write_sequnlock_bh(&ack_m->ack_info[index].seqlock);
}
out:
return ret;
}
void move_tcpack_msg(struct rwnx_hw *priv,
struct msg_buf *msg)
{
struct tcp_ack_info *ack_info;
struct tcp_ack_manage *ack_m = &priv->ack_m;
int i = 0;
if (!atomic_read(&ack_m->enable))
return;
//if (msg->len > MAX_TCP_ACK)
// return;
for (i = 0; i < TCP_ACK_NUM; i++) {
ack_info = &ack_m->ack_info[i];
write_seqlock_bh(&ack_info->seqlock);
if (ack_info->busy && (ack_info->in_send_msg == msg))
ack_info->in_send_msg = NULL;
write_sequnlock_bh(&ack_info->seqlock);
}
}

View File

@ -0,0 +1,111 @@
#ifndef _AICWF_TCP_ACK_H_
#define _AICWF_TCP_ACK_H_
#include <uapi/linux/if_ether.h>
#include <uapi/linux/tcp.h>
#include <uapi/linux/ip.h>
#include <uapi/linux/in.h>
#include <linux/moduleparam.h>
#include <net/tcp.h>
#include <linux/timer.h>
#define TCP_ACK_NUM 32
#define TCP_ACK_EXIT_VAL 0x800
#define TCP_ACK_DROP_CNT 10
#define ACK_OLD_TIME 4000
#define U32_BEFORE(a, b) ((__s32)((__u32)a - (__u32)b) <= 0)
#define MAX_TCP_ACK 200
/*min window size in KB, it's 256KB*/
#define MIN_WIN 256
#define SIZE_KB 1024
struct msg_buf {
//struct list_head list;
struct sk_buff *skb;
struct rwnx_vif *rwnx_vif;
/* data just tx cmd use,not include the head */
/*void *data;
void *tran_data;
unsigned long pcie_addr;
u8 type;
u8 mode;
u16 len;
unsigned long timeout;*/
/*unsigned int fifo_id;
struct sprdwl_msg_list *msglist;*/
/*unsigned char buffer_type;
struct sprdwl_xmit_msg_list *xmit_msg_list;
unsigned char msg_type;
unsigned long last_time;
u8 ctxt_id;*/
};
struct tcp_ack_msg {
u16 source;
u16 dest;
s32 saddr;
s32 daddr;
u32 seq;
u16 win;
};
struct tcp_ack_info {
int ack_info_num;
int busy;
int drop_cnt;
int psh_flag;
u32 psh_seq;
u16 win_scale;
/* seqlock for ack info */
seqlock_t seqlock;
unsigned long last_time;
unsigned long timeout;
struct timer_list timer;
struct msg_buf *msgbuf;
struct msg_buf *in_send_msg;
struct tcp_ack_msg ack_msg;
};
struct tcp_ack_manage {
/* 1 filter */
atomic_t enable;
int max_num;
int free_index;
unsigned long last_time;
unsigned long timeout;
atomic_t max_drop_cnt;
/* lock for tcp ack alloc and free */
spinlock_t lock;
struct rwnx_hw *priv;
struct tcp_ack_info ack_info[TCP_ACK_NUM];
/*size in KB*/
unsigned int ack_winsize;
};
struct msg_buf *intf_tcp_alloc_msg(struct msg_buf *msg);
void tcp_ack_init(struct rwnx_hw *priv);
void tcp_ack_deinit(struct rwnx_hw *priv);
int is_drop_tcp_ack(struct tcphdr *tcphdr, int tcp_tot_len, unsigned short *win_scale);
int is_tcp_ack(struct sk_buff *skb, unsigned short *win_scale);
int filter_send_tcp_ack(struct rwnx_hw *priv, struct msg_buf *msgbuf,unsigned char *buf, unsigned int plen);
void filter_rx_tcp_ack(struct rwnx_hw *priv,unsigned char *buf, unsigned plen);
void move_tcpack_msg(struct rwnx_hw *priv, struct msg_buf * msg);
#endif

View File

@ -0,0 +1,885 @@
/**
* aicwf_bus.c
*
* bus function declarations
*
* Copyright (C) AICSemi 2018-2020
*/
#include <linux/kthread.h>
#include <linux/netdevice.h>
#include <linux/printk.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/semaphore.h>
#include <linux/debugfs.h>
#include <linux/atomic.h>
#include <linux/vmalloc.h>
#include "lmac_msg.h"
#include "aicwf_txrxif.h"
#include "rwnx_platform.h"
#include "rwnx_defs.h"
#include "rwnx_msg_rx.h"
#include "rwnx_rx.h"
#include "aicwf_rx_prealloc.h"
#ifdef AICWF_SDIO_SUPPORT
#include "sdio_host.h"
#endif
#include "aic_bsp_export.h"
#ifdef CONFIG_PREALLOC_RX_SKB
void aicwf_rxframe_queue_init_2(struct rx_frame_queue *pq, int max_len)
{
//int prio;
memset(pq, 0, offsetof(struct rx_frame_queue, queuelist) + (sizeof(struct list_head)));
pq->qmax = (u16)max_len;
INIT_LIST_HEAD(&pq->queuelist);
#if 0
memset(pq, 0, offsetof(struct rx_frame_queue, queuelist) + (sizeof(struct list_head) * num_prio));
pq->num_prio = (u16)num_prio;
pq->qmax = (u16)max_len;
for (prio = 0; prio < num_prio; prio++) {
INIT_LIST_HEAD(&pq->queuelist[prio]);
}
#endif
}
//extern struct aic_sdio_dev *g_sdiodev;
void rxbuff_queue_flush(struct aicwf_rx_priv* rx_priv)
{
//int prio;
struct rx_frame_queue *pq = &rx_priv->rxq;
struct list_head *pos;
struct list_head *n;
struct list_head *head;
struct rx_buff *tempbuf = NULL;
head = &pq->queuelist;
list_for_each_safe(pos, n, head) {
tempbuf = list_entry(pos, struct rx_buff, queue);
list_del_init(&tempbuf->queue);
#if 0
rxbuff_free(tempbuf);
#else
aicwf_prealloc_rxbuff_free(tempbuf, &rx_priv->rxbuff_lock);
#endif
pq->qcnt--;
}
}
#endif
int aicwf_bus_init(uint bus_hdrlen, struct device *dev)
{
int ret = 0;
struct aicwf_bus *bus_if;
if (!dev) {
txrx_err("device not found\n");
return -1;
}
bus_if = dev_get_drvdata(dev);
bus_if->cmd_buf = kzalloc(CMD_BUF_MAX, GFP_KERNEL);
if (!bus_if->cmd_buf) {
ret = -ENOMEM;
txrx_err("proto_attach failed\n");
goto fail;
}
memset(bus_if->cmd_buf, '\0', CMD_BUF_MAX);
init_completion(&bus_if->bustx_trgg);
init_completion(&bus_if->busrx_trgg);
//new oob feature
init_completion(&bus_if->busirq_trgg);
#ifdef AICWF_SDIO_SUPPORT
spin_lock_init(&bus_if->bus_priv.sdio->wslock);//AIDEN test
bus_if->bustx_thread = kthread_run(sdio_bustx_thread, (void *)bus_if, "aicwf_bustx_thread");
bus_if->busrx_thread = kthread_run(sdio_busrx_thread, (void *)bus_if->bus_priv.sdio->rx_priv, "aicwf_busrx_thread");
//new oob feature
#ifdef CONFIG_OOB
if(bus_if->bus_priv.sdio->oob_enable){
bus_if->busirq_thread = kthread_run(sdio_busirq_thread, (void *)bus_if->bus_priv.sdio->rx_priv, "aicwf_busirq_thread");
}
#endif //CONFIG_OOB
#endif
#ifdef AICWF_USB_SUPPORT
bus_if->bustx_thread = kthread_run(usb_bustx_thread, (void *)bus_if, "aicwf_bustx_thread");
bus_if->busrx_thread = kthread_run(usb_busrx_thread, (void *)bus_if->bus_priv.usb->rx_priv, "aicwf_busrx_thread");
#endif
if (IS_ERR(bus_if->bustx_thread)) {
bus_if->bustx_thread = NULL;
txrx_err("aicwf_bustx_thread run fail\n");
goto fail;
}
if (IS_ERR(bus_if->busrx_thread)) {
bus_if->busrx_thread = NULL;
txrx_err("aicwf_bustx_thread run fail\n");
goto fail;
}
return ret;
fail:
aicwf_bus_deinit(dev);
return ret;
}
void aicwf_bus_deinit(struct device *dev)
{
struct aicwf_bus *bus_if;
#ifdef AICWF_USB_SUPPORT
struct aic_usb_dev *usb;
#endif
#ifdef AICWF_SDIO_SUPPORT
struct aic_sdio_dev *sdiodev;
#endif
if (!dev) {
txrx_err("device not found\n");
return;
}
AICWFDBG(LOGINFO, "%s Enter\r\n", __func__);
bus_if = dev_get_drvdata(dev);
aicwf_bus_stop(bus_if);
#ifdef AICWF_USB_SUPPORT
usb = bus_if->bus_priv.usb;
if (g_rwnx_plat->enabled)
rwnx_platform_deinit(usb->rwnx_hw);
#endif
#ifdef AICWF_SDIO_SUPPORT
sdiodev = bus_if->bus_priv.sdio;
if (g_rwnx_plat && g_rwnx_plat->enabled) {
rwnx_platform_deinit(sdiodev->rwnx_hw);
}
#endif
if (bus_if->cmd_buf) {
kfree(bus_if->cmd_buf);
bus_if->cmd_buf = NULL;
}
if (bus_if->bustx_thread) {
complete_all(&bus_if->bustx_trgg);
kthread_stop(bus_if->bustx_thread);
bus_if->bustx_thread = NULL;
}
AICWFDBG(LOGINFO, "%s Exit\r\n", __func__);
}
void aicwf_frame_tx(void *dev, struct sk_buff *skb)
{
#ifdef AICWF_SDIO_SUPPORT
struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *)dev;
aicwf_bus_txdata(sdiodev->bus_if, skb);
#else
struct aic_usb_dev *usbdev = (struct aic_usb_dev *)dev;
if (!usbdev->state) {
txrx_err("down\n");
aicwf_usb_tx_flowctrl(usbdev->rwnx_hw, true);
dev_kfree_skb(skb);
return;
}
aicwf_bus_txdata(usbdev->bus_if, skb);
#endif
}
struct aicwf_tx_priv *aicwf_tx_init(void *arg)
{
struct aicwf_tx_priv *tx_priv;
tx_priv = kzalloc(sizeof(struct aicwf_tx_priv), GFP_KERNEL);
if (!tx_priv)
return NULL;
#ifdef AICWF_SDIO_SUPPORT
tx_priv->sdiodev = (struct aic_sdio_dev *)arg;
#else
tx_priv->usbdev = (struct aic_usb_dev *)arg;
#endif
atomic_set(&tx_priv->aggr_count, 0);
#ifdef CONFIG_RESV_MEM_SUPPORT
tx_priv->aggr_buf = aicbsp_resv_mem_alloc_skb(MAX_AGGR_TXPKT_LEN, AIC_RESV_MEM_TXDATA);
#else
tx_priv->aggr_buf = dev_alloc_skb(MAX_AGGR_TXPKT_LEN);
#endif
if (!tx_priv->aggr_buf) {
txrx_err("Alloc bus->txdata_buf failed!\n");
kfree(tx_priv);
return NULL;
}
tx_priv->head = tx_priv->aggr_buf->data;
tx_priv->tail = tx_priv->aggr_buf->data;
return tx_priv;
}
void aicwf_tx_deinit(struct aicwf_tx_priv *tx_priv)
{
if (tx_priv && tx_priv->aggr_buf) {
#ifdef CONFIG_RESV_MEM_SUPPORT
aicbsp_resv_mem_kfree_skb(tx_priv->aggr_buf, AIC_RESV_MEM_TXDATA);
#else
dev_kfree_skb(tx_priv->aggr_buf);
#endif
kfree(tx_priv);
}
}
#ifdef AICWF_SDIO_SUPPORT
#ifdef CONFIG_PREALLOC_RX_SKB
static bool aicwf_another_ptk_1(struct rx_buff *buffer)
{
u8 *read = buffer->read;
u16 aggr_len = 0;
BUG_ON((read - buffer->start)%4 != 0);
if(read == NULL || read >= buffer->end) {
return false;
}
aggr_len = (*read | (*(read + 1) << 8));
if(aggr_len == 0) {
return false;
}
return true;
}
#else
static bool aicwf_another_ptk(struct sk_buff *skb)
{
u8 *data;
u16 aggr_len = 0;
if (skb->data == NULL || skb->len == 0) {
return false;
}
data = skb->data;
aggr_len = (*skb->data | (*(skb->data + 1) << 8));
if (aggr_len == 0) {
return false;
}
return true;
}
#endif
#endif
int aicwf_process_rxframes(struct aicwf_rx_priv *rx_priv)
{
#ifdef AICWF_SDIO_SUPPORT
int ret = 0;
unsigned long flags = 0;
#ifndef CONFIG_PREALLOC_RX_SKB
struct sk_buff *skb = NULL;
#endif
u16 pkt_len = 0;
struct sk_buff *skb_inblock = NULL;
u16 aggr_len = 0, adjust_len = 0;
u8 *data = NULL;
u8_l *msg = NULL;
#ifdef CONFIG_PREALLOC_RX_SKB
struct rx_buff *buffer = NULL;
while (1) {
spin_lock_irqsave(&rx_priv->rxqlock, flags);
if (!rx_priv->rxq.qcnt) {
spin_unlock_irqrestore(&rx_priv->rxqlock, flags);
break;
}
buffer = rxbuff_dequeue(&rx_priv->rxq);
spin_unlock_irqrestore(&rx_priv->rxqlock, flags);
if (buffer == NULL) {
txrx_err("skb_error\r\n");
break;
}
while (aicwf_another_ptk_1(buffer)) {
data = buffer->read;
pkt_len = (*data | (*(data + 1) << 8));
if ((data[2] & SDIO_TYPE_CFG) != SDIO_TYPE_CFG) { // type : data
aggr_len = pkt_len + RX_HWHRD_LEN;
if (aggr_len & (RX_ALIGNMENT - 1))
adjust_len = roundup(aggr_len, RX_ALIGNMENT);
else
adjust_len = aggr_len;
skb_inblock = __dev_alloc_skb(aggr_len + CCMP_OR_WEP_INFO, GFP_KERNEL);
if (skb_inblock == NULL) {
txrx_err("no more space! skip\n");
buffer->read = buffer->read + adjust_len;
continue;
}
skb_put(skb_inblock, aggr_len);
memcpy(skb_inblock->data, data, aggr_len);
rwnx_rxdataind_aicwf(rx_priv->sdiodev->rwnx_hw, skb_inblock, (void *)rx_priv);
buffer->read = buffer->read + adjust_len;
} else {
// type : config
aggr_len = pkt_len;
if (aggr_len & (RX_ALIGNMENT - 1))
adjust_len = roundup(aggr_len, RX_ALIGNMENT);
else
adjust_len = aggr_len;
msg = kmalloc(aggr_len+4, GFP_KERNEL);
if (msg == NULL) {
txrx_err("no more space for msg!\n");
aicwf_prealloc_rxbuff_free(buffer, &rx_priv->rxbuff_lock);
return -EBADE;
}
memcpy(msg, data, aggr_len + 4);
if (((*(msg + 2) & 0x7f) == SDIO_TYPE_CFG_CMD_RSP) && (rx_priv->sdiodev->bus_if->state != BUS_DOWN_ST))
rwnx_rx_handle_msg(rx_priv->sdiodev->rwnx_hw, (struct ipc_e2a_msg *)(msg + 4));
if ((*(msg + 2) & 0x7f) == SDIO_TYPE_CFG_DATA_CFM)
aicwf_sdio_host_tx_cfm_handler(&(rx_priv->sdiodev->rwnx_hw->sdio_env), (u32 *)(msg + 4));
if ((*(msg + 2) & 0x7f) == SDIO_TYPE_CFG_PRINT)
rwnx_rx_handle_print(rx_priv->sdiodev->rwnx_hw, msg + 4, aggr_len);
buffer->read = buffer->read + (adjust_len + 4);
kfree(msg);
}
}
aicwf_prealloc_rxbuff_free(buffer, &rx_priv->rxbuff_lock);
atomic_dec(&rx_priv->rx_cnt);
}
#else
while (1) {
spin_lock_irqsave(&rx_priv->rxqlock, flags);
if (aicwf_is_framequeue_empty(&rx_priv->rxq)) {
spin_unlock_irqrestore(&rx_priv->rxqlock, flags);
break;
}
skb = aicwf_frame_dequeue(&rx_priv->rxq);
spin_unlock_irqrestore(&rx_priv->rxqlock, flags);
if (skb == NULL) {
txrx_err("skb_error\r\n");
break;
}
while (aicwf_another_ptk(skb)) {
data = skb->data;
pkt_len = (*skb->data | (*(skb->data + 1) << 8));
if ((skb->data[2] & SDIO_TYPE_CFG) != SDIO_TYPE_CFG) { // type : data
aggr_len = pkt_len + RX_HWHRD_LEN;
if (aggr_len & (RX_ALIGNMENT - 1))
adjust_len = roundup(aggr_len, RX_ALIGNMENT);
else
adjust_len = aggr_len;
skb_inblock = __dev_alloc_skb(aggr_len + CCMP_OR_WEP_INFO, GFP_KERNEL);
if (skb_inblock == NULL) {
txrx_err("no more space! skip\n");
skb_pull(skb, adjust_len);
continue;
}
skb_put(skb_inblock, aggr_len);
memcpy(skb_inblock->data, data, aggr_len);
rwnx_rxdataind_aicwf(rx_priv->sdiodev->rwnx_hw, skb_inblock, (void *)rx_priv);
skb_pull(skb, adjust_len);
} else {
// type : config
aggr_len = pkt_len;
if (aggr_len & (RX_ALIGNMENT - 1))
adjust_len = roundup(aggr_len, RX_ALIGNMENT);
else
adjust_len = aggr_len;
msg = kmalloc(aggr_len+4, GFP_KERNEL);
if (msg == NULL) {
txrx_err("no more space for msg!\n");
aicwf_dev_skb_free(skb);
return -EBADE;
}
memcpy(msg, data, aggr_len + 4);
if (((*(msg + 2) & 0x7f) == SDIO_TYPE_CFG_CMD_RSP) && (rx_priv->sdiodev->bus_if->state != BUS_DOWN_ST))
rwnx_rx_handle_msg(rx_priv->sdiodev->rwnx_hw, (struct ipc_e2a_msg *)(msg + 4));
if ((*(msg + 2) & 0x7f) == SDIO_TYPE_CFG_DATA_CFM)
aicwf_sdio_host_tx_cfm_handler(&(rx_priv->sdiodev->rwnx_hw->sdio_env), (u32 *)(msg + 4));
if ((*(msg + 2) & 0x7f) == SDIO_TYPE_CFG_PRINT)
rwnx_rx_handle_print(rx_priv->sdiodev->rwnx_hw, msg + 4, aggr_len);
skb_pull(skb, adjust_len+4);
kfree(msg);
}
}
dev_kfree_skb(skb);
atomic_dec(&rx_priv->rx_cnt);
}
#endif
#if defined(CONFIG_SDIO_PWRCTRL)
aicwf_sdio_pwr_stctl(rx_priv->sdiodev, SDIO_ACTIVE_ST);
#endif
return ret;
#else //AICWF_USB_SUPPORT
int ret = 0;
unsigned long flags = 0;
struct sk_buff *skb = NULL; /* Packet for event or data frames */
u16 pkt_len = 0;
struct sk_buff *skb_inblock = NULL;
u16 aggr_len = 0, adjust_len = 0;
u8 *data = NULL;
u8_l *msg = NULL;
while (1) {
spin_lock_irqsave(&rx_priv->rxqlock, flags);
if (aicwf_is_framequeue_empty(&rx_priv->rxq)) {
usb_info("no more rxdata\n");
spin_unlock_irqrestore(&rx_priv->rxqlock, flags);
break;
}
skb = aicwf_frame_dequeue(&rx_priv->rxq);
spin_unlock_irqrestore(&rx_priv->rxqlock, flags);
if (skb == NULL) {
txrx_err("skb_error\r\n");
break;
}
data = skb->data;
pkt_len = (*skb->data | (*(skb->data + 1) << 8));
//printk("p:%d, s:%d , %x\n", pkt_len, skb->len, data[2]);
if (pkt_len > 1600) {
dev_kfree_skb(skb);
atomic_dec(&rx_priv->rx_cnt);
continue;
}
if ((skb->data[2] & USB_TYPE_CFG) != USB_TYPE_CFG) { // type : data
aggr_len = pkt_len + RX_HWHRD_LEN;
if (aggr_len & (RX_ALIGNMENT - 1))
adjust_len = roundup(aggr_len, RX_ALIGNMENT);
else
adjust_len = aggr_len;
skb_inblock = __dev_alloc_skb(aggr_len + CCMP_OR_WEP_INFO, GFP_KERNEL);//8 is for ccmp mic or wep icv
if (skb_inblock == NULL) {
txrx_err("no more space! skip!\n");
skb_pull(skb, adjust_len);
continue;
}
skb_put(skb_inblock, aggr_len);
memcpy(skb_inblock->data, data, aggr_len);
rwnx_rxdataind_aicwf(rx_priv->usbdev->rwnx_hw, skb_inblock, (void *)rx_priv);
///TODO: here need to add rx data process
skb_pull(skb, adjust_len);
} else { // type : config
aggr_len = pkt_len;
if (aggr_len & (RX_ALIGNMENT - 1))
adjust_len = roundup(aggr_len, RX_ALIGNMENT);
else
adjust_len = aggr_len;
msg = kmalloc(aggr_len+4, GFP_KERNEL);
if (msg == NULL) {
txrx_err("no more space for msg!\n");
aicwf_dev_skb_free(skb);
return -EBADE;
}
memcpy(msg, data, aggr_len + 4);
if ((*(msg + 2) & 0x7f) == USB_TYPE_CFG_CMD_RSP)
rwnx_rx_handle_msg(rx_priv->usbdev->rwnx_hw, (struct ipc_e2a_msg *)(msg + 4));
if ((*(msg + 2) & 0x7f) == USB_TYPE_CFG_DATA_CFM)
aicwf_usb_host_tx_cfm_handler(&(rx_priv->usbdev->rwnx_hw->usb_env), (u32 *)(msg + 4));
skb_pull(skb, adjust_len + 4);
kfree(msg);
}
dev_kfree_skb(skb);
atomic_dec(&rx_priv->rx_cnt);
}
return ret;
#endif //AICWF_SDIO_SUPPORT
}
static struct recv_msdu *aicwf_rxframe_queue_init(struct list_head *q, int qsize)
{
int i;
struct recv_msdu *req, *reqs;
reqs = vmalloc(qsize*sizeof(struct recv_msdu));
if (reqs == NULL)
return NULL;
req = reqs;
for (i = 0; i < qsize; i++) {
INIT_LIST_HEAD(&req->rxframe_list);
list_add(&req->rxframe_list, q);
req++;
}
return reqs;
}
struct aicwf_rx_priv *aicwf_rx_init(void *arg)
{
struct aicwf_rx_priv *rx_priv;
rx_priv = kzalloc(sizeof(struct aicwf_rx_priv), GFP_KERNEL);
if (!rx_priv)
return NULL;
#ifdef AICWF_SDIO_SUPPORT
rx_priv->sdiodev = (struct aic_sdio_dev *)arg;
#else
rx_priv->usbdev = (struct aic_usb_dev *)arg;
#endif
#ifdef CONFIG_PREALLOC_RX_SKB
aicwf_rxframe_queue_init_2(&rx_priv->rxq, MAX_RXQLEN);
#else
aicwf_frame_queue_init(&rx_priv->rxq, 1, MAX_RXQLEN);
#endif
spin_lock_init(&rx_priv->rxqlock);
#ifdef CONFIG_PREALLOC_RX_SKB
spin_lock_init(&rx_priv->rxbuff_lock);
aicwf_prealloc_init();
#endif
atomic_set(&rx_priv->rx_cnt, 0);
#ifdef AICWF_RX_REORDER
INIT_LIST_HEAD(&rx_priv->rxframes_freequeue);
spin_lock_init(&rx_priv->freeq_lock);
rx_priv->recv_frames = aicwf_rxframe_queue_init(&rx_priv->rxframes_freequeue, MAX_REORD_RXFRAME);
if (!rx_priv->recv_frames) {
txrx_err("no enough buffer for free recv frame queue!\n");
kfree(rx_priv);
return NULL;
}
spin_lock_init(&rx_priv->stas_reord_lock);
INIT_LIST_HEAD(&rx_priv->stas_reord_list);
#endif
return rx_priv;
}
static void aicwf_recvframe_queue_deinit(struct list_head *q)
{
struct recv_msdu *req, *next;
list_for_each_entry_safe(req, next, q, rxframe_list) {
list_del_init(&req->rxframe_list);
}
}
void aicwf_rx_deinit(struct aicwf_rx_priv *rx_priv)
{
#ifdef AICWF_RX_REORDER
struct reord_ctrl_info *reord_info, *tmp;
AICWFDBG(LOGINFO, "%s\n", __func__);
spin_lock_bh(&rx_priv->stas_reord_lock);
list_for_each_entry_safe(reord_info, tmp,
&rx_priv->stas_reord_list, list) {
reord_deinit_sta(rx_priv, reord_info);
}
spin_unlock_bh(&rx_priv->stas_reord_lock);
#endif
#ifdef AICWF_SDIO_SUPPORT
AICWFDBG(LOGINFO, "sdio rx thread\n");
if (rx_priv->sdiodev->bus_if->busrx_thread) {
complete_all(&rx_priv->sdiodev->bus_if->busrx_trgg);
kthread_stop(rx_priv->sdiodev->bus_if->busrx_thread);
rx_priv->sdiodev->bus_if->busrx_thread = NULL;
}
#ifdef CONFIG_OOB
if(rx_priv->sdiodev->oob_enable){
//new oob feature
if (rx_priv->sdiodev->bus_if->busirq_thread) {
complete_all(&rx_priv->sdiodev->bus_if->busirq_trgg);
kthread_stop(rx_priv->sdiodev->bus_if->busirq_thread);
rx_priv->sdiodev->bus_if->busirq_thread = NULL;
}
}
#endif //CONFIG_OOB
#endif
#ifdef AICWF_USB_SUPPORT
if (rx_priv->usbdev->bus_if->busrx_thread) {
complete_all(&rx_priv->usbdev->bus_if->busrx_trgg);
kthread_stop(rx_priv->usbdev->bus_if->busrx_thread);
rx_priv->usbdev->bus_if->busrx_thread = NULL;
}
#endif
#ifdef CONFIG_PREALLOC_RX_SKB
rxbuff_queue_flush(rx_priv);
#else
aicwf_frame_queue_flush(&rx_priv->rxq);
#endif
#ifdef AICWF_RX_REORDER
aicwf_recvframe_queue_deinit(&rx_priv->rxframes_freequeue);
if (rx_priv->recv_frames)
vfree(rx_priv->recv_frames);
#endif
#ifdef CONFIG_PREALLOC_RX_SKB
aicwf_prealloc_exit();
#endif
kfree(rx_priv);
AICWFDBG(LOGINFO, "%s exit \n", __func__);
}
bool aicwf_rxframe_enqueue(struct device *dev, struct frame_queue *q, struct sk_buff *pkt)
{
return aicwf_frame_enq(dev, q, pkt, 0);
}
void aicwf_dev_skb_free(struct sk_buff *skb)
{
if (!skb)
return;
dev_kfree_skb_any(skb);
}
static struct sk_buff *aicwf_frame_queue_penq(struct frame_queue *pq, int prio, struct sk_buff *p)
{
struct sk_buff_head *q;
if (pq->queuelist[prio].qlen >= pq->qmax)
return NULL;
q = &pq->queuelist[prio];
__skb_queue_tail(q, p);
pq->qcnt++;
if (pq->hi_prio < prio)
pq->hi_prio = (u16)prio;
return p;
}
void aicwf_frame_queue_flush(struct frame_queue *pq)
{
int prio;
struct sk_buff_head *q;
struct sk_buff *p, *next;
for (prio = 0; prio < pq->num_prio; prio++) {
q = &pq->queuelist[prio];
skb_queue_walk_safe(q, p, next) {
skb_unlink(p, q);
aicwf_dev_skb_free(p);
pq->qcnt--;
}
}
}
void aicwf_frame_queue_init(struct frame_queue *pq, int num_prio, int max_len)
{
int prio;
memset(pq, 0, offsetof(struct frame_queue, queuelist) + (sizeof(struct sk_buff_head) * num_prio));
pq->num_prio = (u16)num_prio;
pq->qmax = (u16)max_len;
for (prio = 0; prio < num_prio; prio++) {
skb_queue_head_init(&pq->queuelist[prio]);
}
}
struct sk_buff *aicwf_frame_queue_peek_tail(struct frame_queue *pq, int *prio_out)
{
int prio;
if (pq->qcnt == 0)
return NULL;
for (prio = 0; prio < pq->hi_prio; prio++)
if (!skb_queue_empty(&pq->queuelist[prio]))
break;
if (prio_out)
*prio_out = prio;
return skb_peek_tail(&pq->queuelist[prio]);
}
bool aicwf_is_framequeue_empty(struct frame_queue *pq)
{
int prio, len = 0;
for (prio = 0; prio <= pq->hi_prio; prio++)
len += pq->queuelist[prio].qlen;
if (len > 0)
return false;
else
return true;
}
struct sk_buff *aicwf_frame_dequeue(struct frame_queue *pq)
{
struct sk_buff_head *q;
struct sk_buff *p;
int prio;
if (pq->qcnt == 0)
return NULL;
while ((prio = pq->hi_prio) > 0 && skb_queue_empty(&pq->queuelist[prio]))
pq->hi_prio--;
q = &pq->queuelist[prio];
p = __skb_dequeue(q);
if (p == NULL)
return NULL;
pq->qcnt--;
return p;
}
#if 0
static struct sk_buff *aicwf_skb_dequeue_tail(struct frame_queue *pq, int prio)
{
struct sk_buff_head *q = &pq->queuelist[prio];
struct sk_buff *p = skb_dequeue_tail(q);
if (!p)
return NULL;
pq->qcnt--;
return p;
}
#endif
bool aicwf_frame_enq(struct device *dev, struct frame_queue *q, struct sk_buff *pkt, int prio)
{
#if 0
struct sk_buff *p = NULL;
int prio_modified = -1;
if (q->queuelist[prio].qlen < q->qmax && q->qcnt < q->qmax) {
aicwf_frame_queue_penq(q, prio, pkt);
return true;
}
if (q->queuelist[prio].qlen >= q->qmax) {
prio_modified = prio;
} else if (q->qcnt >= q->qmax) {
p = aicwf_frame_queue_peek_tail(q, &prio_modified);
if (prio_modified > prio)
return false;
}
if (prio_modified >= 0) {
if (prio_modified == prio)
return false;
p = aicwf_skb_dequeue_tail(q, prio_modified);
aicwf_dev_skb_free(p);
p = aicwf_frame_queue_penq(q, prio_modified, pkt);
if (p == NULL)
txrx_err("failed\n");
}
return p != NULL;
#else
if (q->queuelist[prio].qlen < q->qmax && q->qcnt < q->qmax) {
aicwf_frame_queue_penq(q, prio, pkt);
return true;
} else
return false;
#endif
}
#ifdef CONFIG_PREALLOC_RX_SKB
void rxbuff_free(struct rx_buff *rxbuff)
{
kfree(rxbuff->data);
kfree(rxbuff);
}
struct rx_buff *rxbuff_queue_penq(struct rx_frame_queue *pq, struct rx_buff *p)
{
struct list_head *q;
if (pq->qcnt >= pq->qmax)
return NULL;
q = &pq->queuelist;
list_add_tail(&p->queue,q);
pq->qcnt++;
return p;
}
struct rx_buff *rxbuff_dequeue(struct rx_frame_queue *pq)
{
struct rx_buff *p = NULL;
if (pq->qcnt == 0) {
printk("%s %d, rxq is empty\n", __func__, __LINE__);
return NULL;
}
if(list_empty(&pq->queuelist)) {
printk("%s %d, rxq is empty\n", __func__, __LINE__);
return NULL;
} else {
p = list_first_entry(&pq->queuelist, struct rx_buff, queue);
list_del_init(&p->queue);
pq->qcnt--;
}
return p;
}
bool aicwf_rxbuff_enqueue(struct device *dev, struct rx_frame_queue *rxq, struct rx_buff *pkt)
{
// struct rx_buff *p = NULL;
if ((rxq == NULL) || (pkt == NULL)) {
printk("%s %d, rxq or pkt is NULL\n", __func__, __LINE__);
return false;
}
if (rxq->qcnt < rxq->qmax) {
if (rxbuff_queue_penq(rxq, pkt)) {
return true;
} else {
printk("%s %d, rxbuff enqueue fail\n", __func__, __LINE__);
return false;
}
} else {
printk("%s %d, rxq or pkt is full\n", __func__, __LINE__);
return false;
}
}
#endif

View File

@ -0,0 +1,262 @@
/**
* aicwf_txrxif.h
*
* bus function declarations
*
* Copyright (C) AICSemi 2018-2020
*/
#ifndef _AICWF_TXRXIF_H_
#define _AICWF_TXRXIF_H_
#include <linux/skbuff.h>
#include <linux/sched.h>
#include "ipc_shared.h"
#include "aicwf_rx_prealloc.h"
#ifdef AICWF_SDIO_SUPPORT
#include "aicwf_sdio.h"
#else
#include "aicwf_usb.h"
#endif
#define CMD_BUF_MAX 1536
#define TXPKT_BLOCKSIZE 512
#define MAX_AGGR_TXPKT_LEN (1536*64)
#define CMD_TX_TIMEOUT 5000
#define TX_ALIGNMENT 4
#define RX_HWHRD_LEN 60 //58->60 word allined
#define CCMP_OR_WEP_INFO 8
#define MAX_RXQLEN 2000
#define RX_ALIGNMENT 4
#define DEBUG_ERROR_LEVEL 0
#define DEBUG_DEBUG_LEVEL 1
#define DEBUG_INFO_LEVEL 2
#define DBG_LEVEL DEBUG_DEBUG_LEVEL
#define txrx_err(fmt, ...) pr_err("txrx_err:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__)
#define sdio_err(fmt, ...) pr_err("sdio_err:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__)
#define usb_err(fmt, ...) pr_err("usb_err:<%s,%d>: " fmt, __func__, __LINE__, ##__VA_ARGS__)
#if DBG_LEVEL >= DEBUG_DEBUG_LEVEL
#define txrx_dbg(fmt, ...) printk("txrx: " fmt, ##__VA_ARGS__)
#define sdio_dbg(fmt, ...) printk("aicsdio: " fmt, ##__VA_ARGS__)
#define usb_dbg(fmt, ...) printk("aicusb: " fmt, ##__VA_ARGS__)
#else
#define txrx_dbg(fmt, ...)
#define sdio_dbg(fmt, ...)
#define usb_dbg(fmt, ...)
#endif
#if DBG_LEVEL >= DEBUG_INFO_LEVEL
#define txrx_info(fmt, ...) printk("aicsdio: " fmt, ##__VA_ARGS__)
#define sdio_info(fmt, ...) printk("aicsdio: " fmt, ##__VA_ARGS__)
#define usb_info(fmt, ...) printk("aicusb: " fmt, ##__VA_ARGS__)
#else
#define txrx_info(fmt, ...)
#define sdio_info(fmt, ...)
#define usb_info(fmt, ...)
#endif
enum aicwf_bus_state {
BUS_DOWN_ST,
BUS_UP_ST
};
struct aicwf_bus_ops {
int (*start) (struct device *dev);
void (*stop) (struct device *dev);
int (*txdata) (struct device *dev, struct sk_buff *skb);
int (*txmsg) (struct device *dev, u8 *msg, uint len);
};
struct frame_queue {
u16 num_prio;
u16 hi_prio;
u16 qmax; /* max number of queued frames */
u16 qcnt;
struct sk_buff_head queuelist[8];
};
#ifdef CONFIG_PREALLOC_RX_SKB
struct rx_frame_queue {
u16 qmax; /* max number of queued frames */
u16 qcnt;
struct list_head queuelist;
};
#endif
struct aicwf_bus {
union {
struct aic_sdio_dev *sdio;
struct aic_usb_dev *usb;
} bus_priv;
struct device *dev;
struct aicwf_bus_ops *ops;
enum aicwf_bus_state state;
u8 *cmd_buf;
struct completion bustx_trgg;
struct completion busrx_trgg;
struct completion busirq_trgg;//new oob feature
struct task_struct *bustx_thread;
struct task_struct *busrx_thread;
struct task_struct *busirq_thread;//new oob feature
};
struct aicwf_tx_priv {
#ifdef AICWF_SDIO_SUPPORT
struct aic_sdio_dev *sdiodev;
int fw_avail_bufcnt;
//for cmd tx
u8 *cmd_buf;
uint cmd_len;
bool cmd_txstate;
bool cmd_tx_succ;
struct semaphore cmd_txsema;
wait_queue_head_t cmd_txdone_wait;
//for data tx
atomic_t tx_pktcnt;
struct frame_queue txq;
spinlock_t txqlock;
struct semaphore txctl_sema;
#endif
#ifdef AICWF_USB_SUPPORT
struct aic_usb_dev *usbdev;
#endif
struct sk_buff *aggr_buf;
atomic_t aggr_count;
u8 *head;
u8 *tail;
};
#define DEFRAG_MAX_WAIT 40 //100
#ifdef AICWF_RX_REORDER
#define MAX_REORD_RXFRAME 250
#define REORDER_UPDATE_TIME 50
#define AICWF_REORDER_WINSIZE 64
#define SN_LESS(a, b) (((a-b)&0x800) != 0)
#define SN_EQUAL(a, b) (a == b)
struct reord_ctrl {
struct aicwf_rx_priv *rx_priv;
u8 enable;
u16 ind_sn;
u8 wsize_b;
spinlock_t reord_list_lock;
struct list_head reord_list;
struct timer_list reord_timer;
struct work_struct reord_timer_work;
};
struct reord_ctrl_info {
u8 mac_addr[6];
struct reord_ctrl preorder_ctrl[8];
struct list_head list;
};
struct recv_msdu {
struct sk_buff *pkt;
u8 tid;
u16 seq_num;
u8 forward;
//uint len;
u32 is_amsdu;
u8 *rx_data;
//for pending rx reorder list
struct list_head reord_pending_list;
//for total frame list, when rxframe from busif, dequeue, when submit frame to net, enqueue
struct list_head rxframe_list;
struct reord_ctrl *preorder_ctrl;
};
#endif
struct aicwf_rx_priv {
#ifdef AICWF_SDIO_SUPPORT
struct aic_sdio_dev *sdiodev;
#endif
#ifdef AICWF_USB_SUPPORT
struct aic_usb_dev *usbdev;
#endif
void *rwnx_vif;
atomic_t rx_cnt;
u32 data_len;
spinlock_t rxqlock;
#ifdef CONFIG_PREALLOC_RX_SKB
struct rx_frame_queue rxq;
#else
struct frame_queue rxq;
#endif
#ifdef AICWF_RX_REORDER
spinlock_t freeq_lock;
struct list_head rxframes_freequeue;
struct list_head stas_reord_list;
spinlock_t stas_reord_lock;
struct recv_msdu *recv_frames;
#endif
#ifdef CONFIG_PREALLOC_RX_SKB
spinlock_t rxbuff_lock;
#endif
};
static inline int aicwf_bus_start(struct aicwf_bus *bus)
{
return bus->ops->start(bus->dev);
}
static inline void aicwf_bus_stop(struct aicwf_bus *bus)
{
bus->ops->stop(bus->dev);
}
static inline int aicwf_bus_txdata(struct aicwf_bus *bus, struct sk_buff *skb)
{
return bus->ops->txdata(bus->dev, skb);
}
static inline int aicwf_bus_txmsg(struct aicwf_bus *bus, u8 *msg, uint len)
{
return bus->ops->txmsg(bus->dev, msg, len);
}
static inline void aicwf_sched_timeout(u32 millisec)
{
ulong timeout = 0, expires = 0;
expires = jiffies + msecs_to_jiffies(millisec);
timeout = millisec;
while (timeout) {
timeout = schedule_timeout(timeout);
if (time_after(jiffies, expires))
break;
}
}
int aicwf_bus_init(uint bus_hdrlen, struct device *dev);
void aicwf_bus_deinit(struct device *dev);
void aicwf_tx_deinit(struct aicwf_tx_priv *tx_priv);
void aicwf_rx_deinit(struct aicwf_rx_priv *rx_priv);
struct aicwf_tx_priv *aicwf_tx_init(void *arg);
struct aicwf_rx_priv *aicwf_rx_init(void *arg);
void aicwf_frame_queue_init(struct frame_queue *pq, int num_prio, int max_len);
void aicwf_frame_queue_flush(struct frame_queue *pq);
bool aicwf_frame_enq(struct device *dev, struct frame_queue *q, struct sk_buff *pkt, int prio);
bool aicwf_rxframe_enqueue(struct device *dev, struct frame_queue *q, struct sk_buff *pkt);
bool aicwf_is_framequeue_empty(struct frame_queue *pq);
void aicwf_frame_tx(void *dev, struct sk_buff *skb);
void aicwf_dev_skb_free(struct sk_buff *skb);
struct sk_buff *aicwf_frame_dequeue(struct frame_queue *pq);
struct sk_buff *aicwf_frame_queue_peek_tail(struct frame_queue *pq, int *prio_out);
#ifdef CONFIG_PREALLOC_RX_SKB
void rxbuff_queue_flush(struct aicwf_rx_priv* rx_priv);
void aicwf_rxframe_queue_init_2(struct rx_frame_queue *pq, int max_len);
void rxbuff_free(struct rx_buff *rxbuff);
struct rx_buff *rxbuff_dequeue(struct rx_frame_queue *pq);
bool aicwf_rxbuff_enqueue(struct device *dev, struct rx_frame_queue *rxq, struct rx_buff *pkt);
extern struct aicwf_rx_buff_list aic_rx_buff_list;
#endif
#endif /* _AICWF_TXRXIF_H_ */

View File

@ -0,0 +1,957 @@
/**
* aicwf_usb.c
*
* USB function declarations
*
* Copyright (C) AICSemi 2018-2020
*/
#include <linux/usb.h>
#include <linux/kthread.h>
#include "aicwf_txrxif.h"
#include "aicwf_usb.h"
#include "rwnx_tx.h"
#include "rwnx_defs.h"
#include "usb_host.h"
#include "rwnx_platform.h"
void aicwf_usb_tx_flowctrl(struct rwnx_hw *rwnx_hw, bool state)
{
struct rwnx_vif *rwnx_vif;
list_for_each_entry(rwnx_vif, &rwnx_hw->vifs, list) {
if (!rwnx_vif->up)
continue;
if (!rwnx_vif->ndev)
continue;
if (state)
netif_stop_queue(rwnx_vif->ndev);
else
netif_wake_queue(rwnx_vif->ndev);
}
}
static struct aicwf_usb_buf *aicwf_usb_tx_dequeue(struct aic_usb_dev *usb_dev,
struct list_head *q, int *counter, spinlock_t *qlock)
{
unsigned long flags;
struct aicwf_usb_buf *usb_buf;
spin_lock_irqsave(qlock, flags);
if (list_empty(q)) {
usb_buf = NULL;
} else {
usb_buf = list_first_entry(q, struct aicwf_usb_buf, list);
list_del_init(&usb_buf->list);
if (counter)
(*counter)--;
}
spin_unlock_irqrestore(qlock, flags);
return usb_buf;
}
static void aicwf_usb_tx_queue(struct aic_usb_dev *usb_dev,
struct list_head *q, struct aicwf_usb_buf *usb_buf, int *counter,
spinlock_t *qlock)
{
unsigned long flags;
spin_lock_irqsave(qlock, flags);
list_add_tail(&usb_buf->list, q);
(*counter)++;
spin_unlock_irqrestore(qlock, flags);
}
static struct aicwf_usb_buf *aicwf_usb_rx_buf_get(struct aic_usb_dev *usb_dev)
{
unsigned long flags;
struct aicwf_usb_buf *usb_buf;
spin_lock_irqsave(&usb_dev->rx_free_lock, flags);
if (list_empty(&usb_dev->rx_free_list)) {
usb_buf = NULL;
} else {
usb_buf = list_first_entry(&usb_dev->rx_free_list, struct aicwf_usb_buf, list);
list_del_init(&usb_buf->list);
}
spin_unlock_irqrestore(&usb_dev->rx_free_lock, flags);
return usb_buf;
}
static void aicwf_usb_rx_buf_put(struct aic_usb_dev *usb_dev, struct aicwf_usb_buf *usb_buf)
{
unsigned long flags;
spin_lock_irqsave(&usb_dev->rx_free_lock, flags);
list_add_tail(&usb_buf->list, &usb_dev->rx_free_list);
spin_unlock_irqrestore(&usb_dev->rx_free_lock, flags);
}
static void aicwf_usb_tx_complete(struct urb *urb)
{
unsigned long flags;
struct aicwf_usb_buf *usb_buf = (struct aicwf_usb_buf *) urb->context;
struct aic_usb_dev *usb_dev = usb_buf->usbdev;
struct sk_buff *skb;
u8 *buf;
if (usb_buf->cfm == false) {
skb = usb_buf->skb;
} else {
buf = (u8 *)usb_buf->skb;
}
if (usb_buf->cfm == false) {
dev_kfree_skb_any(skb);
} else {
kfree(buf);
}
usb_buf->skb = NULL;
aicwf_usb_tx_queue(usb_dev, &usb_dev->tx_free_list, usb_buf,
&usb_dev->tx_free_count, &usb_dev->tx_free_lock);
spin_lock_irqsave(&usb_dev->tx_flow_lock, flags);
if (usb_dev->tx_free_count > AICWF_USB_TX_HIGH_WATER) {
if (usb_dev->tbusy) {
usb_dev->tbusy = false;
aicwf_usb_tx_flowctrl(usb_dev->rwnx_hw, false);
}
}
spin_unlock_irqrestore(&usb_dev->tx_flow_lock, flags);
}
static void aicwf_usb_rx_complete(struct urb *urb)
{
struct aicwf_usb_buf *usb_buf = (struct aicwf_usb_buf *) urb->context;
struct aic_usb_dev *usb_dev = usb_buf->usbdev;
struct aicwf_rx_priv *rx_priv = usb_dev->rx_priv;
struct sk_buff *skb = NULL;
unsigned long flags = 0;
skb = usb_buf->skb;
usb_buf->skb = NULL;
if (urb->actual_length > urb->transfer_buffer_length) {
aicwf_dev_skb_free(skb);
aicwf_usb_rx_buf_put(usb_dev, usb_buf);
schedule_work(&usb_dev->rx_urb_work);
return;
}
if (urb->status != 0 || !urb->actual_length) {
aicwf_dev_skb_free(skb);
aicwf_usb_rx_buf_put(usb_dev, usb_buf);
schedule_work(&usb_dev->rx_urb_work);
return;
}
if (usb_dev->state == USB_UP_ST) {
skb_put(skb, urb->actual_length);
spin_lock_irqsave(&rx_priv->rxqlock, flags);
if (!aicwf_rxframe_enqueue(usb_dev->dev, &rx_priv->rxq, skb)) {
spin_unlock_irqrestore(&rx_priv->rxqlock, flags);
usb_err("rx_priv->rxq is over flow!!!\n");
aicwf_dev_skb_free(skb);
aicwf_usb_rx_buf_put(usb_dev, usb_buf);
return;
}
spin_unlock_irqrestore(&rx_priv->rxqlock, flags);
atomic_inc(&rx_priv->rx_cnt);
complete(&rx_priv->usbdev->bus_if->busrx_trgg);
aicwf_usb_rx_buf_put(usb_dev, usb_buf);
schedule_work(&usb_dev->rx_urb_work);
} else {
aicwf_dev_skb_free(skb);
aicwf_usb_rx_buf_put(usb_dev, usb_buf);
}
}
static int aicwf_usb_submit_rx_urb(struct aic_usb_dev *usb_dev,
struct aicwf_usb_buf *usb_buf)
{
struct sk_buff *skb;
int ret;
if (!usb_buf || !usb_dev)
return -1;
if (usb_dev->state != USB_UP_ST) {
usb_err("usb state is not up!\n");
aicwf_usb_rx_buf_put(usb_dev, usb_buf);
return -1;
}
skb = __dev_alloc_skb(AICWF_USB_MAX_PKT_SIZE, GFP_KERNEL);
if (!skb) {
aicwf_usb_rx_buf_put(usb_dev, usb_buf);
return -1;
}
usb_buf->skb = skb;
usb_fill_bulk_urb(usb_buf->urb,
usb_dev->udev,
usb_dev->bulk_in_pipe,
skb->data, skb_tailroom(skb), aicwf_usb_rx_complete, usb_buf);
usb_buf->usbdev = usb_dev;
usb_anchor_urb(usb_buf->urb, &usb_dev->rx_submitted);
ret = usb_submit_urb(usb_buf->urb, GFP_ATOMIC);
if (ret) {
usb_err("usb submit rx urb fail:%d\n", ret);
usb_unanchor_urb(usb_buf->urb);
aicwf_dev_skb_free(usb_buf->skb);
usb_buf->skb = NULL;
aicwf_usb_rx_buf_put(usb_dev, usb_buf);
msleep(100);
}
return 0;
}
static void aicwf_usb_rx_submit_all_urb(struct aic_usb_dev *usb_dev)
{
struct aicwf_usb_buf *usb_buf;
if (usb_dev->state != USB_UP_ST) {
usb_err("bus is not up=%d\n", usb_dev->state);
return;
}
while ((usb_buf = aicwf_usb_rx_buf_get(usb_dev)) != NULL) {
if (aicwf_usb_submit_rx_urb(usb_dev, usb_buf)) {
usb_err("usb rx refill fail\n");
if (usb_dev->state != USB_UP_ST)
return;
}
}
}
static void aicwf_usb_rx_prepare(struct aic_usb_dev *usb_dev)
{
aicwf_usb_rx_submit_all_urb(usb_dev);
}
static void aicwf_usb_tx_prepare(struct aic_usb_dev *usb_dev)
{
struct aicwf_usb_buf *usb_buf;
while (!list_empty(&usb_dev->tx_post_list)) {
usb_buf = aicwf_usb_tx_dequeue(usb_dev, &usb_dev->tx_post_list,
&usb_dev->tx_post_count, &usb_dev->tx_post_lock);
if (usb_buf->skb) {
dev_kfree_skb(usb_buf->skb);
usb_buf->skb = NULL;
}
aicwf_usb_tx_queue(usb_dev, &usb_dev->tx_free_list, usb_buf,
&usb_dev->tx_free_count, &usb_dev->tx_free_lock);
}
}
static void aicwf_usb_tx_process(struct aic_usb_dev *usb_dev)
{
struct aicwf_usb_buf *usb_buf;
int ret = 0;
u8 *data = NULL;
while (!list_empty(&usb_dev->tx_post_list)) {
if (usb_dev->state != USB_UP_ST) {
usb_err("usb state is not up!\n");
return;
}
usb_buf = aicwf_usb_tx_dequeue(usb_dev, &usb_dev->tx_post_list,
&usb_dev->tx_post_count, &usb_dev->tx_post_lock);
if (!usb_buf) {
usb_err("can not get usb_buf from tx_post_list!\n");
return;
}
data = usb_buf->skb->data;
ret = usb_submit_urb(usb_buf->urb, GFP_ATOMIC);
if (ret) {
usb_err("aicwf_usb_bus_tx usb_submit_urb FAILED\n");
goto fail;
}
continue;
fail:
dev_kfree_skb(usb_buf->skb);
usb_buf->skb = NULL;
aicwf_usb_tx_queue(usb_dev, &usb_dev->tx_free_list, usb_buf,
&usb_dev->tx_free_count, &usb_dev->tx_free_lock);
}
}
int usb_bustx_thread(void *data)
{
struct aicwf_bus *bus = (struct aicwf_bus *)data;
struct aic_usb_dev *usbdev = bus->bus_priv.usb;
while (1) {
if (kthread_should_stop()) {
usb_err("usb bustx thread stop\n");
break;
}
if (!wait_for_completion_interruptible(&bus->bustx_trgg)) {
if (usbdev->bus_if->state == BUS_DOWN_ST)
continue;
if (usbdev->tx_post_count > 0)
aicwf_usb_tx_process(usbdev);
}
}
return 0;
}
int usb_busrx_thread(void *data)
{
struct aicwf_rx_priv *rx_priv = (struct aicwf_rx_priv *)data;
struct aicwf_bus *bus_if = rx_priv->usbdev->bus_if;
while (1) {
if (kthread_should_stop()) {
usb_err("usb busrx thread stop\n");
break;
}
if (!wait_for_completion_interruptible(&bus_if->busrx_trgg)) {
if (bus_if->state == BUS_DOWN_ST)
continue;
aicwf_process_rxframes(rx_priv);
}
}
return 0;
}
static void aicwf_usb_send_msg_complete(struct urb *urb)
{
struct aic_usb_dev *usb_dev = (struct aic_usb_dev *) urb->context;
usb_dev->msg_finished = true;
if (waitqueue_active(&usb_dev->msg_wait))
wake_up(&usb_dev->msg_wait);
}
static int aicwf_usb_bus_txmsg(struct device *dev, u8 *buf, u32 len)
{
int ret = 0;
struct aicwf_bus *bus_if = dev_get_drvdata(dev);
struct aic_usb_dev *usb_dev = bus_if->bus_priv.usb;
if (usb_dev->state != USB_UP_ST)
return -EIO;
if (buf == NULL || len == 0 || usb_dev->msg_out_urb == NULL)
return -EINVAL;
if (test_and_set_bit(0, &usb_dev->msg_busy)) {
usb_err("In a control frame option, can't tx!\n");
return -EIO;
}
usb_dev->msg_finished = false;
usb_fill_bulk_urb(usb_dev->msg_out_urb,
usb_dev->udev,
usb_dev->bulk_out_pipe,
buf, len, (usb_complete_t) aicwf_usb_send_msg_complete, usb_dev);
usb_dev->msg_out_urb->transfer_flags |= URB_ZERO_PACKET;
ret = usb_submit_urb(usb_dev->msg_out_urb, GFP_ATOMIC);
if (ret) {
usb_err("usb_submit_urb failed %d\n", ret);
goto exit;
}
ret = wait_event_timeout(usb_dev->msg_wait,
usb_dev->msg_finished, msecs_to_jiffies(CMD_TX_TIMEOUT));
if (!ret) {
if (usb_dev->msg_out_urb)
usb_kill_urb(usb_dev->msg_out_urb);
usb_err("Txmsg wait timed out\n");
ret = -EIO;
goto exit;
}
if (usb_dev->msg_finished == false) {
usb_err("Txmsg timed out\n");
ret = -ETIMEDOUT;
goto exit;
}
exit:
clear_bit(0, &usb_dev->msg_busy);
return ret;
}
static void aicwf_usb_free_urb(struct list_head *q, spinlock_t *qlock)
{
struct aicwf_usb_buf *usb_buf, *tmp;
unsigned long flags;
spin_lock_irqsave(qlock, flags);
list_for_each_entry_safe(usb_buf, tmp, q, list) {
spin_unlock_irqrestore(qlock, flags);
if (!usb_buf->urb) {
usb_err("bad usb_buf\n");
spin_lock_irqsave(qlock, flags);
break;
}
usb_free_urb(usb_buf->urb);
list_del_init(&usb_buf->list);
spin_lock_irqsave(qlock, flags);
}
spin_unlock_irqrestore(qlock, flags);
}
static int aicwf_usb_alloc_rx_urb(struct aic_usb_dev *usb_dev)
{
int i;
for (i = 0; i < AICWF_USB_RX_URBS; i++) {
struct aicwf_usb_buf *usb_buf = &usb_dev->usb_rx_buf[i];
usb_buf->usbdev = usb_dev;
usb_buf->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!usb_buf->urb) {
usb_err("could not allocate rx data urb\n");
goto err;
}
list_add_tail(&usb_buf->list, &usb_dev->rx_free_list);
}
return 0;
err:
aicwf_usb_free_urb(&usb_dev->rx_free_list, &usb_dev->rx_free_lock);
return -ENOMEM;
}
static int aicwf_usb_alloc_tx_urb(struct aic_usb_dev *usb_dev)
{
int i;
for (i = 0; i < AICWF_USB_TX_URBS; i++) {
struct aicwf_usb_buf *usb_buf = &usb_dev->usb_tx_buf[i];
usb_buf->usbdev = usb_dev;
usb_buf->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!usb_buf->urb) {
usb_err("could not allocate tx data urb\n");
goto err;
}
list_add_tail(&usb_buf->list, &usb_dev->tx_free_list);
(usb_dev->tx_free_count)++;
}
return 0;
err:
aicwf_usb_free_urb(&usb_dev->tx_free_list, &usb_dev->tx_free_lock);
return -ENOMEM;
}
static void aicwf_usb_state_change(struct aic_usb_dev *usb_dev, int state)
{
int old_state;
if (usb_dev->state == state)
return;
old_state = usb_dev->state;
usb_dev->state = state;
if (state == USB_DOWN_ST) {
usb_dev->bus_if->state = BUS_DOWN_ST;
}
if (state == USB_UP_ST) {
usb_dev->bus_if->state = BUS_UP_ST;
}
}
static int aicwf_usb_bus_txdata(struct device *dev, struct sk_buff *skb)
{
u8 *buf;
u16 buf_len = 0;
u16 adjust_len = 0;
struct aicwf_usb_buf *usb_buf;
int ret = 0;
unsigned long flags;
struct aicwf_bus *bus_if = dev_get_drvdata(dev);
struct aic_usb_dev *usb_dev = bus_if->bus_priv.usb;
struct rwnx_txhdr *txhdr = (struct rwnx_txhdr *)skb->data;
struct rwnx_hw *rwnx_hw = usb_dev->rwnx_hw;
u8 usb_header[4];
u8 adj_buf[4] = {0};
u16 index = 0;
bool need_cfm = false;
if (usb_dev->state != USB_UP_ST) {
usb_err("usb state is not up!\n");
kmem_cache_free(rwnx_hw->sw_txhdr_cache, txhdr->sw_hdr);
dev_kfree_skb_any(skb);
return -EIO;
}
usb_buf = aicwf_usb_tx_dequeue(usb_dev, &usb_dev->tx_free_list,
&usb_dev->tx_free_count, &usb_dev->tx_free_lock);
if (!usb_buf) {
usb_err("free:%d, post:%d\n", usb_dev->tx_free_count, usb_dev->tx_post_count);
kmem_cache_free(rwnx_hw->sw_txhdr_cache, txhdr->sw_hdr);
dev_kfree_skb_any(skb);
ret = -ENOMEM;
goto flow_ctrl;
}
if (txhdr->sw_hdr->need_cfm) {
need_cfm = true;
buf = kmalloc(skb->len, GFP_KERNEL);
index += sizeof(usb_header);
memcpy(&buf[index], (u8 *)(long)&txhdr->sw_hdr->desc, sizeof(struct txdesc_api));
index += sizeof(struct txdesc_api);
memcpy(&buf[index], &skb->data[txhdr->sw_hdr->headroom], skb->len - txhdr->sw_hdr->headroom);
index += skb->len - txhdr->sw_hdr->headroom;
buf_len = index;
if (buf_len & (TX_ALIGNMENT - 1)) {
adjust_len = roundup(buf_len, TX_ALIGNMENT)-buf_len;
memcpy(&buf[buf_len], adj_buf, adjust_len);
buf_len += adjust_len;
}
usb_header[0] = ((buf_len) & 0xff);
usb_header[1] = (((buf_len) >> 8)&0x0f);
usb_header[2] = 0x01; //data
usb_header[3] = 0; //reserved
memcpy(&buf[0], usb_header, sizeof(usb_header));
usb_buf->skb = (struct sk_buff *)buf;
} else {
skb_pull(skb, txhdr->sw_hdr->headroom);
skb_push(skb, sizeof(struct txdesc_api));
memcpy(&skb->data[0], (u8 *)(long)&txhdr->sw_hdr->desc, sizeof(struct txdesc_api));
kmem_cache_free(rwnx_hw->sw_txhdr_cache, txhdr->sw_hdr);
skb_push(skb, sizeof(usb_header));
usb_header[0] = ((skb->len) & 0xff);
usb_header[1] = (((skb->len) >> 8)&0x0f);
usb_header[2] = 0x01; //data
usb_header[3] = 0; //reserved
memcpy(&skb->data[0], usb_header, sizeof(usb_header));
buf = skb->data;
buf_len = skb->len;
usb_buf->skb = skb;
}
usb_buf->usbdev = usb_dev;
if (need_cfm)
usb_buf->cfm = true;
else
usb_buf->cfm = false;
usb_fill_bulk_urb(usb_buf->urb, usb_dev->udev, usb_dev->bulk_out_pipe,
buf, buf_len, aicwf_usb_tx_complete, usb_buf);
usb_buf->urb->transfer_flags |= URB_ZERO_PACKET;
aicwf_usb_tx_queue(usb_dev, &usb_dev->tx_post_list, usb_buf,
&usb_dev->tx_post_count, &usb_dev->tx_post_lock);
complete(&bus_if->bustx_trgg);
ret = 0;
flow_ctrl:
spin_lock_irqsave(&usb_dev->tx_flow_lock, flags);
if (usb_dev->tx_free_count < AICWF_USB_TX_LOW_WATER) {
usb_dev->tbusy = true;
aicwf_usb_tx_flowctrl(usb_dev->rwnx_hw, true);
}
spin_unlock_irqrestore(&usb_dev->tx_flow_lock, flags);
return ret;
}
static int aicwf_usb_bus_start(struct device *dev)
{
struct aicwf_bus *bus_if = dev_get_drvdata(dev);
struct aic_usb_dev *usb_dev = bus_if->bus_priv.usb;
if (usb_dev->state == USB_UP_ST)
return 0;
aicwf_usb_state_change(usb_dev, USB_UP_ST);
aicwf_usb_rx_prepare(usb_dev);
aicwf_usb_tx_prepare(usb_dev);
return 0;
}
static void aicwf_usb_cancel_all_urbs(struct aic_usb_dev *usb_dev)
{
struct aicwf_usb_buf *usb_buf, *tmp;
unsigned long flags;
if (usb_dev->msg_out_urb)
usb_kill_urb(usb_dev->msg_out_urb);
spin_lock_irqsave(&usb_dev->tx_post_lock, flags);
list_for_each_entry_safe(usb_buf, tmp, &usb_dev->tx_post_list, list) {
spin_unlock_irqrestore(&usb_dev->tx_post_lock, flags);
if (!usb_buf->urb) {
usb_err("bad usb_buf\n");
spin_lock_irqsave(&usb_dev->tx_post_lock, flags);
break;
}
usb_kill_urb(usb_buf->urb);
spin_lock_irqsave(&usb_dev->tx_post_lock, flags);
}
spin_unlock_irqrestore(&usb_dev->tx_post_lock, flags);
usb_kill_anchored_urbs(&usb_dev->rx_submitted);
}
static void aicwf_usb_bus_stop(struct device *dev)
{
struct aicwf_bus *bus_if = dev_get_drvdata(dev);
struct aic_usb_dev *usb_dev = bus_if->bus_priv.usb;
usb_dbg("%s\r\n", __func__);
if (usb_dev == NULL)
return;
if (usb_dev->state == USB_DOWN_ST)
return;
aicwf_usb_state_change(usb_dev, USB_DOWN_ST);
aicwf_usb_cancel_all_urbs(usb_dev);
}
static void aicwf_usb_deinit(struct aic_usb_dev *usbdev)
{
cancel_work_sync(&usbdev->rx_urb_work);
aicwf_usb_free_urb(&usbdev->rx_free_list, &usbdev->rx_free_lock);
aicwf_usb_free_urb(&usbdev->tx_free_list, &usbdev->tx_free_lock);
usb_free_urb(usbdev->msg_out_urb);
}
static void aicwf_usb_rx_urb_work(struct work_struct *work)
{
struct aic_usb_dev *usb_dev = container_of(work, struct aic_usb_dev, rx_urb_work);
aicwf_usb_rx_submit_all_urb(usb_dev);
}
static int aicwf_usb_init(struct aic_usb_dev *usb_dev)
{
int ret = 0;
usb_dev->tbusy = false;
usb_dev->state = USB_DOWN_ST;
init_waitqueue_head(&usb_dev->msg_wait);
init_usb_anchor(&usb_dev->rx_submitted);
spin_lock_init(&usb_dev->tx_free_lock);
spin_lock_init(&usb_dev->tx_post_lock);
spin_lock_init(&usb_dev->rx_free_lock);
spin_lock_init(&usb_dev->tx_flow_lock);
INIT_LIST_HEAD(&usb_dev->rx_free_list);
INIT_LIST_HEAD(&usb_dev->tx_free_list);
INIT_LIST_HEAD(&usb_dev->tx_post_list);
usb_dev->tx_free_count = 0;
usb_dev->tx_post_count = 0;
ret = aicwf_usb_alloc_rx_urb(usb_dev);
if (ret) {
goto error;
}
ret = aicwf_usb_alloc_tx_urb(usb_dev);
if (ret) {
goto error;
}
usb_dev->msg_out_urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!usb_dev->msg_out_urb) {
usb_err("usb_alloc_urb (msg out) failed\n");
ret = ENOMEM;
goto error;
}
INIT_WORK(&usb_dev->rx_urb_work, aicwf_usb_rx_urb_work);
return ret;
error:
usb_err("failed!\n");
aicwf_usb_deinit(usb_dev);
return ret;
}
static int aicwf_parse_usb(struct aic_usb_dev *usb_dev, struct usb_interface *interface)
{
struct usb_interface_descriptor *interface_desc;
struct usb_host_interface *host_interface;
struct usb_endpoint_descriptor *endpoint;
struct usb_device *usb = usb_dev->udev;
int i, endpoints;
u8 endpoint_num;
int ret = 0;
usb_dev->bulk_in_pipe = 0;
usb_dev->bulk_out_pipe = 0;
host_interface = &interface->altsetting[0];
interface_desc = &host_interface->desc;
endpoints = interface_desc->bNumEndpoints;
/* Check device configuration */
if (usb->descriptor.bNumConfigurations != 1) {
usb_err("Number of configurations: %d not supported\n",
usb->descriptor.bNumConfigurations);
ret = -ENODEV;
goto exit;
}
/* Check deviceclass */
#ifndef CONFIG_USB_BT
if (usb->descriptor.bDeviceClass != 0x00) {
usb_err("DeviceClass %d not supported\n",
usb->descriptor.bDeviceClass);
ret = -ENODEV;
goto exit;
}
#endif
/* Check interface number */
#ifdef CONFIG_USB_BT
if (usb->actconfig->desc.bNumInterfaces != 3) {
#else
if (usb->actconfig->desc.bNumInterfaces != 1) {
#endif
usb_err("Number of interfaces: %d not supported\n",
usb->actconfig->desc.bNumInterfaces);
ret = -ENODEV;
goto exit;
}
if ((interface_desc->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
(interface_desc->bInterfaceSubClass != 0xff) ||
(interface_desc->bInterfaceProtocol != 0xff)) {
usb_err("non WLAN interface %d: 0x%x:0x%x:0x%x\n",
interface_desc->bInterfaceNumber, interface_desc->bInterfaceClass,
interface_desc->bInterfaceSubClass, interface_desc->bInterfaceProtocol);
ret = -ENODEV;
goto exit;
}
for (i = 0; i < endpoints; i++) {
endpoint = &host_interface->endpoint[i].desc;
endpoint_num = usb_endpoint_num(endpoint);
if (usb_endpoint_dir_in(endpoint) &&
usb_endpoint_xfer_bulk(endpoint)) {
if (!usb_dev->bulk_in_pipe) {
usb_dev->bulk_in_pipe = usb_rcvbulkpipe(usb, endpoint_num);
}
}
if (usb_endpoint_dir_out(endpoint) &&
usb_endpoint_xfer_bulk(endpoint)) {
if (!usb_dev->bulk_out_pipe) {
usb_dev->bulk_out_pipe = usb_sndbulkpipe(usb, endpoint_num);
}
}
}
if (usb_dev->bulk_in_pipe == 0) {
usb_err("No RX (in) Bulk EP found\n");
ret = -ENODEV;
goto exit;
}
if (usb_dev->bulk_out_pipe == 0) {
usb_err("No TX (out) Bulk EP found\n");
ret = -ENODEV;
goto exit;
}
if (usb->speed == USB_SPEED_HIGH)
printk("Aic high speed USB device detected\n");
else
printk("Aic full speed USB device detected\n");
exit:
return ret;
}
static struct aicwf_bus_ops aicwf_usb_bus_ops = {
.start = aicwf_usb_bus_start,
.stop = aicwf_usb_bus_stop,
.txdata = aicwf_usb_bus_txdata,
.txmsg = aicwf_usb_bus_txmsg,
};
static int aicwf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
int ret = 0;
struct usb_device *usb = interface_to_usbdev(intf);
struct aicwf_bus *bus_if ;
struct device *dev = NULL;
struct aicwf_rx_priv *rx_priv = NULL;
struct aic_usb_dev *usb_dev = NULL;
usb_dev = kzalloc(sizeof(struct aic_usb_dev), GFP_ATOMIC);
if (!usb_dev) {
return -ENOMEM;
}
usb_dev->udev = usb;
usb_dev->dev = &usb->dev;
usb_set_intfdata(intf, usb_dev);
ret = aicwf_parse_usb(usb_dev, intf);
if (ret) {
usb_err("aicwf_parse_usb err %d\n", ret);
goto out_free;
}
ret = aicwf_usb_init(usb_dev);
if (ret) {
usb_err("aicwf_usb_init err %d\n", ret);
goto out_free;
}
bus_if = kzalloc(sizeof(struct aicwf_bus), GFP_ATOMIC);
if (!bus_if) {
ret = -ENOMEM;
goto out_free_usb;
}
dev = usb_dev->dev;
bus_if->dev = dev;
usb_dev->bus_if = bus_if;
bus_if->bus_priv.usb = usb_dev;
dev_set_drvdata(dev, bus_if);
bus_if->ops = &aicwf_usb_bus_ops;
rx_priv = aicwf_rx_init(usb_dev);
if (!rx_priv) {
txrx_err("rx init failed\n");
ret = -1;
goto out_free_bus;
}
usb_dev->rx_priv = rx_priv;
ret = aicwf_bus_init(0, dev);
if (ret < 0) {
usb_err("aicwf_bus_init err %d\n", ret);
goto out_free_bus;
}
ret = aicwf_bus_start(bus_if);
if (ret < 0) {
usb_err("aicwf_bus_start err %d\n", ret);
goto out_free_bus;
}
aicwf_rwnx_usb_platform_init(usb_dev);
aicwf_hostif_ready();
return 0;
out_free_bus:
aicwf_bus_deinit(dev);
kfree(bus_if);
out_free_usb:
aicwf_usb_deinit(usb_dev);
out_free:
usb_err("failed with errno %d\n", ret);
kfree(usb_dev);
usb_set_intfdata(intf, NULL);
return ret;
}
static void aicwf_usb_disconnect(struct usb_interface *intf)
{
struct aic_usb_dev *usb_dev =
(struct aic_usb_dev *) usb_get_intfdata(intf);
if (!usb_dev)
return;
aicwf_bus_deinit(usb_dev->dev);
aicwf_usb_deinit(usb_dev);
rwnx_cmd_mgr_deinit(&usb_dev->cmd_mgr);
if (usb_dev->rx_priv)
aicwf_rx_deinit(usb_dev->rx_priv);
kfree(usb_dev->bus_if);
kfree(usb_dev);
}
static int aicwf_usb_suspend(struct usb_interface *intf, pm_message_t state)
{
struct aic_usb_dev *usb_dev =
(struct aic_usb_dev *) usb_get_intfdata(intf);
aicwf_usb_state_change(usb_dev, USB_SLEEP_ST);
aicwf_bus_stop(usb_dev->bus_if);
return 0;
}
static int aicwf_usb_resume(struct usb_interface *intf)
{
struct aic_usb_dev *usb_dev =
(struct aic_usb_dev *) usb_get_intfdata(intf);
if (usb_dev->state == USB_UP_ST)
return 0;
aicwf_bus_start(usb_dev->bus_if);
return 0;
}
static int aicwf_usb_reset_resume(struct usb_interface *intf)
{
return aicwf_usb_resume(intf);
}
static struct usb_device_id aicwf_usb_id_table[] = {
#ifndef CONFIG_USB_BT
{USB_DEVICE(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC)},
#else
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC, 0xff, 0xff, 0xff)},
#endif
{}
};
MODULE_DEVICE_TABLE(usb, aicwf_usb_id_table);
static struct usb_driver aicwf_usbdrvr = {
.name = KBUILD_MODNAME,
.probe = aicwf_usb_probe,
.disconnect = aicwf_usb_disconnect,
.id_table = aicwf_usb_id_table,
.suspend = aicwf_usb_suspend,
.resume = aicwf_usb_resume,
.reset_resume = aicwf_usb_reset_resume,
.supports_autosuspend = 1,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
.disable_hub_initiated_lpm = 1,
#endif
};
void aicwf_usb_register(void)
{
if (usb_register(&aicwf_usbdrvr) < 0) {
usb_err("usb_register failed\n");
}
}
void aicwf_usb_exit(void)
{
if (g_rwnx_plat && g_rwnx_plat->enabled)
rwnx_platform_deinit(g_rwnx_plat->usbdev->rwnx_hw);
usb_deregister(&aicwf_usbdrvr);
kfree(g_rwnx_plat);
}

View File

@ -0,0 +1,99 @@
/**
* aicwf_usb.h
*
* USB function declarations
*
* Copyright (C) AICSemi 2018-2020
*/
#ifndef _AICWF_USB_H_
#define _AICWF_USB_H_
#include <linux/usb.h>
#include "rwnx_cmds.h"
#ifdef AICWF_USB_SUPPORT
/* USB Device ID */
#define USB_VENDOR_ID_AIC 0xA69C
#ifndef CONFIG_USB_BT
#define USB_PRODUCT_ID_AIC 0x8800
#else
#define USB_PRODUCT_ID_AIC 0x8801
#endif
#define AICWF_USB_RX_URBS (200)
#define AICWF_USB_TX_URBS (100)
#define AICWF_USB_TX_LOW_WATER (AICWF_USB_TX_URBS/4)
#define AICWF_USB_TX_HIGH_WATER (AICWF_USB_TX_LOW_WATER*3)
#define AICWF_USB_MAX_PKT_SIZE (2048)
typedef enum {
USB_TYPE_DATA = 0X00,
USB_TYPE_CFG = 0X10,
USB_TYPE_CFG_CMD_RSP = 0X11,
USB_TYPE_CFG_DATA_CFM = 0X12
} usb_type;
enum aicwf_usb_state {
USB_DOWN_ST,
USB_UP_ST,
USB_SLEEP_ST
};
struct aicwf_usb_buf {
struct list_head list;
struct aic_usb_dev *usbdev;
struct urb *urb;
struct sk_buff *skb;
bool cfm;
};
struct aic_usb_dev {
struct rwnx_hw *rwnx_hw;
struct aicwf_bus *bus_if;
struct usb_device *udev;
struct device *dev;
struct aicwf_rx_priv *rx_priv;
enum aicwf_usb_state state;
struct rwnx_cmd_mgr cmd_mgr;
struct usb_anchor rx_submitted;
struct work_struct rx_urb_work;
spinlock_t rx_free_lock;
spinlock_t tx_free_lock;
spinlock_t tx_post_lock;
spinlock_t tx_flow_lock;
struct list_head rx_free_list;
struct list_head tx_free_list;
struct list_head tx_post_list;
uint bulk_in_pipe;
uint bulk_out_pipe;
int tx_free_count;
int tx_post_count;
struct aicwf_usb_buf usb_tx_buf[AICWF_USB_TX_URBS];
struct aicwf_usb_buf usb_rx_buf[AICWF_USB_RX_URBS];
int msg_finished;
wait_queue_head_t msg_wait;
ulong msg_busy;
struct urb *msg_out_urb;
bool tbusy;
};
extern void aicwf_usb_exit(void);
extern void aicwf_usb_register(void);
extern void aicwf_usb_tx_flowctrl(struct rwnx_hw *rwnx_hw, bool state);
int usb_bustx_thread(void *data);
int usb_busrx_thread(void *data);
extern void aicwf_hostif_ready(void);
#endif /* AICWF_USB_SUPPORT */
#endif /* _AICWF_USB_H_ */

View File

@ -0,0 +1,353 @@
/**
******************************************************************************
*
* @file hal_desc.h
*
* @brief File containing the definition of HW descriptors.
*
* Contains the definition and structures used by HW
*
* Copyright (C) RivieraWaves 2011-2019
*
******************************************************************************
*/
#ifndef _HAL_DESC_H_
#define _HAL_DESC_H_
#include "lmac_types.h"
/* Rate and policy table */
#define N_CCK 8
#define N_OFDM 8
#define N_HT (8 * 2 * 2 * 4)
#define N_VHT (10 * 4 * 2 * 8)
#define N_HE_SU (12 * 4 * 3 * 8)
#define N_HE_MU (12 * 6 * 3 * 8)
#define N_HE_ER (3 * 3 + 3) //RU242 + RU106
/* conversion table from NL80211 to MACHW enum */
extern const int chnl2bw[];
/* conversion table from MACHW to NL80211 enum */
extern const int bw2chnl[];
/* Values for formatModTx */
#define FORMATMOD_NON_HT 0
#define FORMATMOD_NON_HT_DUP_OFDM 1
#define FORMATMOD_HT_MF 2
#define FORMATMOD_HT_GF 3
#define FORMATMOD_VHT 4
#define FORMATMOD_HE_SU 5
#define FORMATMOD_HE_MU 6
#define FORMATMOD_HE_ER 7
#define FORMATMOD_HE_TB 8
/* Values for navProtFrmEx */
#define NAV_PROT_NO_PROT_BIT 0
#define NAV_PROT_SELF_CTS_BIT 1
#define NAV_PROT_RTS_CTS_BIT 2
#define NAV_PROT_RTS_CTS_WITH_QAP_BIT 3
#define NAV_PROT_STBC_BIT 4
/* THD MACCTRLINFO2 fields, used in struct umacdesc umac.flags */
/// WhichDescriptor definition - contains aMPDU bit and position value
/// Offset of WhichDescriptor field in the MAC CONTROL INFO 2 word
#define WHICHDESC_OFT 19
/// Mask of the WhichDescriptor field
#define WHICHDESC_MSK (0x07 << WHICHDESC_OFT)
/// Only 1 THD possible, describing an unfragmented MSDU
#define WHICHDESC_UNFRAGMENTED_MSDU (0x00 << WHICHDESC_OFT)
/// THD describing the first MPDU of a fragmented MSDU
#define WHICHDESC_FRAGMENTED_MSDU_FIRST (0x01 << WHICHDESC_OFT)
/// THD describing intermediate MPDUs of a fragmented MSDU
#define WHICHDESC_FRAGMENTED_MSDU_INT (0x02 << WHICHDESC_OFT)
/// THD describing the last MPDU of a fragmented MSDU
#define WHICHDESC_FRAGMENTED_MSDU_LAST (0x03 << WHICHDESC_OFT)
/// THD for extra descriptor starting an AMPDU
#define WHICHDESC_AMPDU_EXTRA (0x04 << WHICHDESC_OFT)
/// THD describing the first MPDU of an A-MPDU
#define WHICHDESC_AMPDU_FIRST (0x05 << WHICHDESC_OFT)
/// THD describing intermediate MPDUs of an A-MPDU
#define WHICHDESC_AMPDU_INT (0x06 << WHICHDESC_OFT)
/// THD describing the last MPDU of an A-MPDU
#define WHICHDESC_AMPDU_LAST (0x07 << WHICHDESC_OFT)
/// aMPDU bit offset
#define AMPDU_OFT 21
/// aMPDU bit
#define AMPDU_BIT CO_BIT(AMPDU_OFT)
union rwnx_mcs_index {
struct {
u32 mcs : 3;
u32 nss : 2;
} ht;
struct {
u32 mcs : 4;
u32 nss : 3;
} vht;
struct {
u32 mcs : 4;
u32 nss : 3;
} he;
u32 legacy : 7;
};
/* c.f RW-WLAN-nX-MAC-HW-UM */
union rwnx_rate_ctrl_info {
struct {
u32 mcsIndexTx : 7;
u32 bwTx : 2;
u32 giAndPreTypeTx : 2;
u32 formatModTx : 3;
u32 navProtFrmEx : 3;
u32 mcsIndexProtTx : 7;
u32 bwProtTx : 2;
u32 formatModProtTx : 3;
u32 nRetry : 3;
};
u32 value;
};
/* c.f RW-WLAN-nX-MAC-HW-UM */
struct rwnx_power_ctrl_info {
u32 txPwrLevelPT : 8;
u32 txPwrLevelProtPT : 8;
u32 reserved :16;
};
/* c.f RW-WLAN-nX-MAC-HW-UM */
union rwnx_pol_phy_ctrl_info_1 {
struct {
u32 rsvd1 : 3;
u32 bfFrmEx : 1;
u32 numExtnSS : 2;
u32 fecCoding : 1;
u32 stbc : 2;
u32 rsvd2 : 5;
u32 nTx : 3;
u32 nTxProt : 3;
};
u32 value;
};
/* c.f RW-WLAN-nX-MAC-HW-UM */
union rwnx_pol_phy_ctrl_info_2 {
struct {
u32 antennaSet : 8;
u32 smmIndex : 8;
u32 beamFormed : 1;
};
u32 value;
};
/* c.f RW-WLAN-nX-MAC-HW-UM */
union rwnx_pol_mac_ctrl_info_1 {
struct {
u32 keySRamIndex : 10;
u32 keySRamIndexRA : 10;
};
u32 value;
};
/* c.f RW-WLAN-nX-MAC-HW-UM */
union rwnx_pol_mac_ctrl_info_2 {
struct {
u32 longRetryLimit : 8;
u32 shortRetryLimit : 8;
u32 rtsThreshold : 12;
};
u32 value;
};
#define POLICY_TABLE_PATTERN 0xBADCAB1E
struct tx_policy_tbl {
/* Unique Pattern at the start of Policy Table */
u32 upatterntx;
/* PHY Control 1 Information used by MAC HW */
union rwnx_pol_phy_ctrl_info_1 phyctrlinfo_1;
/* PHY Control 2 Information used by MAC HW */
union rwnx_pol_phy_ctrl_info_2 phyctrlinfo_2;
/* MAC Control 1 Information used by MAC HW */
union rwnx_pol_mac_ctrl_info_1 macctrlinfo_1;
/* MAC Control 2 Information used by MAC HW */
union rwnx_pol_mac_ctrl_info_2 macctrlinfo_2;
union rwnx_rate_ctrl_info ratectrlinfos[NX_TX_MAX_RATES];
struct rwnx_power_ctrl_info powerctrlinfos[NX_TX_MAX_RATES];
};
#ifdef CONFIG_RWNX_FULLMAC
/**
* struct rwnx_hw_txstatus - Bitfield of confirmation status
*
* @tx_done: packet has been processed by the firmware.
* @retry_required: packet has been transmitted but not acknoledged.
* Driver must repush it.
* @sw_retry_required: packet has not been transmitted (FW wasn't able to push
* it when it received it: not active channel ...). Driver must repush it.
* @acknowledged: packet has been acknowledged by peer
*/
union rwnx_hw_txstatus {
struct {
u32 tx_done : 1;
u32 retry_required : 1;
u32 sw_retry_required : 1;
u32 acknowledged : 1;
u32 reserved :28;
};
u32 value;
};
/**
* struct tx_cfm_tag - Structure indicating the status and other
* information about the transmission
*
* @pn: PN that was used for the transmission
* @sn: Sequence number of the packet
* @timestamp: Timestamp of first transmission of this MPDU
* @credits: Number of credits to be reallocated for the txq that push this
* buffer (can be 0 or 1)
* @ampdu_size: Size of the ampdu in which the frame has been transmitted if
* this was the last frame of the a-mpdu, and 0 if the frame is not the last
* frame on a a-mdpu.
* 1 means that the frame has been transmitted as a singleton.
* @amsdu_size: Size, in bytes, allowed to create a-msdu.
* @status: transmission status
*/
struct tx_cfm_tag {
/*
u16_l pn[4];
u16_l sn;
u16_l timestamp;
*/
s8_l credits;
u8_l ampdu_size;
#ifdef CONFIG_RWNX_SPLIT_TX_BUF
u16_l amsdu_size;
#endif
union rwnx_hw_txstatus status;
u32_l hostid;
};
/**
* struct rwnx_hw_txhdr - Hardware part of tx header
*
* @cfm: Information updated by fw/hardware after sending a frame
*/
struct rwnx_hw_txhdr {
struct tx_cfm_tag cfm;
};
#endif /* CONFIG_RWNX_FULLMAC */
/* Modem */
#define MDM_PHY_CONFIG_TRIDENT 0
#define MDM_PHY_CONFIG_ELMA 1
#define MDM_PHY_CONFIG_KARST 2
// MODEM features (from reg_mdm_stat.h)
/// MUMIMOTX field bit
#define MDM_MUMIMOTX_BIT ((u32)0x80000000)
/// MUMIMOTX field position
#define MDM_MUMIMOTX_POS 31
/// MUMIMORX field bit
#define MDM_MUMIMORX_BIT ((u32)0x40000000)
/// MUMIMORX field position
#define MDM_MUMIMORX_POS 30
/// BFMER field bit
#define MDM_BFMER_BIT ((u32)0x20000000)
/// BFMER field position
#define MDM_BFMER_POS 29
/// BFMEE field bit
#define MDM_BFMEE_BIT ((u32)0x10000000)
/// BFMEE field position
#define MDM_BFMEE_POS 28
/// LDPCDEC field bit
#define MDM_LDPCDEC_BIT ((u32)0x08000000)
/// LDPCDEC field position
#define MDM_LDPCDEC_POS 27
/// LDPCENC field bit
#define MDM_LDPCENC_BIT ((u32)0x04000000)
/// LDPCENC field position
#define MDM_LDPCENC_POS 26
/// CHBW field mask
#define MDM_CHBW_MASK ((u32)0x03000000)
/// CHBW field LSB position
#define MDM_CHBW_LSB 24
/// CHBW field width
#define MDM_CHBW_WIDTH ((u32)0x00000002)
/// DSSSCCK field bit
#define MDM_DSSSCCK_BIT ((u32)0x00800000)
/// DSSSCCK field position
#define MDM_DSSSCCK_POS 23
/// VHT field bit
#define MDM_VHT_BIT ((u32)0x00400000)
/// VHT field position
#define MDM_VHT_POS 22
/// HE field bit
#define MDM_HE_BIT ((u32)0x00200000)
/// HE field position
#define MDM_HE_POS 21
/// ESS field bit
#define MDM_ESS_BIT ((u32)0x00100000)
/// ESS field position
#define MDM_ESS_POS 20
/// RFMODE field mask
#define MDM_RFMODE_MASK ((u32)0x000F0000)
/// RFMODE field LSB position
#define MDM_RFMODE_LSB 16
/// RFMODE field width
#define MDM_RFMODE_WIDTH ((u32)0x00000004)
/// NSTS field mask
#define MDM_NSTS_MASK ((u32)0x0000F000)
/// NSTS field LSB position
#define MDM_NSTS_LSB 12
/// NSTS field width
#define MDM_NSTS_WIDTH ((u32)0x00000004)
/// NSS field mask
#define MDM_NSS_MASK ((u32)0x00000F00)
/// NSS field LSB position
#define MDM_NSS_LSB 8
/// NSS field width
#define MDM_NSS_WIDTH ((u32)0x00000004)
/// NTX field mask
#define MDM_NTX_MASK ((u32)0x000000F0)
/// NTX field LSB position
#define MDM_NTX_LSB 4
/// NTX field width
#define MDM_NTX_WIDTH ((u32)0x00000004)
/// NRX field mask
#define MDM_NRX_MASK ((u32)0x0000000F)
/// NRX field LSB position
#define MDM_NRX_LSB 0
/// NRX field width
#define MDM_NRX_WIDTH ((u32)0x00000004)
#define __MDM_PHYCFG_FROM_VERS(v) (((v) & MDM_RFMODE_MASK) >> MDM_RFMODE_LSB)
#define RIU_FCU_PRESENT_MASK ((u32)0xFF000000)
#define RIU_FCU_PRESENT_LSB 24
#define __RIU_FCU_PRESENT(v) (((v) & RIU_FCU_PRESENT_MASK) >> RIU_FCU_PRESENT_LSB == 5)
/// AGC load version field mask
#define RIU_AGC_LOAD_MASK ((u32)0x00C00000)
/// AGC load version field LSB position
#define RIU_AGC_LOAD_LSB 22
#define __RIU_AGCLOAD_FROM_VERS(v) (((v) & RIU_AGC_LOAD_MASK) >> RIU_AGC_LOAD_LSB)
#define __FPGA_TYPE(v) (((v) & 0xFFFF0000) >> 16)
#define __MDM_MAJOR_VERSION(v) (((v) & 0xFF000000) >> 24)
#define __MDM_MINOR_VERSION(v) (((v) & 0x00FF0000) >> 16)
#define __MDM_VERSION(v) ((__MDM_MAJOR_VERSION(v) + 2) * 10 + __MDM_MINOR_VERSION(v))
#endif // _HAL_DESC_H_

View File

@ -0,0 +1,25 @@
/**
****************************************************************************************
*
* @file ipc_compat.h
*
* Copyright (C) RivieraWaves 2011-2019
*
****************************************************************************************
*/
#ifndef _IPC_H_
#define _IPC_H_
#define __INLINE inline
#define __ALIGN4 __aligned(4)
#define ASSERT_ERR(condition) \
do { \
if (unlikely(!(condition))) { \
printk(KERN_ERR "%s:%d:ASSERT_ERR(" #condition ")\n", __FILE__, __LINE__); \
} \
} while (0)
#endif /* _IPC_H_ */

View File

@ -0,0 +1,52 @@
/**
******************************************************************************
*
* @file ipc_host.c
*
* @brief IPC module.
*
* Copyright (C) RivieraWaves 2011-2019
*
******************************************************************************
*/
/*
* INCLUDE FILES
******************************************************************************
*/
#ifndef __KERNEL__
#include <stdio.h>
#else
#include <linux/spinlock.h>
#include "rwnx_defs.h"
#include "rwnx_prof.h"
#endif
#include "ipc_host.h"
/*
* TYPES DEFINITION
******************************************************************************
*/
const int nx_txdesc_cnt[] = {
NX_TXDESC_CNT0,
NX_TXDESC_CNT1,
NX_TXDESC_CNT2,
NX_TXDESC_CNT3,
#if NX_TXQ_CNT == 5
NX_TXDESC_CNT4,
#endif
};
const int nx_txuser_cnt[] = {
CONFIG_USER_MAX,
CONFIG_USER_MAX,
CONFIG_USER_MAX,
CONFIG_USER_MAX,
#if NX_TXQ_CNT == 5
1,
#endif
};

View File

@ -0,0 +1,168 @@
/**
******************************************************************************
*
* @file ipc_host.h
*
* @brief IPC module.
*
* Copyright (C) RivieraWaves 2011-2019
*
******************************************************************************
*/
#ifndef _IPC_HOST_H_
#define _IPC_HOST_H_
/*
* INCLUDE FILES
******************************************************************************
*/
#include "ipc_shared.h"
#ifndef __KERNEL__
#include "arch.h"
#else
#include "ipc_compat.h"
#endif
/**
******************************************************************************
* @brief This structure is used to initialize the MAC SW
*
* The WLAN device driver provides functions call-back with this structure
******************************************************************************
*/
struct ipc_host_cb_tag {
/// WLAN driver call-back function: send_data_cfm
int (*send_data_cfm)(void *pthis, void *host_id);
/// WLAN driver call-back function: recv_data_ind
uint8_t (*recv_data_ind)(void *pthis, void *host_id);
/// WLAN driver call-back function: recv_radar_ind
uint8_t (*recv_radar_ind)(void *pthis, void *host_id);
/// WLAN driver call-back function: recv_unsup_rx_vec_ind
uint8_t (*recv_unsup_rx_vec_ind)(void *pthis, void *host_id);
/// WLAN driver call-back function: recv_msg_ind
uint8_t (*recv_msg_ind)(void *pthis, void *host_id);
/// WLAN driver call-back function: recv_msgack_ind
uint8_t (*recv_msgack_ind)(void *pthis, void *host_id);
/// WLAN driver call-back function: recv_dbg_ind
uint8_t (*recv_dbg_ind)(void *pthis, void *host_id);
/// WLAN driver call-back function: prim_tbtt_ind
void (*prim_tbtt_ind)(void *pthis);
/// WLAN driver call-back function: sec_tbtt_ind
void (*sec_tbtt_ind)(void *pthis);
};
/*
* Struct used to store information about host buffers (DMA Address and local pointer)
*/
struct ipc_hostbuf {
void *hostid; ///< ptr to hostbuf client (ipc_host client) structure
uint32_t dma_addr; ///< ptr to real hostbuf dma address
};
/// Definition of the IPC Host environment structure.
struct ipc_host_env_tag {
/// Structure containing the callback pointers
struct ipc_host_cb_tag cb;
/// Pointer to the shared environment
struct ipc_shared_env_tag *shared;
#ifdef CONFIG_RWNX_FULLMAC
// Array used to store the descriptor addresses
struct ipc_hostbuf ipc_host_rxdesc_array[IPC_RXDESC_CNT];
// Index of the host RX descriptor array (ipc_shared environment)
uint8_t ipc_host_rxdesc_idx;
/// Store the number of RX Descriptors
uint8_t rxdesc_nb;
#endif //(CONFIG_RWNX_FULLMAC)
/// Fields for Data Rx handling
// Index used for ipc_host_rxbuf_array to point to current buffer
uint8_t ipc_host_rxbuf_idx;
// Store the number of Rx Data buffers
uint32_t rx_bufnb;
// Store the size of the Rx Data buffers
uint32_t rx_bufsz;
/// Fields for Radar events handling
// Global array used to store the hostid and hostbuf addresses
struct ipc_hostbuf ipc_host_radarbuf_array[IPC_RADARBUF_CNT];
// Index used for ipc_host_rxbuf_array to point to current buffer
uint8_t ipc_host_radarbuf_idx;
// Store the number of radar event buffers
uint32_t radar_bufnb;
// Store the size of the radar event buffers
uint32_t radar_bufsz;
///Fields for Unsupported frame handling
// Global array used to store the hostid and hostbuf addresses
struct ipc_hostbuf ipc_host_unsuprxvecbuf_array[IPC_UNSUPRXVECBUF_CNT];
// Index used for ipc_host_unsuprxvecbuf_array to point to current buffer
uint8_t ipc_host_unsuprxvecbuf_idx;
// Store the number of unsupported rx vector buffers
uint32_t unsuprxvec_bufnb;
// Store the size of unsupported rx vector buffers
uint32_t unsuprxvec_bufsz;
// Index used that points to the first free TX desc
uint32_t txdesc_free_idx[IPC_TXQUEUE_CNT][CONFIG_USER_MAX];
// Index used that points to the first used TX desc
uint32_t txdesc_used_idx[IPC_TXQUEUE_CNT][CONFIG_USER_MAX];
// Array storing the currently pushed host ids for the BK queue
void *tx_host_id0[CONFIG_USER_MAX][NX_TXDESC_CNT0];
// Array storing the currently pushed host ids for the BE queue
void *tx_host_id1[CONFIG_USER_MAX][NX_TXDESC_CNT1];
// Array storing the currently pushed host ids for the VI queue
void *tx_host_id2[CONFIG_USER_MAX][NX_TXDESC_CNT2];
// Array storing the currently pushed host ids for the VO queue
void *tx_host_id3[CONFIG_USER_MAX][NX_TXDESC_CNT3];
#if NX_TXQ_CNT == 5
// Array storing the currently pushed host ids for the BCN queue
void *tx_host_id4[1][NX_TXDESC_CNT4];
#endif
// Pointer to the different host ids arrays, per IPC queue
void **tx_host_id[IPC_TXQUEUE_CNT][CONFIG_USER_MAX];
// Pointer to the different TX descriptor arrays, per IPC queue
volatile struct txdesc_host *txdesc[IPC_TXQUEUE_CNT][CONFIG_USER_MAX];
/// Fields for Emb->App MSGs handling
// Global array used to store the hostid and hostbuf addresses for msg/ind
struct ipc_hostbuf ipc_host_msgbuf_array[IPC_MSGE2A_BUF_CNT];
// Index of the MSG E2A buffers array to point to current buffer
uint8_t ipc_host_msge2a_idx;
// Store the number of E2A MSG buffers
uint32_t ipc_e2amsg_bufnb;
// Store the size of the E2A MSG buffers
uint32_t ipc_e2amsg_bufsz;
/// E2A ACKs of A2E MSGs
uint8_t msga2e_cnt;
void *msga2e_hostid;
/// Fields for Debug MSGs handling
// Global array used to store the hostid and hostbuf addresses for Debug messages
struct ipc_hostbuf ipc_host_dbgbuf_array[IPC_DBGBUF_CNT];
// Index of the Debug messages buffers array to point to current buffer
uint8_t ipc_host_dbg_idx;
// Store the number of Debug messages buffers
uint32_t ipc_dbg_bufnb;
// Store the size of the Debug messages buffers
uint32_t ipc_dbg_bufsz;
/// Pointer to the attached object (used in callbacks and register accesses)
void *pthis;
};
extern const int nx_txdesc_cnt[];
extern const int nx_txuser_cnt[];
#endif // _IPC_HOST_H_

View File

@ -0,0 +1,785 @@
/**
****************************************************************************************
*
* @file ipc_shared.h
*
* @brief Shared data between both IPC modules.
*
* Copyright (C) RivieraWaves 2011-2019
*
****************************************************************************************
*/
#ifndef _IPC_SHARED_H_
#define _IPC_SHARED_H_
/*
* INCLUDE FILES
****************************************************************************************
*/
#include "ipc_compat.h"
#include "lmac_mac.h"
/*
* DEFINES AND MACROS
****************************************************************************************
*/
#define CO_BIT(pos) (1U<<(pos))
#define IPC_TXQUEUE_CNT NX_TXQ_CNT
#define NX_TXDESC_CNT0 8
#define NX_TXDESC_CNT1 64
#define NX_TXDESC_CNT2 64
#define NX_TXDESC_CNT3 32
#if NX_TXQ_CNT == 5
#define NX_TXDESC_CNT4 8
#endif
/*
* Number of Host buffers available for Data Rx handling (through DMA)
*/
#define IPC_RXBUF_CNT 128
/*
* Number of shared descriptors available for Data RX handling
*/
#define IPC_RXDESC_CNT 128
/*
* Number of Host buffers available for Radar events handling (through DMA)
*/
#define IPC_RADARBUF_CNT 16
/*
* Number of Host buffers available for unsupported Rx vectors handling (through DMA)
*/
#define IPC_UNSUPRXVECBUF_CNT 8
/*
* Size of RxVector
*/
#define IPC_RXVEC_SIZE 16
/*
* Number of Host buffers available for Emb->App MSGs sending (through DMA)
*/
#ifdef CONFIG_RWNX_FULLMAC
#define IPC_MSGE2A_BUF_CNT 64
#endif
/*
* Number of Host buffers available for Debug Messages sending (through DMA)
*/
#define IPC_DBGBUF_CNT 32
/*
* Length used in MSGs structures
*/
#define IPC_A2E_MSG_BUF_SIZE 127 // size in 4-byte words
#ifdef CONFIG_RWNX_FULLMAC
#define IPC_E2A_MSG_SIZE_BASE 256 // size in 4-byte words
#endif
#ifdef CONFIG_RWNX_TL4
#define IPC_E2A_MSG_PARAM_SIZE (IPC_E2A_MSG_SIZE_BASE + (IPC_E2A_MSG_SIZE_BASE / 2))
#else
#define IPC_E2A_MSG_PARAM_SIZE IPC_E2A_MSG_SIZE_BASE
#endif
/*
* Debug messages buffers size (in bytes)
*/
#define IPC_DBG_PARAM_SIZE 256
/*
* Define used for Rx hostbuf validity.
* This value should appear only when hostbuf was used for a Reception.
*/
#define RX_DMA_OVER_PATTERN 0xAAAAAA00
/*
* Define used for MSG buffers validity.
* This value will be written only when a MSG buffer is used for sending from Emb to App.
*/
#define IPC_MSGE2A_VALID_PATTERN 0xADDEDE2A
/*
* Define used for Debug messages buffers validity.
* This value will be written only when a DBG buffer is used for sending from Emb to App.
*/
#define IPC_DBG_VALID_PATTERN 0x000CACA0
/*
* Length of the receive vectors, in bytes
*/
#define DMA_HDR_PHYVECT_LEN 36
/*
* Maximum number of payload addresses and lengths present in the descriptor
*/
#ifdef CONFIG_RWNX_SPLIT_TX_BUF
#define NX_TX_PAYLOAD_MAX 6
#else
#define NX_TX_PAYLOAD_MAX 1
#endif
/*
* Message struct/ID API version
*/
#define MSG_API_VER 33
/*
****************************************************************************************
*/
// c.f LMAC/src/tx/tx_swdesc.h
/// Descriptor filled by the Host
struct hostdesc {
/// Pointer to packet payload
//u32_l packet_addr;
/// Size of the payload
u16_l packet_len;
u16_l flags_ext;
u32_l hostid;
#ifdef CONFIG_RWNX_FULLMAC
/// Address of the status descriptor in host memory (used for confirmation upload)
//u32_l status_desc_addr;
/// Destination Address
struct mac_addr eth_dest_addr;
/// Source Address
struct mac_addr eth_src_addr;
/// Ethernet Type
u16_l ethertype;
#else /* ! CONFIG_RWNX_FULLMAC */
#ifdef CONFIG_RWNX_AGG_TX
///Sequence Number for AMPDU MPDUs - for quick check if it's allowed within window
u16_l sn;
#endif /* CONFIG_RWNX_AGG_TX */
/// Padding between the buffer control structure and the MPDU in host memory
u8_l padding;
#endif /* CONFIG_RWNX_FULLMAC */
u8_l ac;
/// Packet TID (0xFF if not a QoS frame)
u8_l tid;
/// Interface Id
u8_l vif_idx;
/// Station Id (0xFF if station is unknown)
u8_l staid;
#ifdef CONFIG_RWNX_MUMIMO_TX
/// MU-MIMO information (GroupId and User Position in the group) - The GroupId
/// is located on bits 0-5 and the User Position on bits 6-7. The GroupId value is set
/// to 63 if MU-MIMO shall not be used
u8_l mumimo_info;
#endif /* CONFIG_RWNX_MUMIMO_TX */
#ifdef CONFIG_RWNX_FULLMAC
/// TX flags
u16_l flags;
#endif /* CONFIG_RWNX_FULLMAC */
};
/// Descriptor filled by the UMAC
struct umacdesc {
#ifdef CONFIG_RWNX_AGG_TX
///First Sequence Number of the BlockAck window
u16_l sn_win;
/// Flags from UMAC (match tx_hd.macctrlinfo2 format)
u32_l flags;
/// PHY related flags field - rate, GI type, BW type - filled by driver
u32_l phy_flags;
#endif //(CONFIG_RWNX_AGG_TX)
};
struct txdesc_api {
/// Information provided by Host
struct hostdesc host;
};
struct txdesc_host {
u32_l ready;
/// API of the embedded part
struct txdesc_api api;
};
/// Comes from ipc_dma.h
/// Element in the pool of TX DMA bridge descriptors.
struct dma_desc {
/** Application subsystem address which is used as source address for DMA payload
* transfer*/
u32_l src;
/** Points to the start of the embedded data buffer associated with this descriptor.
* This address acts as the destination address for the DMA payload transfer*/
u32_l dest;
/// Complete length of the buffer in memory
u16_l length;
/// Control word for the DMA engine (e.g. for interrupt generation)
u16_l ctrl;
/// Pointer to the next element of the chained list
u32_l next;
};
// Comes from la.h
/// Length of the configuration data of a logic analyzer
#define LA_CONF_LEN 10
/// Structure containing the configuration data of a logic analyzer
struct la_conf_tag {
u32_l conf[LA_CONF_LEN];
u32_l trace_len;
u32_l diag_conf;
};
/// Size of a logic analyzer memory
#define LA_MEM_LEN (1024 * 1024)
/// Type of errors
enum {
/// Recoverable error, not requiring any action from Upper MAC
DBG_ERROR_RECOVERABLE = 0,
/// Fatal error, requiring Upper MAC to reset Lower MAC and HW and restart operation
DBG_ERROR_FATAL
};
/// Maximum length of the SW diag trace
#define DBG_SW_DIAG_MAX_LEN 1024
/// Maximum length of the error trace
#define DBG_ERROR_TRACE_SIZE 256
/// Number of MAC diagnostic port banks
#define DBG_DIAGS_MAC_MAX 48
/// Number of PHY diagnostic port banks
#define DBG_DIAGS_PHY_MAX 32
/// Maximum size of the RX header descriptor information in the debug dump
#define DBG_RHD_MEM_LEN (5 * 1024)
/// Maximum size of the RX buffer descriptor information in the debug dump
#define DBG_RBD_MEM_LEN (5 * 1024)
/// Maximum size of the TX header descriptor information in the debug dump
#define DBG_THD_MEM_LEN (10 * 1024)
/// Structure containing the information about the PHY channel that is used
struct phy_channel_info {
/// PHY channel information 1
u32_l info1;
/// PHY channel information 2
u32_l info2;
};
/// Debug information forwarded to host when an error occurs
struct dbg_debug_info_tag {
/// Type of error (0: recoverable, 1: fatal)
u32_l error_type;
/// Pointer to the first RX Header Descriptor chained to the MAC HW
u32_l rhd;
/// Size of the RX header descriptor buffer
u32_l rhd_len;
/// Pointer to the first RX Buffer Descriptor chained to the MAC HW
u32_l rbd;
/// Size of the RX buffer descriptor buffer
u32_l rbd_len;
/// Pointer to the first TX Header Descriptors chained to the MAC HW
u32_l thd[NX_TXQ_CNT];
/// Size of the TX header descriptor buffer
u32_l thd_len[NX_TXQ_CNT];
/// MAC HW diag configuration
u32_l hw_diag;
/// Error message
u32_l error[DBG_ERROR_TRACE_SIZE/4];
/// SW diag configuration length
u32_l sw_diag_len;
/// SW diag configuration
u32_l sw_diag[DBG_SW_DIAG_MAX_LEN/4];
/// PHY channel information
struct phy_channel_info chan_info;
/// Embedded LA configuration
struct la_conf_tag la_conf;
/// MAC diagnostic port state
u16_l diags_mac[DBG_DIAGS_MAC_MAX];
/// PHY diagnostic port state
u16_l diags_phy[DBG_DIAGS_PHY_MAX];
/// MAC HW RX Header descriptor pointer
u32_l rhd_hw_ptr;
/// MAC HW RX Buffer descriptor pointer
u32_l rbd_hw_ptr;
};
/// Full debug dump that is forwarded to host in case of error
struct dbg_debug_dump_tag {
/// Debug information
struct dbg_debug_info_tag dbg_info;
/// RX header descriptor memory
u32_l rhd_mem[DBG_RHD_MEM_LEN/4];
/// RX buffer descriptor memory
u32_l rbd_mem[DBG_RBD_MEM_LEN/4];
/// TX header descriptor memory
u32_l thd_mem[NX_TXQ_CNT][DBG_THD_MEM_LEN/4];
/// Logic analyzer memory
u32_l la_mem[LA_MEM_LEN/4];
};
/// Number of pulses in a radar event structure
#define RADAR_PULSE_MAX 4
/// Definition of an array of radar pulses
struct radar_pulse_array_desc {
/// Buffer containing the radar pulses
u32_l pulse[RADAR_PULSE_MAX];
/// Index of the radar detection chain that detected those pulses
u32_l idx;
/// Number of valid pulses in the buffer
u32_l cnt;
};
/// Bit mapping inside a radar pulse element
struct radar_pulse {
s32_l freq:6; /** Freq (resolution is 2Mhz range is [-Fadc/4 .. Fadc/4]) */
u32_l fom:4; /** Figure of Merit */
u32_l len:6; /** Length of the current radar pulse (resolution is 2us) */
u32_l rep:16; /** Time interval between the previous radar event
and the current one (in us) */
};
/// Definition of a RX vector descriptor
struct rx_vector_desc {
/// PHY channel information
struct phy_channel_info phy_info;
/// RX vector 1
u32_l rx_vect1[IPC_RXVEC_SIZE/4];
/// Used to print a valid rx vector
u32_l pattern;
};
///
struct rxdesc_tag {
/// Host Buffer Address
u32_l host_id;
/// Length
u32_l frame_len;
/// Status
u16_l status;
};
/**
****************************************************************************************
* @defgroup IPC IPC
* @ingroup NXMAC
* @brief Inter Processor Communication module.
*
* The IPC module implements the protocol to communicate between the Host CPU
* and the Embedded CPU.
*
* @see http://en.wikipedia.org/wiki/Circular_buffer
* For more information about the ring buffer typical use and difficulties.
****************************************************************************************
*/
/**
****************************************************************************************
* @addtogroup IPC_TX IPC Tx path
* @ingroup IPC
* @brief IPC Tx path structures and functions
*
* A typical use case of the IPC Tx path API:
* @msc
* hscale = "2";
*
* a [label=Driver],
* b [label="IPC host"],
* c [label="IPC emb"],
* d [label=Firmware];
*
* --- [label="Tx descriptor queue example"];
* a=>a [label="Driver receives a Tx packet from OS"];
* a=>b [label="ipc_host_txdesc_get()"];
* a<<b [label="struct txdesc_host *"];
* a=>a [label="Driver fill the descriptor"];
* a=>b [label="ipc_host_txdesc_push()"];
* ... [label="(several Tx desc can be pushed)"];
* b:>c [label="Tx desc queue filled IRQ"];
* c=>>d [label="EDCA sub-scheduler callback"];
* c<<d [label="Tx desc queue to pop"];
* c=>>d [label="UMAC Tx desc callback"];
* ... [label="(several Tx desc can be popped)"];
* d=>d [label="Packets are sent or discarded"];
* --- [label="Tx confirm queue example"];
* c<=d [label="ipc_emb_txcfm_push()"];
* c>>d [label="Request accepted"];
* ... [label="(several Tx cfm can be pushed)"];
* b<:c [label="Tx cfm queue filled IRQ"];
* a<<=b [label="Driver's Tx Confirm callback"];
* a=>b [label="ipc_host_txcfm_pop()"];
* a<<b [label="struct ipc_txcfm"];
* a<=a [label="Packets are freed by the driver"];
* @endmsc
*
* @{
****************************************************************************************
*/
/// @} IPC_TX
/**
****************************************************************************************
* @defgroup IPC_RX IPC Rx path
* @ingroup IPC
* @brief IPC Rx path functions and structures
*
* A typical use case of the IPC Rx path API:
* @msc
* hscale = "2";
*
* a [label=Firmware],
* b [label="IPC emb"],
* c [label="IPC host"],
* d [label=Driver];
*
* --- [label="Rx buffer and desc queues usage example"];
* d=>c [label="ipc_host_rxbuf_push()"];
* d=>c [label="ipc_host_rxbuf_push()"];
* d=>c [label="ipc_host_rxbuf_push()"];
* ... [label="(several Rx buffer are pushed)"];
* a=>a [label=" Frame is received\n from the medium"];
* a<<b [label="struct ipc_rxbuf"];
* a=>a [label=" Firmware fill the buffer\n with received frame"];
* a<<b [label="Push accepted"];
* ... [label="(several Rx desc can be pushed)"];
* b:>c [label="Rx desc queue filled IRQ"];
* c=>>d [label="Driver Rx packet callback"];
* c<=d [label="ipc_host_rxdesc_pop()"];
* d=>d [label="Rx packet is handed \nover to the OS "];
* ... [label="(several Rx desc can be poped)"];
* --- [label="Rx buffer request exemple"];
* b:>c [label="Low Rx buffer count IRQ"];
* a<<b [label="struct ipc_rxbuf"];
* c=>>d [label="Driver Rx buffer callback"];
* d=>c [label="ipc_host_rxbuf_push()"];
* d=>c [label="ipc_host_rxbuf_push()"];
* d=>c [label="ipc_host_rxbuf_push()"];
* ... [label="(several Rx buffer are pushed)"];
* @endmsc
*
* @addtogroup IPC_RX
* @{
****************************************************************************************
*/
/// @} IPC_RX
/**
****************************************************************************************
* @defgroup IPC_MISC IPC Misc
* @ingroup IPC
* @brief IPC miscellaneous functions
****************************************************************************************
*/
/** IPC header structure. This structure is stored at the beginning of every IPC message.
* @warning This structure's size must NOT exceed 4 bytes in length.
*/
struct ipc_header {
/// IPC message type.
u16_l type;
/// IPC message size in number of bytes.
u16_l size;
};
struct ipc_msg_elt {
/// Message header (alignment forced on word size, see allocation in shared env).
struct ipc_header header __ALIGN4;
};
/// Message structure for MSGs from Emb to App
struct ipc_e2a_msg {
u16_l id; ///< Message id.
u16_l dummy_dest_id;
u16_l dummy_src_id;
u16_l param_len; ///< Parameter embedded struct length.
u32_l pattern; ///< Used to stamp a valid MSG buffer
u32_l param[IPC_E2A_MSG_PARAM_SIZE]; ///< Parameter embedded struct. Must be word-aligned.
};
/// Message structure for Debug messages from Emb to App
struct ipc_dbg_msg {
u32_l string[IPC_DBG_PARAM_SIZE/4]; ///< Debug string
u32_l pattern; ///< Used to stamp a valid buffer
};
/// Message structure for MSGs from App to Emb.
/// Actually a sub-structure will be used when filling the messages.
struct ipc_a2e_msg {
u32_l dummy_word; // used to cope with kernel message structure
u32_l msg[IPC_A2E_MSG_BUF_SIZE]; // body of the msg
};
struct ipc_shared_rx_buf {
/// < ptr to hostbuf client (ipc_host client) structure
u32_l hostid;
/// < ptr to real hostbuf dma address
u32_l dma_addr;
};
struct ipc_shared_rx_desc {
/// DMA Address
u32_l dma_addr;
};
/// Structure containing FW characteristics for compatibility checking
struct compatibility_tag {
/// Size of IPC shared memory
u16_l ipc_shared_size;
/// Message struct/ID API version
u16_l msg_api;
/// Version of IPC shared
u8_l ipc_shared_version;
/// Number of host buffers available for Emb->App MSGs sending
u8_l msge2a_buf_cnt;
/// Number of host buffers available for Debug Messages sending
u8_l dbgbuf_cnt;
/// Number of host buffers available for Radar events handling
u8_l radarbuf_cnt;
/// Number of host buffers available for unsupported Rx vectors handling
u8_l unsuprxvecbuf_cnt;
/// Number of shared descriptors available for Data RX handling
u8_l rxdesc_cnt;
/// Number of host buffers available for Data Rx handling
u8_l rxbuf_cnt;
/// Number of descriptors in BK TX queue (power of 2, min 4, max 64)
u8_l bk_txq;
/// Number of descriptors in BE TX queue (power of 2, min 4, max 64)
u8_l be_txq;
/// Number of descriptors in VI TX queue (power of 2, min 4, max 64)
u8_l vi_txq;
/// Number of descriptors in VO TX queue (power of 2, min 4, max 64)
u8_l vo_txq;
/// Number of descriptors in BCN TX queue (power of 2, min 4, max 64)
u8_l bcn_txq;
};
/*
* TYPE and STRUCT DEFINITIONS
****************************************************************************************
*/
// Indexes are defined in the MIB shared structure
struct ipc_shared_env_tag {
volatile struct compatibility_tag comp_info; //FW characteristics
volatile struct ipc_a2e_msg msg_a2e_buf; // room for MSG to be sent from App to Emb
// Fields for MSGs sending from Emb to App
volatile struct ipc_e2a_msg msg_e2a_buf; // room to build the MSG to be DMA Xferred
volatile struct dma_desc msg_dma_desc; // DMA descriptor for Emb->App MSGs Xfers
volatile u32_l msg_e2a_hostbuf_addr[IPC_MSGE2A_BUF_CNT]; // buffers @ for DMA Xfers
// Fields for Debug MSGs sending from Emb to App
volatile struct ipc_dbg_msg dbg_buf; // room to build the MSG to be DMA Xferred
volatile struct dma_desc dbg_dma_desc; // DMA descriptor for Emb->App MSGs Xfers
volatile u32_l dbg_hostbuf_addr[IPC_DBGBUF_CNT]; // buffers @ for MSGs DMA Xfers
volatile u32_l la_dbginfo_addr; // Host buffer address for the debug information
volatile u32_l pattern_addr;
volatile u32_l radarbuf_hostbuf[IPC_RADARBUF_CNT]; // buffers @ for Radar Events
volatile u32_l unsuprxvecbuf_hostbuf[IPC_UNSUPRXVECBUF_CNT]; // buffers @ for unsupported Rx vectors
volatile struct txdesc_host txdesc0[CONFIG_USER_MAX][NX_TXDESC_CNT0];
volatile struct txdesc_host txdesc1[CONFIG_USER_MAX][NX_TXDESC_CNT1];
volatile struct txdesc_host txdesc2[CONFIG_USER_MAX][NX_TXDESC_CNT2];
volatile struct txdesc_host txdesc3[CONFIG_USER_MAX][NX_TXDESC_CNT3];
#if NX_TXQ_CNT == 5
volatile struct txdesc_host txdesc4[1][NX_TXDESC_CNT4];
#endif
#ifdef CONFIG_RWNX_FULLMAC
// RX Descriptors Array
volatile struct ipc_shared_rx_desc host_rxdesc[IPC_RXDESC_CNT];
// RX Buffers Array
volatile struct ipc_shared_rx_buf host_rxbuf[IPC_RXBUF_CNT];
#else
// buffers @ for Data Rx
volatile u32_l host_rxbuf[IPC_RXBUF_CNT];
#endif /* CONFIG_RWNX_FULLMAC */
u32_l buffered[NX_REMOTE_STA_MAX][TID_MAX];
volatile uint16_t trace_pattern;
volatile uint32_t trace_start;
volatile uint32_t trace_end;
volatile uint32_t trace_size;
volatile uint32_t trace_offset;
volatile uint32_t trace_nb_compo;
volatile uint32_t trace_offset_compo;
};
extern struct ipc_shared_env_tag ipc_shared_env;
/*
* TYPE and STRUCT DEFINITIONS
****************************************************************************************
*/
// IRQs from app to emb
/// Interrupts bits used for the TX descriptors of the AC queues
#ifdef CONFIG_RWNX_MUMIMO_TX
#ifdef CONFIG_RWNX_OLD_IPC
#error "MU-MIMO cannot be compiled for old IPC"
#endif
/// Interrupts bits used
#if CONFIG_USER_MAX > 3
#define IPC_IRQ_A2E_USER_MSK 0xF
#elif CONFIG_USER_MAX > 2
#define IPC_IRQ_A2E_USER_MSK 0x7
#else
#define IPC_IRQ_A2E_USER_MSK 0x3
#endif
/// Offset of the interrupts for AC0
#define IPC_IRQ_A2E_AC0_OFT 8
/// Mask of the interrupts for AC0
#define IPC_IRQ_A2E_AC0_MSK (IPC_IRQ_A2E_USER_MSK << IPC_IRQ_A2E_AC0_OFT)
/// Offset of the interrupts for AC1
#define IPC_IRQ_A2E_AC1_OFT (IPC_IRQ_A2E_AC0_OFT + CONFIG_USER_MAX)
/// Mask of the interrupts for AC1
#define IPC_IRQ_A2E_AC1_MSK (IPC_IRQ_A2E_USER_MSK << IPC_IRQ_A2E_AC1_OFT)
/// Offset of the interrupts for AC2
#define IPC_IRQ_A2E_AC2_OFT (IPC_IRQ_A2E_AC1_OFT + CONFIG_USER_MAX)
/// Mask of the interrupts for AC2
#define IPC_IRQ_A2E_AC2_MSK (IPC_IRQ_A2E_USER_MSK << IPC_IRQ_A2E_AC2_OFT)
/// Offset of the interrupts for AC3
#define IPC_IRQ_A2E_AC3_OFT (IPC_IRQ_A2E_AC2_OFT + CONFIG_USER_MAX)
/// Mask of the interrupts for AC3
#define IPC_IRQ_A2E_AC3_MSK (IPC_IRQ_A2E_USER_MSK << IPC_IRQ_A2E_AC3_OFT)
/// Offset of the interrupts for BCN
#define IPC_IRQ_A2E_BCN_OFT (IPC_IRQ_A2E_AC3_OFT + CONFIG_USER_MAX)
/// Mask of the interrupts for BCN
#define IPC_IRQ_A2E_BCN_MSK CO_BIT(IPC_IRQ_A2E_BCN_OFT)
#define IPC_IRQ_A2E_AC_TXDESC (IPC_IRQ_A2E_AC0_MSK | IPC_IRQ_A2E_AC1_MSK | \
IPC_IRQ_A2E_AC2_MSK | IPC_IRQ_A2E_AC3_MSK)
/// Interrupts bits used for the TX descriptors of the BCN queue
#if NX_TXQ_CNT < 5
#define IPC_IRQ_A2E_BCN_TXDESC 0
#else
#define IPC_IRQ_A2E_BCN_TXDESC (0x01 << IPC_IRQ_A2E_BCN_OFT)
#endif
/// IPC TX descriptor interrupt mask
#define IPC_IRQ_A2E_TXDESC (IPC_IRQ_A2E_AC_TXDESC | IPC_IRQ_A2E_BCN_TXDESC)
#else
/// IPC TX descriptor interrupt mask
#define IPC_IRQ_A2E_TXDESC 0xFF00
#endif
#define IPC_IRQ_A2E_TXDESC_FIRSTBIT (8)
#define IPC_IRQ_A2E_RXBUF_BACK CO_BIT(5)
#define IPC_IRQ_A2E_RXDESC_BACK CO_BIT(4)
#define IPC_IRQ_A2E_MSG CO_BIT(1)
#define IPC_IRQ_A2E_DBG CO_BIT(0)
#define IPC_IRQ_A2E_ALL (IPC_IRQ_A2E_TXDESC|IPC_IRQ_A2E_MSG|IPC_IRQ_A2E_DBG)
// IRQs from emb to app
#define IPC_IRQ_E2A_TXCFM_POS 7
#ifdef CONFIG_RWNX_MUMIMO_TX
#ifdef CONFIG_RWNX_OLD_IPC
#error "MU-MIMO cannot be compiled for old IPC"
#endif
/// Interrupts bits used
#if CONFIG_USER_MAX > 3
#define IPC_IRQ_E2A_USER_MSK 0xF
#elif CONFIG_USER_MAX > 2
#define IPC_IRQ_E2A_USER_MSK 0x7
#else
#define IPC_IRQ_E2A_USER_MSK 0x3
#endif
/// Offset of the interrupts for AC0
#define IPC_IRQ_E2A_AC0_OFT IPC_IRQ_E2A_TXCFM_POS
/// Mask of the interrupts for AC0
#define IPC_IRQ_E2A_AC0_MSK (IPC_IRQ_E2A_USER_MSK << IPC_IRQ_E2A_AC0_OFT)
/// Offset of the interrupts for AC1
#define IPC_IRQ_E2A_AC1_OFT (IPC_IRQ_E2A_AC0_OFT + CONFIG_USER_MAX)
/// Mask of the interrupts for AC1
#define IPC_IRQ_E2A_AC1_MSK (IPC_IRQ_E2A_USER_MSK << IPC_IRQ_E2A_AC1_OFT)
/// Offset of the interrupts for AC2
#define IPC_IRQ_E2A_AC2_OFT (IPC_IRQ_E2A_AC1_OFT + CONFIG_USER_MAX)
/// Mask of the interrupts for AC2
#define IPC_IRQ_E2A_AC2_MSK (IPC_IRQ_E2A_USER_MSK << IPC_IRQ_E2A_AC2_OFT)
/// Offset of the interrupts for AC3
#define IPC_IRQ_E2A_AC3_OFT (IPC_IRQ_E2A_AC2_OFT + CONFIG_USER_MAX)
/// Mask of the interrupts for AC3
#define IPC_IRQ_E2A_AC3_MSK (IPC_IRQ_E2A_USER_MSK << IPC_IRQ_E2A_AC3_OFT)
/// Offset of the interrupts for BCN
#define IPC_IRQ_E2A_BCN_OFT (IPC_IRQ_E2A_AC3_OFT + CONFIG_USER_MAX)
/// Mask of the interrupts for BCN
#define IPC_IRQ_E2A_BCN_MSK CO_BIT(IPC_IRQ_E2A_BCN_OFT)
#define IPC_IRQ_E2A_AC_TXCFM (IPC_IRQ_E2A_AC0_MSK | IPC_IRQ_E2A_AC1_MSK | \
IPC_IRQ_E2A_AC2_MSK | IPC_IRQ_E2A_AC3_MSK)
/// Interrupts bits used for the TX descriptors of the BCN queue
#if NX_TXQ_CNT < 5
#define IPC_IRQ_E2A_BCN_TXCFM 0
#else
#define IPC_IRQ_E2A_BCN_TXCFM (0x01 << IPC_IRQ_E2A_BCN_OFT)
#endif
/// IPC TX descriptor interrupt mask
#define IPC_IRQ_E2A_TXCFM (IPC_IRQ_E2A_AC_TXCFM | IPC_IRQ_E2A_BCN_TXCFM)
#else
#define IPC_IRQ_E2A_TXCFM (((1 << NX_TXQ_CNT) - 1) << IPC_IRQ_E2A_TXCFM_POS)
#endif /* CONFIG_RWNX_MUMIMO_TX */
#define IPC_IRQ_E2A_UNSUP_RX_VEC CO_BIT(7)
#define IPC_IRQ_E2A_RADAR CO_BIT(6)
#define IPC_IRQ_E2A_TBTT_SEC CO_BIT(5)
#define IPC_IRQ_E2A_TBTT_PRIM CO_BIT(4)
#define IPC_IRQ_E2A_RXDESC CO_BIT(3)
#define IPC_IRQ_E2A_MSG_ACK CO_BIT(2)
#define IPC_IRQ_E2A_MSG CO_BIT(1)
#define IPC_IRQ_E2A_DBG CO_BIT(0)
#define IPC_IRQ_E2A_ALL (IPC_IRQ_E2A_TXCFM \
| IPC_IRQ_E2A_RXDESC \
| IPC_IRQ_E2A_MSG_ACK \
| IPC_IRQ_E2A_MSG \
| IPC_IRQ_E2A_DBG \
| IPC_IRQ_E2A_TBTT_PRIM \
| IPC_IRQ_E2A_TBTT_SEC \
| IPC_IRQ_E2A_RADAR \
| IPC_IRQ_E2A_UNSUP_RX_VEC)
// FLAGS for RX desc
#define IPC_RX_FORWARD CO_BIT(1)
#define IPC_RX_INTRABSS CO_BIT(0)
// IPC message TYPE
enum {
IPC_MSG_NONE = 0,
IPC_MSG_WRAP,
IPC_MSG_KMSG,
IPC_DBG_STRING,
};
#endif // _IPC_SHARED_H_

View File

@ -0,0 +1,564 @@
/**
****************************************************************************************
*
* @file lmac_mac_types.h
*
* @brief MAC related definitions.
*
* Adapted from mac_types.h to used lmac_types.h instead of standard types
* eg: perl -pi -e '$_ =~ s/uint(\d{1,2})_t/u$1_l/g; \
* $_ =~ s/int(\d{1,2})_t/s$1_l/g; \
* $_ =~ s/CO_BIT/BIT/g;' lmac_mac.h
*
* Copyright (C) RivieraWaves 2011-2019
*
****************************************************************************************
*/
#ifndef LMAC_MAC_H_
#define LMAC_MAC_H_
#include "lmac_types.h"
/// Interface types
enum mac_vif_type {
/// ESS STA interface
VIF_STA,
/// IBSS STA interface
VIF_IBSS,
/// AP interface
VIF_AP,
/// Mesh Point interface
VIF_MESH_POINT,
/// Monitor interface
VIF_MONITOR,
/// Unknown type
VIF_UNKNOWN
};
/// MAC address length in bytes.
#define MAC_ADDR_LEN 6
/// MAC address structure.
struct mac_addr {
/// Array of 16-bit words that make up the MAC address.
u16_l array[MAC_ADDR_LEN/2];
};
/// SSID maximum length.
#define MAC_SSID_LEN 32
/// SSID.
struct mac_ssid {
/// Actual length of the SSID.
u8_l length;
/// Array containing the SSID name.
u8_l array[MAC_SSID_LEN];
};
/// BSS type
enum mac_bss_type {
INFRASTRUCTURE_MODE = 1,
INDEPENDENT_BSS_MODE,
ANY_BSS_MODE
};
/// Channel Band
enum mac_chan_band {
/// 2.4GHz Band
PHY_BAND_2G4,
/// 5GHz band
PHY_BAND_5G,
/// Number of bands
PHY_BAND_MAX,
};
/// Operating Channel Bandwidth
enum mac_chan_bandwidth {
/// 20MHz BW
PHY_CHNL_BW_20,
/// 40MHz BW
PHY_CHNL_BW_40,
/// 80MHz BW
PHY_CHNL_BW_80,
/// 160MHz BW
PHY_CHNL_BW_160,
/// 80+80MHz BW
PHY_CHNL_BW_80P80,
/// Reserved BW
PHY_CHNL_BW_OTHER,
};
/// max number of channels in the 2.4 GHZ band
#define MAC_DOMAINCHANNEL_24G_MAX 14
/// max number of channels in the 5 GHZ band
#define MAC_DOMAINCHANNEL_5G_MAX 28
/// Channel Flag
enum mac_chan_flags {
/// Cannot initiate radiation on this channel
CHAN_NO_IR = BIT(0),
/// Channel is not allowed
CHAN_DISABLED = BIT(1),
/// Radar detection required on this channel
CHAN_RADAR = BIT(2),
};
/// Primary Channel definition
struct mac_chan_def {
/// Frequency of the channel (in MHz)
u16_l freq;
/// RF band (@ref mac_chan_band)
u8_l band;
/// Additional information (@ref mac_chan_flags)
u8_l flags;
/// Max transmit power allowed on this channel (dBm)
s8_l tx_power;
};
/// Operating Channel
struct mac_chan_op {
/// Band (@ref mac_chan_band)
u8_l band;
/// Channel type (@ref mac_chan_bandwidth)
u8_l type;
/// Frequency for Primary 20MHz channel (in MHz)
u16_l prim20_freq;
/// Frequency center of the contiguous channel or center of Primary 80+80 (in MHz)
u16_l center1_freq;
/// Frequency center of the non-contiguous secondary 80+80 (in MHz)
u16_l center2_freq;
/// Max transmit power allowed on this channel (dBm)
s8_l tx_power;
/// Additional information (@ref mac_chan_flags)
u8_l flags;
};
/// Cipher suites (order is important as it is used by MACHW)
enum mac_cipher_suite {
/// 00-0F-AC 1
MAC_CIPHER_WEP40 = 0,
/// 00-0F-AC 2
MAC_CIPHER_TKIP = 1,
/// 00-0F-AC 4
MAC_CIPHER_CCMP = 2,
/// 00-0F-AC 5
MAC_CIPHER_WEP104 = 3,
/// 00-14-72 1
MAC_CIPHER_WPI_SMS4 = 4,
/// 00-0F-AC 6 (aka AES_CMAC)
MAC_CIPHER_BIP_CMAC_128 = 5,
// following cipher are not supported by MACHW
/// 00-0F-AC 08
MAC_CIPHER_GCMP_128,
/// 00-0F-AC 09
MAC_CIPHER_GCMP_256,
/// 00-0F-AC 10
MAC_CIPHER_CCMP_256,
/// 00-0F-AC 11
MAC_CIPHER_BIP_GMAC_128,
/// 00-0F-AC 12
MAC_CIPHER_BIP_GMAC_256,
/// 00-0F-AC 13
MAC_CIPHER_BIP_CMAC_256,
MAC_CIPHER_INVALID = 0xFF
};
/// Authentication and Key Management suite
enum mac_akm_suite {
/// No security
MAC_AKM_NONE,
/// Pre RSN (WEP or WPA)
MAC_AKM_PRE_RSN,
/// 00-0F-AC 1
MAC_AKM_8021X,
/// 00-0F-AC 2
MAC_AKM_PSK,
/// 00-0F-AC 3
MAC_AKM_FT_8021X,
/// 00-0F-AC 4
MAC_AKM_FT_PSK,
/// 00-0F-AC 5
MAC_AKM_8021X_SHA256,
/// 00-0F-AC 6
MAC_AKM_PSK_SHA256,
/// 00-0F-AC 7
MAC_AKM_TDLS,
/// 00-0F-AC 8
MAC_AKM_SAE,
/// 00-0F-AC 9
MAC_AKM_FT_OVER_SAE,
/// 00-0F-AC 11
MAC_AKM_8021X_SUITE_B,
/// 00-0F-AC 12
MAC_AKM_8021X_SUITE_B_192,
/// 00-0F-AC 14
MAC_AKM_FILS_SHA256,
/// 00-0F-AC 15
MAC_AKM_FILS_SHA384,
/// 00-0F-AC 16
MAC_AKM_FT_FILS_SHA256,
/// 00-0F-AC 17
MAC_AKM_FT_FILS_SHA384,
/// 00-0F-AC 18
MAC_AKM_OWE,
/// 00-14-72 1
MAC_AKM_WAPI_CERT,
/// 00-14-72 2
MAC_AKM_WAPI_PSK,
};
/// Scan result element, parsed from beacon or probe response frames.
struct mac_scan_result {
/// Scan result is valid
bool valid_flag;
/// Network BSSID.
struct mac_addr bssid;
/// Network name.
struct mac_ssid ssid;
/// Network type (@ref mac_bss_type).
u16_l bsstype;
/// Network channel.
struct mac_chan_def *chan;
/// Network beacon period (in TU).
u16_l beacon_period;
/// Capability information
u16_l cap_info;
/// Supported AKM (bit-field of @ref mac_akm_suite)
u32_l akm;
/// Group cipher (bit-field of @ref mac_cipher_suite)
u16_l group_cipher;
/// Group cipher (bit-field of @ref mac_cipher_suite)
u16_l pairwise_cipher;
/// RSSI of the scanned BSS (in dBm)
s8_l rssi;
};
/// Legacy rate 802.11 definitions
enum mac_legacy_rates {
/// DSSS/CCK 1Mbps
MAC_RATE_1MBPS = 2,
/// DSSS/CCK 2Mbps
MAC_RATE_2MBPS = 4,
/// DSSS/CCK 5.5Mbps
MAC_RATE_5_5MBPS = 11,
/// OFDM 6Mbps
MAC_RATE_6MBPS = 12,
/// OFDM 9Mbps
MAC_RATE_9MBPS = 18,
/// DSSS/CCK 11Mbps
MAC_RATE_11MBPS = 22,
/// OFDM 12Mbps
MAC_RATE_12MBPS = 24,
/// OFDM 18Mbps
MAC_RATE_18MBPS = 36,
/// OFDM 24Mbps
MAC_RATE_24MBPS = 48,
/// OFDM 36Mbps
MAC_RATE_36MBPS = 72,
/// OFDM 48Mbps
MAC_RATE_48MBPS = 96,
/// OFDM 54Mbps
MAC_RATE_54MBPS = 108
};
/// BSS Membership Selector definitions
enum mac_bss_membership {
/// HT PHY
MAC_BSS_MEMBERSHIP_HT_PHY = 127,
/// VHT PHY
MAC_BSS_MEMBERSHIP_VHT_PHY = 126,
};
/// MAC rateset maximum length
#define MAC_RATESET_LEN 12
/// Structure containing the legacy rateset of a station
struct mac_rateset {
/// Number of legacy rates supported
u8_l length;
/// Array of legacy rates
u8_l array[MAC_RATESET_LEN];
};
/// MAC Security Key maximum length
#define MAC_SEC_KEY_LEN 32 // TKIP keys 256 bits (max length) with MIC keys
/// Structure defining a security key
struct mac_sec_key {
/// Key material length
u8_l length;
/// Key material
u32_l array[MAC_SEC_KEY_LEN/4];
};
/// Access Category enumeration
enum mac_ac {
/// Background
AC_BK = 0,
/// Best-effort
AC_BE,
/// Video
AC_VI,
/// Voice
AC_VO,
/// Number of access categories
AC_MAX
};
/// Traffic ID enumeration
enum mac_tid {
/// TID_0. Mapped to @ref AC_BE as per 802.11 standard.
TID_0,
/// TID_1. Mapped to @ref AC_BK as per 802.11 standard.
TID_1,
/// TID_2. Mapped to @ref AC_BK as per 802.11 standard.
TID_2,
/// TID_3. Mapped to @ref AC_BE as per 802.11 standard.
TID_3,
/// TID_4. Mapped to @ref AC_VI as per 802.11 standard.
TID_4,
/// TID_5. Mapped to @ref AC_VI as per 802.11 standard.
TID_5,
/// TID_6. Mapped to @ref AC_VO as per 802.11 standard.
TID_6,
/// TID_7. Mapped to @ref AC_VO as per 802.11 standard.
TID_7,
/// Non standard Management TID used internally
TID_MGT,
/// Number of TID supported
TID_MAX
};
/// MCS bitfield maximum size (in bytes)
#define MAX_MCS_LEN 16 // 16 * 8 = 128
/// MAC HT capability information element
struct mac_htcapability {
/// HT capability information
u16_l ht_capa_info;
/// A-MPDU parameters
u8_l a_mpdu_param;
/// Supported MCS
u8_l mcs_rate[MAX_MCS_LEN];
/// HT extended capability information
u16_l ht_extended_capa;
/// Beamforming capability information
u32_l tx_beamforming_capa;
/// Antenna selection capability information
u8_l asel_capa;
};
/// MAC VHT capability information element
struct mac_vhtcapability {
/// VHT capability information
u32_l vht_capa_info;
/// RX MCS map
u16_l rx_mcs_map;
/// RX highest data rate
u16_l rx_highest;
/// TX MCS map
u16_l tx_mcs_map;
/// TX highest data rate
u16_l tx_highest;
};
/// Length (in bytes) of the MAC HE capability field
#define MAC_HE_MAC_CAPA_LEN 6
/// Length (in bytes) of the PHY HE capability field
#define MAC_HE_PHY_CAPA_LEN 11
/// Maximum length (in bytes) of the PPE threshold data
#define MAC_HE_PPE_THRES_MAX_LEN 25
/// Structure listing the per-NSS, per-BW supported MCS combinations
struct mac_he_mcs_nss_supp {
/// per-NSS supported MCS in RX, for BW <= 80MHz
u16_l rx_mcs_80;
/// per-NSS supported MCS in TX, for BW <= 80MHz
u16_l tx_mcs_80;
/// per-NSS supported MCS in RX, for BW = 160MHz
u16_l rx_mcs_160;
/// per-NSS supported MCS in TX, for BW = 160MHz
u16_l tx_mcs_160;
/// per-NSS supported MCS in RX, for BW = 80+80MHz
u16_l rx_mcs_80p80;
/// per-NSS supported MCS in TX, for BW = 80+80MHz
u16_l tx_mcs_80p80;
};
/// MAC HE capability information element
struct mac_hecapability {
/// MAC HE capabilities
u8_l mac_cap_info[MAC_HE_MAC_CAPA_LEN];
/// PHY HE capabilities
u8_l phy_cap_info[MAC_HE_PHY_CAPA_LEN];
/// Supported MCS combinations
struct mac_he_mcs_nss_supp mcs_supp;
/// PPE Thresholds data
u8_l ppe_thres[MAC_HE_PPE_THRES_MAX_LEN];
};
/// Station flags
enum mac_sta_flags {
/// Bit indicating that a STA has QoS (WMM) capability
STA_QOS_CAPA = BIT(0),
/// Bit indicating that a STA has HT capability
STA_HT_CAPA = BIT(1),
/// Bit indicating that a STA has VHT capability
STA_VHT_CAPA = BIT(2),
/// Bit indicating that a STA has MFP capability
STA_MFP_CAPA = BIT(3),
/// Bit indicating that the STA included the Operation Notification IE
STA_OPMOD_NOTIF = BIT(4),
/// Bit indicating that a STA has HE capability
STA_HE_CAPA = BIT(5),
};
/// Connection flags
enum mac_connection_flags {
/// Flag indicating whether the control port is controlled by host or not
CONTROL_PORT_HOST = BIT(0),
/// Flag indicating whether the control port frame shall be sent unencrypted
CONTROL_PORT_NO_ENC = BIT(1),
/// Flag indicating whether HT and VHT shall be disabled or not
DISABLE_HT = BIT(2),
/// Flag indicating whether WPA or WPA2 authentication is in use
WPA_WPA2_IN_USE = BIT(3),
/// Flag indicating whether MFP is in use
MFP_IN_USE = BIT(4),
// Flag indicating Roam
REASSOCIATION = BIT(5),
};
#ifdef CONFIG_HE_FOR_OLD_KERNEL
#define IEEE80211_HE_MAC_CAP2_ALL_ACK 0x02
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G 0x02
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G 0x04
#define IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD 0x20
#define IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US 0x40
#define IEEE80211_HE_PHY_CAP1_MIDAMBLE_RX_TX_MAX_NSTS 0x80
#define IEEE80211_HE_PHY_CAP2_MIDAMBLE_RX_TX_MAX_NSTS 0x01
#define IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US 0x02
#define IEEE80211_HE_PHY_CAP2_DOPPLER_RX 0x20
#define IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ 0x08
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM 0x18
#define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 0x00
#define IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA 0x40
#define IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE 0x01
#define IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 0x0c
#define IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK 0x40
#define IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK 0x80
#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU 0x01
#define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU 0x02
#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB 0x04
#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB 0x08
#define IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT 0x80
#define IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO 0x40
#define IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI 0x04
#define IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G 0x02
#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB 0x10
#define IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB 0x20
#define IEEE80211_HE_PPE_THRES_MAX_LEN 25
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
#define WLAN_EID_EXTENSION 255
/* Element ID Extensions for Element ID 255 */
enum ieee80211_eid_ext {
WLAN_EID_EXT_ASSOC_DELAY_INFO = 1,
WLAN_EID_EXT_FILS_REQ_PARAMS = 2,
WLAN_EID_EXT_FILS_KEY_CONFIRM = 3,
WLAN_EID_EXT_FILS_SESSION = 4,
WLAN_EID_EXT_FILS_HLP_CONTAINER = 5,
WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN = 6,
WLAN_EID_EXT_KEY_DELIVERY = 7,
WLAN_EID_EXT_FILS_WRAPPED_DATA = 8,
WLAN_EID_EXT_FILS_PUBLIC_KEY = 12,
WLAN_EID_EXT_FILS_NONCE = 13,
WLAN_EID_EXT_FUTURE_CHAN_GUIDANCE = 14,
};
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
#define WLAN_EID_EXT_HE_CAPABILITY 35
#define WLAN_EID_EXT_HE_OPERATION 36
#define WLAN_EID_EXT_UORA 37
#define WLAN_EID_EXT_HE_MU_EDCA 38
#define WLAN_EID_EXT_HE_SPR 39
#define WLAN_EID_EXT_NDP_FEEDBACK_REPORT_PARAMSET 41
#define WLAN_EID_EXT_BSS_COLOR_CHG_ANN 42
#define WLAN_EID_EXT_QUIET_TIME_PERIOD_SETUP 43
#define WLAN_EID_EXT_ESS_REPORT 45
#define WLAN_EID_EXT_OPS 46
#define WLAN_EID_EXT_HE_BSS_LOAD 47
#define WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME 52
#define WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION 55
#define WLAN_EID_EXT_NON_INHERITANCE 56
#define WLAN_EID_EXT_KNOWN_BSSID 57
#define WLAN_EID_EXT_SHORT_SSID_LIST 58
#define WLAN_EID_EXT_HE_6GHZ_CAPA 59
#define WLAN_EID_EXT_UL_MU_POWER_CAPA 60
#define WLAN_EID_EXT_EHT_OPERATION 106
#define WLAN_EID_EXT_EHT_MULTI_LINK 107
#define WLAN_EID_EXT_EHT_CAPABILITY 108
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
#include <linux/ieee80211.h>
#else
struct ieee80211_he_cap_elem {
u8 mac_cap_info[6];
u8 phy_cap_info[11];
} __packed;
struct ieee80211_he_mcs_nss_supp {
__le16 rx_mcs_80;
__le16 tx_mcs_80;
__le16 rx_mcs_160;
__le16 tx_mcs_160;
__le16 rx_mcs_80p80;
__le16 tx_mcs_80p80;
} __packed;
struct ieee80211_sta_he_cap {
bool has_he;
struct ieee80211_he_cap_elem he_cap_elem;
struct ieee80211_he_mcs_nss_supp he_mcs_nss_supp;
u8 ppe_thres[IEEE80211_HE_PPE_THRES_MAX_LEN];
};
struct ieee80211_sband_iftype_data {
u16 types_mask;
struct ieee80211_sta_he_cap he_cap;
};
#endif
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) || defined(CONFIG_VHT_FOR_OLD_KERNEL)
struct ieee80211_vht_mcs_info {
__le16 rx_mcs_map;
__le16 rx_highest;
__le16 tx_mcs_map;
__le16 tx_highest;
} __packed;
struct ieee80211_vht_cap {
__le32 vht_cap_info;
struct ieee80211_vht_mcs_info supp_mcs;
};
#define WLAN_EID_VHT_CAPABILITY 191
struct ieee80211_sta_vht_cap {
bool vht_supported;
u32 cap; /* use IEEE80211_VHT_CAP_ */
struct ieee80211_vht_mcs_info vht_mcs;
};
#endif
#endif // LMAC_MAC_H_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,62 @@
/**
****************************************************************************************
*
* @file co_types.h
*
* @brief This file replaces the need to include stdint or stdbool typical headers,
* which may not be available in all toolchains, and adds new types
*
* Copyright (C) RivieraWaves 2009-2019
*
* $Rev: $
*
****************************************************************************************
*/
#ifndef _LMAC_INT_H_
#define _LMAC_INT_H_
/**
****************************************************************************************
* @addtogroup CO_INT
* @ingroup COMMON
* @brief Common integer standard types (removes use of stdint)
*
* @{
****************************************************************************************
*/
/*
* DEFINES
****************************************************************************************
*/
#include <linux/version.h>
#include <linux/types.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
#include <linux/bits.h>
#else
#include <linux/bitops.h>
#endif
#ifdef CONFIG_RWNX_TL4
typedef uint16_t u8_l;
typedef int16_t s8_l;
typedef uint16_t bool_l;
#else
typedef uint8_t u8_l;
typedef int8_t s8_l;
typedef bool bool_l;
#endif
typedef uint16_t u16_l;
typedef int16_t s16_l;
typedef uint32_t u32_l;
typedef int32_t s32_l;
typedef uint64_t u64_l;
/// @} CO_INT
#endif // _LMAC_INT_H_

View File

@ -0,0 +1,161 @@
#include <linux/memory.h>
#include "md5.h"
unsigned char PADDING[]={0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
void MD5Init(MD5_CTX *context)
{
context->count[0] = 0;
context->count[1] = 0;
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
}
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen)
{
unsigned int i = 0,index = 0,partlen = 0;
index = (context->count[0] >> 3) & 0x3F;
partlen = 64 - index;
context->count[0] += inputlen << 3;
if(context->count[0] < (inputlen << 3))
context->count[1]++;
context->count[1] += inputlen >> 29;
if(inputlen >= partlen)
{
memcpy(&context->buffer[index],input,partlen);
MD5Transform(context->state,context->buffer);
for(i = partlen;i+64 <= inputlen;i+=64)
MD5Transform(context->state,&input[i]);
index = 0;
}
else
{
i = 0;
}
memcpy(&context->buffer[index],&input[i],inputlen-i);
}
void MD5Final(MD5_CTX *context,unsigned char digest[16])
{
unsigned int index = 0,padlen = 0;
unsigned char bits[8];
index = (context->count[0] >> 3) & 0x3F;
padlen = (index < 56)?(56-index):(120-index);
MD5Encode(bits,context->count,8);
MD5Update(context,PADDING,padlen);
MD5Update(context,bits,8);
MD5Encode(digest,context->state,16);
}
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)
{
unsigned int i = 0,j = 0;
while(j < len)
{
output[j] = input[i] & 0xFF;
output[j+1] = (input[i] >> 8) & 0xFF;
output[j+2] = (input[i] >> 16) & 0xFF;
output[j+3] = (input[i] >> 24) & 0xFF;
i++;
j+=4;
}
}
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)
{
unsigned int i = 0,j = 0;
while(j < len)
{
output[i] = (input[j]) |
(input[j+1] << 8) |
(input[j+2] << 16) |
(input[j+3] << 24);
i++;
j+=4;
}
}
void MD5Transform(unsigned int state[4],unsigned char block[64])
{
unsigned int a = state[0];
unsigned int b = state[1];
unsigned int c = state[2];
unsigned int d = state[3];
unsigned int x[64];
MD5Decode(x,block,64);
FF(a, b, c, d, x[ 0], 7, 0xd76aa478); /* 1 */
FF(d, a, b, c, x[ 1], 12, 0xe8c7b756); /* 2 */
FF(c, d, a, b, x[ 2], 17, 0x242070db); /* 3 */
FF(b, c, d, a, x[ 3], 22, 0xc1bdceee); /* 4 */
FF(a, b, c, d, x[ 4], 7, 0xf57c0faf); /* 5 */
FF(d, a, b, c, x[ 5], 12, 0x4787c62a); /* 6 */
FF(c, d, a, b, x[ 6], 17, 0xa8304613); /* 7 */
FF(b, c, d, a, x[ 7], 22, 0xfd469501); /* 8 */
FF(a, b, c, d, x[ 8], 7, 0x698098d8); /* 9 */
FF(d, a, b, c, x[ 9], 12, 0x8b44f7af); /* 10 */
FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
/* Round 2 */
GG(a, b, c, d, x[ 1], 5, 0xf61e2562); /* 17 */
GG(d, a, b, c, x[ 6], 9, 0xc040b340); /* 18 */
GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa); /* 20 */
GG(a, b, c, d, x[ 5], 5, 0xd62f105d); /* 21 */
GG(d, a, b, c, x[10], 9, 0x2441453); /* 22 */
GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8); /* 24 */
GG(a, b, c, d, x[ 9], 5, 0x21e1cde6); /* 25 */
GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
GG(c, d, a, b, x[ 3], 14, 0xf4d50d87); /* 27 */
GG(b, c, d, a, x[ 8], 20, 0x455a14ed); /* 28 */
GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8); /* 30 */
GG(c, d, a, b, x[ 7], 14, 0x676f02d9); /* 31 */
GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH(a, b, c, d, x[ 5], 4, 0xfffa3942); /* 33 */
HH(d, a, b, c, x[ 8], 11, 0x8771f681); /* 34 */
HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
HH(a, b, c, d, x[ 1], 4, 0xa4beea44); /* 37 */
HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9); /* 38 */
HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60); /* 39 */
HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
HH(d, a, b, c, x[ 0], 11, 0xeaa127fa); /* 42 */
HH(c, d, a, b, x[ 3], 16, 0xd4ef3085); /* 43 */
HH(b, c, d, a, x[ 6], 23, 0x4881d05); /* 44 */
HH(a, b, c, d, x[ 9], 4, 0xd9d4d039); /* 45 */
HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
HH(b, c, d, a, x[ 2], 23, 0xc4ac5665); /* 48 */
/* Round 4 */
II(a, b, c, d, x[ 0], 6, 0xf4292244); /* 49 */
II(d, a, b, c, x[ 7], 10, 0x432aff97); /* 50 */
II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
II(b, c, d, a, x[ 5], 21, 0xfc93a039); /* 52 */
II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
II(d, a, b, c, x[ 3], 10, 0x8f0ccc92); /* 54 */
II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
II(b, c, d, a, x[ 1], 21, 0x85845dd1); /* 56 */
II(a, b, c, d, x[ 8], 6, 0x6fa87e4f); /* 57 */
II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
II(c, d, a, b, x[ 6], 15, 0xa3014314); /* 59 */
II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
II(a, b, c, d, x[ 4], 6, 0xf7537e82); /* 61 */
II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb); /* 63 */
II(b, c, d, a, x[ 9], 21, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}

View File

@ -0,0 +1,48 @@
#ifndef MD5_H
#define MD5_H
typedef struct
{
unsigned int count[2];
unsigned int state[4];
unsigned char buffer[64];
}MD5_CTX;
#define F(x,y,z) ((x & y) | (~x & z))
#define G(x,y,z) ((x & z) | (y & ~z))
#define H(x,y,z) (x^y^z)
#define I(x,y,z) (y ^ (x | ~z))
#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))
#define FF(a,b,c,d,x,s,ac) \
{ \
a += F(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define GG(a,b,c,d,x,s,ac) \
{ \
a += G(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define HH(a,b,c,d,x,s,ac) \
{ \
a += H(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
#define II(a,b,c,d,x,s,ac) \
{ \
a += I(b,c,d) + x + ac; \
a = ROTATE_LEFT(a,s); \
a += b; \
}
void MD5Init(MD5_CTX *context);
void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen);
void MD5Final(MD5_CTX *context,unsigned char digest[16]);
void MD5Transform(unsigned int state[4],unsigned char block[64]);
void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len);
void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len);
#endif

View File

@ -0,0 +1,148 @@
/**
******************************************************************************
*
* @file reg_access.h
*
* @brief Definitions and macros for MAC HW and platform register accesses
*
* Copyright (C) RivieraWaves 2011-2019
*
******************************************************************************
*/
#ifndef REG_ACCESS_H_
#define REG_ACCESS_H_
/*****************************************************************************
* Addresses within RWNX_ADDR_SYSTEM
*****************************************************************************/
/* Shard RAM */
#define SHARED_RAM_START_ADDR 0x00000000
/* IPC registers */
#define IPC_REG_BASE_ADDR 0x00800000
/* System Controller Registers */
#define SYSCTRL_SIGNATURE_ADDR 0x00900000
// old diag register name
#define SYSCTRL_DIAG_CONF_ADDR 0x00900068
#define SYSCTRL_PHYDIAG_CONF_ADDR 0x00900074
#define SYSCTRL_RIUDIAG_CONF_ADDR 0x00900078
// new diag register name
#define SYSCTRL_DIAG_CONF0 0x00900064
#define SYSCTRL_DIAG_CONF1 0x00900068
#define SYSCTRL_DIAG_CONF2 0x00900074
#define SYSCTRL_DIAG_CONF3 0x00900078
#define SYSCTRL_MISC_CNTL_ADDR 0x009000E0
#define BOOTROM_ENABLE BIT(4)
#define FPGA_B_RESET BIT(1)
#define SOFT_RESET BIT(0)
/* MAC platform */
#define NXMAC_VERSION_1_ADDR 0x00B00004
#define NXMAC_MU_MIMO_TX_BIT BIT(19)
#define NXMAC_BFMER_BIT BIT(18)
#define NXMAC_BFMEE_BIT BIT(17)
#define NXMAC_MAC_80211MH_FORMAT_BIT BIT(16)
#define NXMAC_COEX_BIT BIT(14)
#define NXMAC_WAPI_BIT BIT(13)
#define NXMAC_TPC_BIT BIT(12)
#define NXMAC_VHT_BIT BIT(11)
#define NXMAC_HT_BIT BIT(10)
#define NXMAC_RCE_BIT BIT(8)
#define NXMAC_CCMP_BIT BIT(7)
#define NXMAC_TKIP_BIT BIT(6)
#define NXMAC_WEP_BIT BIT(5)
#define NXMAC_SECURITY_BIT BIT(4)
#define NXMAC_SME_BIT BIT(3)
#define NXMAC_HCCA_BIT BIT(2)
#define NXMAC_EDCA_BIT BIT(1)
#define NXMAC_QOS_BIT BIT(0)
#define NXMAC_RX_CNTRL_ADDR 0x00B00060
#define NXMAC_EN_DUPLICATE_DETECTION_BIT BIT(31)
#define NXMAC_ACCEPT_UNKNOWN_BIT BIT(30)
#define NXMAC_ACCEPT_OTHER_DATA_FRAMES_BIT BIT(29)
#define NXMAC_ACCEPT_QO_S_NULL_BIT BIT(28)
#define NXMAC_ACCEPT_QCFWO_DATA_BIT BIT(27)
#define NXMAC_ACCEPT_Q_DATA_BIT BIT(26)
#define NXMAC_ACCEPT_CFWO_DATA_BIT BIT(25)
#define NXMAC_ACCEPT_DATA_BIT BIT(24)
#define NXMAC_ACCEPT_OTHER_CNTRL_FRAMES_BIT BIT(23)
#define NXMAC_ACCEPT_CF_END_BIT BIT(22)
#define NXMAC_ACCEPT_ACK_BIT BIT(21)
#define NXMAC_ACCEPT_CTS_BIT BIT(20)
#define NXMAC_ACCEPT_RTS_BIT BIT(19)
#define NXMAC_ACCEPT_PS_POLL_BIT BIT(18)
#define NXMAC_ACCEPT_BA_BIT BIT(17)
#define NXMAC_ACCEPT_BAR_BIT BIT(16)
#define NXMAC_ACCEPT_OTHER_MGMT_FRAMES_BIT BIT(15)
#define NXMAC_ACCEPT_BFMEE_FRAMES_BIT BIT(14)
#define NXMAC_ACCEPT_ALL_BEACON_BIT BIT(13)
#define NXMAC_ACCEPT_NOT_EXPECTED_BA_BIT BIT(12)
#define NXMAC_ACCEPT_DECRYPT_ERROR_FRAMES_BIT BIT(11)
#define NXMAC_ACCEPT_BEACON_BIT BIT(10)
#define NXMAC_ACCEPT_PROBE_RESP_BIT BIT(9)
#define NXMAC_ACCEPT_PROBE_REQ_BIT BIT(8)
#define NXMAC_ACCEPT_MY_UNICAST_BIT BIT(7)
#define NXMAC_ACCEPT_UNICAST_BIT BIT(6)
#define NXMAC_ACCEPT_ERROR_FRAMES_BIT BIT(5)
#define NXMAC_ACCEPT_OTHER_BSSID_BIT BIT(4)
#define NXMAC_ACCEPT_BROADCAST_BIT BIT(3)
#define NXMAC_ACCEPT_MULTICAST_BIT BIT(2)
#define NXMAC_DONT_DECRYPT_BIT BIT(1)
#define NXMAC_EXC_UNENCRYPTED_BIT BIT(0)
#define NXMAC_DEBUG_PORT_SEL_ADDR 0x00B00510
#define NXMAC_SW_SET_PROFILING_ADDR 0x00B08564
#define NXMAC_SW_CLEAR_PROFILING_ADDR 0x00B08568
/* Modem Status */
#define MDM_HDMCONFIG_ADDR 0x00C00000
/* Clock gating configuration */
#define MDM_MEMCLKCTRL0_ADDR 0x00C00848
#define MDM_CLKGATEFCTRL0_ADDR 0x00C00874
#define CRM_CLKGATEFCTRL0_ADDR 0x00940010
/* AGC (trident) */
#define AGC_RWNXAGCCNTL_ADDR 0x00C02060
/* LDPC RAM*/
#define PHY_LDPC_RAM_ADDR 0x00C09000
/* FCU (elma )*/
#define FCU_RWNXFCAGCCNTL_ADDR 0x00C09034
/* AGC RAM */
#define PHY_AGC_UCODE_ADDR 0x00C0A000
/* RIU */
#define RIU_RWNXVERSION_ADDR 0x00C0B000
#define RIU_RWNXDYNAMICCONFIG_ADDR 0x00C0B008
#define RIU_AGCMEMBISTSTAT_ADDR 0x00C0B238
#define RIU_AGCMEMSIGNATURESTAT_ADDR 0x00C0B23C
#define RIU_RWNXAGCCNTL_ADDR 0x00C0B390
/* FCU RAM */
#define PHY_FCU_UCODE_ADDR 0x00C0E000
/* RF ITF */
#define FPGAB_MPIF_SEL_ADDR 0x00C10030
#define RF_V6_DIAGPORT_CONF1_ADDR 0x00C10010
#define RF_v6_PHYDIAG_CONF1_ADDR 0x00C10018
#define RF_V7_DIAGPORT_CONF1_ADDR 0x00F10010
#define RF_v7_PHYDIAG_CONF1_ADDR 0x00F10018
/*****************************************************************************
* Macros for generated register files
*****************************************************************************/
/* Macros for IPC registers access (used in reg_ipc_app.h) */
#define REG_IPC_APP_RD(env, INDEX) \
(*(volatile u32 *)((u8 *)env + IPC_REG_BASE_ADDR + 4 * (INDEX)))
#define REG_IPC_APP_WR(env, INDEX, value) \
(*(volatile u32 *)((u8 *)env + IPC_REG_BASE_ADDR + 4 * (INDEX)) = value)
#endif /* REG_ACCESS_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,105 @@
/**
******************************************************************************
*
* @file rwnx_bfmer.c
*
* @brief VHT Beamformer function definitions
*
* Copyright (C) RivieraWaves 2016-2019
*
******************************************************************************
*/
/**
* INCLUDE FILES
******************************************************************************
*/
#include <linux/slab.h>
#include "rwnx_bfmer.h"
/**
* FUNCTION DEFINITIONS
******************************************************************************
*/
int rwnx_bfmer_report_add(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta,
unsigned int length)
{
gfp_t flags;
struct rwnx_bfmer_report *bfm_report ;
if (in_softirq())
flags = GFP_ATOMIC;
else
flags = GFP_KERNEL;
/* Allocate a structure that will contain the beamforming report */
bfm_report = kmalloc(sizeof(*bfm_report) + length, flags);
/* Check report allocation */
if (!bfm_report) {
/* Do not use beamforming */
return -1;
}
/* Store report length */
bfm_report->length = length;
/*
* Need to provide a Virtual Address to the MAC so that it can
* upload the received Beamforming Report in driver memory
*/
bfm_report->dma_addr = dma_map_single(rwnx_hw->dev, &bfm_report->report[0],
length, DMA_FROM_DEVICE);
/* Check DMA mapping result */
if (dma_mapping_error(rwnx_hw->dev, bfm_report->dma_addr)) {
/* Free allocated report */
kfree(bfm_report);
/* And leave */
return -1;
}
/* Store report structure */
rwnx_sta->bfm_report = bfm_report;
return 0;
}
void rwnx_bfmer_report_del(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta)
{
/* Verify if a report has been allocated */
if (rwnx_sta->bfm_report) {
struct rwnx_bfmer_report *bfm_report = rwnx_sta->bfm_report;
/* Unmap DMA region */
dma_unmap_single(rwnx_hw->dev, bfm_report->dma_addr,
bfm_report->length, DMA_BIDIRECTIONAL);
/* Free allocated report structure and clean the pointer */
kfree(bfm_report);
rwnx_sta->bfm_report = NULL;
}
}
#ifdef CONFIG_RWNX_FULLMAC
u8 rwnx_bfmer_get_rx_nss(const struct ieee80211_vht_cap *vht_capa)
{
int i;
u8 rx_nss = 0;
u16 rx_mcs_map = le16_to_cpu(vht_capa->supp_mcs.rx_mcs_map);
for (i = 7; i >= 0; i--) {
u8 mcs = (rx_mcs_map >> (2 * i)) & 3;
if (mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
rx_nss = i + 1;
break;
}
}
return rx_nss;
}
#endif /* CONFIG_RWNX_FULLMAC */

View File

@ -0,0 +1,100 @@
/**
******************************************************************************
*
* @file rwnx_bfmer.h
*
* @brief VHT Beamformer function declarations
*
* Copyright (C) RivieraWaves 2016-2019
*
******************************************************************************
*/
#ifndef _RWNX_BFMER_H_
#define _RWNX_BFMER_H_
/**
* INCLUDE FILES
******************************************************************************
*/
#include "rwnx_defs.h"
/**
* DEFINES
******************************************************************************
*/
/// Maximal supported report length (in bytes)
#define RWNX_BFMER_REPORT_MAX_LEN 2048
/// Size of the allocated report space (twice the maximum report length)
#define RWNX_BFMER_REPORT_SPACE_SIZE (RWNX_BFMER_REPORT_MAX_LEN * 2)
/**
* TYPE DEFINITIONS
******************************************************************************
*/
/*
* Structure used to store a beamforming report.
*/
struct rwnx_bfmer_report {
dma_addr_t dma_addr; /* Virtual address provided to MAC for
DMA transfer of the Beamforming Report */
unsigned int length; /* Report Length */
u8 report[1]; /* Report to be used for VHT TX Beamforming */
};
/**
* FUNCTION DECLARATIONS
******************************************************************************
*/
/**
******************************************************************************
* @brief Allocate memory aiming to contains the Beamforming Report received
* from a Beamformee capable capable.
* The providing length shall be large enough to contain the VHT Compressed
* Beaforming Report and the MU Exclusive part.
* It also perform a DMA Mapping providing an address to be provided to the HW
* responsible for the DMA transfer of the report.
* If successful a struct rwnx_bfmer_report object is allocated, it's address
* is stored in rwnx_sta->bfm_report.
*
* @param[in] rwnx_hw PHY Information
* @param[in] rwnx_sta Peer STA Information
* @param[in] length Memory size to be allocated
*
* @return 0 if operation is successful, else -1.
******************************************************************************
*/
int rwnx_bfmer_report_add(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta,
unsigned int length);
/**
******************************************************************************
* @brief Free a previously allocated memory intended to be used for
* Beamforming Reports.
*
* @param[in] rwnx_hw PHY Information
* @param[in] rwnx_sta Peer STA Information
*
******************************************************************************
*/
void rwnx_bfmer_report_del(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta);
#ifdef CONFIG_RWNX_FULLMAC
/**
******************************************************************************
* @brief Parse a Rx VHT-MCS map in order to deduce the maximum number of
* Spatial Streams supported by a beamformee.
*
* @param[in] vht_capa Received VHT Capability field.
*
******************************************************************************
*/
u8 rwnx_bfmer_get_rx_nss(const struct ieee80211_vht_cap *vht_capa);
#endif /* CONFIG_RWNX_FULLMAC */
#endif /* _RWNX_BFMER_H_ */

View File

@ -0,0 +1,239 @@
/**
****************************************************************************************
*
* @file rwnx_configparse.c
*
* Copyright (C) RivieraWaves 2012-2019
*
****************************************************************************************
*/
#include <linux/firmware.h>
#include <linux/if_ether.h>
#include "rwnx_defs.h"
#include "rwnx_cfgfile.h"
/**
*
*/
static const char *rwnx_find_tag(const u8 *file_data, unsigned int file_size,
const char *tag_name, unsigned int tag_len)
{
unsigned int curr, line_start = 0, line_size;
RWNX_DBG(RWNX_FN_ENTRY_STR);
/* Walk through all the lines of the configuration file */
while (line_start < file_size) {
/* Search the end of the current line (or the end of the file) */
for (curr = line_start; curr < file_size; curr++)
if (file_data[curr] == '\n')
break;
/* Compute the line size */
line_size = curr - line_start;
/* Check if this line contains the expected tag */
if ((line_size == (strlen(tag_name) + tag_len)) &&
(!strncmp(&file_data[line_start], tag_name, strlen(tag_name))))
return &file_data[line_start + strlen(tag_name)];
/* Move to next line */
line_start = curr + 1;
}
/* Tag not found */
return NULL;
}
/**
* Parse the Config file used at init time
*/
int rwnx_parse_configfile(struct rwnx_hw *rwnx_hw, const char *filename,
struct rwnx_conf_file *config)
{
const struct firmware *config_fw;
u8 dflt_mac[ETH_ALEN] = { 0, 111, 111, 111, 111, 0 };
int ret;
const u8 *tag_ptr;
RWNX_DBG(RWNX_FN_ENTRY_STR);
ret = request_firmware(&config_fw, filename, rwnx_hw->dev);
if (ret) {
printk(KERN_CRIT "%s: Failed to get %s (%d)\n", __func__, filename, ret);
return ret;
}
/* Get MAC Address */
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
"MAC_ADDR=", strlen("00:00:00:00:00:00"));
if (tag_ptr != NULL) {
u8 *addr = config->mac_addr;
if (sscanf(tag_ptr,
"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
addr + 0, addr + 1, addr + 2,
addr + 3, addr + 4, addr + 5) != ETH_ALEN)
memcpy(config->mac_addr, dflt_mac, ETH_ALEN);
} else
memcpy(config->mac_addr, dflt_mac, ETH_ALEN);
RWNX_DBG("MAC Address is:\n%pM\n", config->mac_addr);
/* Release the configuration file */
release_firmware(config_fw);
return 0;
}
/**
* Parse the Config file used at init time
*/
int rwnx_parse_phy_configfile(struct rwnx_hw *rwnx_hw, const char *filename,
struct rwnx_phy_conf_file *config, int path)
{
const struct firmware *config_fw;
int ret;
const u8 *tag_ptr;
RWNX_DBG(RWNX_FN_ENTRY_STR);
ret = request_firmware(&config_fw, filename, rwnx_hw->dev);
if (ret) {
printk(KERN_CRIT "%s: Failed to get %s (%d)\n", __func__, filename, ret);
return ret;
}
/* Get Trident path mapping */
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
"TRD_PATH_MAPPING=", strlen("00"));
if (tag_ptr != NULL) {
u8 val;
if (sscanf(tag_ptr, "%hhx", &val) == 1)
config->trd.path_mapping = val;
else
config->trd.path_mapping = path;
} else
config->trd.path_mapping = path;
RWNX_DBG("Trident path mapping is: %d\n", config->trd.path_mapping);
/* Get DC offset compensation */
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
"TX_DC_OFF_COMP=", strlen("00000000"));
if (tag_ptr != NULL) {
if (sscanf(tag_ptr, "%08x", &config->trd.tx_dc_off_comp) != 1)
config->trd.tx_dc_off_comp = 0;
} else
config->trd.tx_dc_off_comp = 0;
RWNX_DBG("TX DC offset compensation is: %08X\n", config->trd.tx_dc_off_comp);
/* Get Karst TX IQ compensation value for path0 on 2.4GHz */
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
"KARST_TX_IQ_COMP_2_4G_PATH_0=", strlen("00000000"));
if (tag_ptr != NULL) {
if (sscanf(tag_ptr, "%08x", &config->karst.tx_iq_comp_2_4G[0]) != 1)
config->karst.tx_iq_comp_2_4G[0] = 0x01000000;
} else
config->karst.tx_iq_comp_2_4G[0] = 0x01000000;
RWNX_DBG("Karst TX IQ compensation for path 0 on 2.4GHz is: %08X\n", config->karst.tx_iq_comp_2_4G[0]);
/* Get Karst TX IQ compensation value for path1 on 2.4GHz */
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
"KARST_TX_IQ_COMP_2_4G_PATH_1=", strlen("00000000"));
if (tag_ptr != NULL) {
if (sscanf(tag_ptr, "%08x", &config->karst.tx_iq_comp_2_4G[1]) != 1)
config->karst.tx_iq_comp_2_4G[1] = 0x01000000;
} else
config->karst.tx_iq_comp_2_4G[1] = 0x01000000;
RWNX_DBG("Karst TX IQ compensation for path 1 on 2.4GHz is: %08X\n", config->karst.tx_iq_comp_2_4G[1]);
/* Get Karst RX IQ compensation value for path0 on 2.4GHz */
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
"KARST_RX_IQ_COMP_2_4G_PATH_0=", strlen("00000000"));
if (tag_ptr != NULL) {
if (sscanf(tag_ptr, "%08x", &config->karst.rx_iq_comp_2_4G[0]) != 1)
config->karst.rx_iq_comp_2_4G[0] = 0x01000000;
} else
config->karst.rx_iq_comp_2_4G[0] = 0x01000000;
RWNX_DBG("Karst RX IQ compensation for path 0 on 2.4GHz is: %08X\n", config->karst.rx_iq_comp_2_4G[0]);
/* Get Karst RX IQ compensation value for path1 on 2.4GHz */
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
"KARST_RX_IQ_COMP_2_4G_PATH_1=", strlen("00000000"));
if (tag_ptr != NULL) {
if (sscanf(tag_ptr, "%08x", &config->karst.rx_iq_comp_2_4G[1]) != 1)
config->karst.rx_iq_comp_2_4G[1] = 0x01000000;
} else
config->karst.rx_iq_comp_2_4G[1] = 0x01000000;
RWNX_DBG("Karst RX IQ compensation for path 1 on 2.4GHz is: %08X\n", config->karst.rx_iq_comp_2_4G[1]);
/* Get Karst TX IQ compensation value for path0 on 5GHz */
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
"KARST_TX_IQ_COMP_5G_PATH_0=", strlen("00000000"));
if (tag_ptr != NULL) {
if (sscanf(tag_ptr, "%08x", &config->karst.tx_iq_comp_5G[0]) != 1)
config->karst.tx_iq_comp_5G[0] = 0x01000000;
} else
config->karst.tx_iq_comp_5G[0] = 0x01000000;
RWNX_DBG("Karst TX IQ compensation for path 0 on 5GHz is: %08X\n", config->karst.tx_iq_comp_5G[0]);
/* Get Karst TX IQ compensation value for path1 on 5GHz */
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
"KARST_TX_IQ_COMP_5G_PATH_1=", strlen("00000000"));
if (tag_ptr != NULL) {
if (sscanf(tag_ptr, "%08x", &config->karst.tx_iq_comp_5G[1]) != 1)
config->karst.tx_iq_comp_5G[1] = 0x01000000;
} else
config->karst.tx_iq_comp_5G[1] = 0x01000000;
RWNX_DBG("Karst TX IQ compensation for path 1 on 5GHz is: %08X\n", config->karst.tx_iq_comp_5G[1]);
/* Get Karst RX IQ compensation value for path0 on 5GHz */
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
"KARST_RX_IQ_COMP_5G_PATH_0=", strlen("00000000"));
if (tag_ptr != NULL) {
if (sscanf(tag_ptr, "%08x", &config->karst.rx_iq_comp_5G[0]) != 1)
config->karst.rx_iq_comp_5G[0] = 0x01000000;
} else
config->karst.rx_iq_comp_5G[0] = 0x01000000;
RWNX_DBG("Karst RX IQ compensation for path 0 on 5GHz is: %08X\n", config->karst.rx_iq_comp_5G[0]);
/* Get Karst RX IQ compensation value for path1 on 5GHz */
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
"KARST_RX_IQ_COMP_5G_PATH_1=", strlen("00000000"));
if (tag_ptr != NULL) {
if (sscanf(tag_ptr, "%08x", &config->karst.rx_iq_comp_5G[1]) != 1)
config->karst.rx_iq_comp_5G[1] = 0x01000000;
} else
config->karst.rx_iq_comp_5G[1] = 0x01000000;
RWNX_DBG("Karst RX IQ compensation for path 1 on 5GHz is: %08X\n", config->karst.rx_iq_comp_5G[1]);
/* Get Karst default path */
tag_ptr = rwnx_find_tag(config_fw->data, config_fw->size,
"KARST_DEFAULT_PATH=", strlen("00"));
if (tag_ptr != NULL) {
u8 val;
if (sscanf(tag_ptr, "%hhx", &val) == 1)
config->karst.path_used = val;
else
config->karst.path_used = path;
} else
config->karst.path_used = path;
RWNX_DBG("Karst default path is: %d\n", config->karst.path_used);
/* Release the configuration file */
release_firmware(config_fw);
return 0;
}

View File

@ -0,0 +1,35 @@
/**
****************************************************************************************
*
* @file rwnx_cfgfile.h
*
* Copyright (C) RivieraWaves 2012-2019
*
****************************************************************************************
*/
#ifndef _RWNX_CFGFILE_H_
#define _RWNX_CFGFILE_H_
/*
* Structure used to retrieve information from the Config file used at Initialization time
*/
struct rwnx_conf_file {
u8 mac_addr[ETH_ALEN];
};
/*
* Structure used to retrieve information from the PHY Config file used at Initialization time
*/
struct rwnx_phy_conf_file {
struct phy_trd_cfg_tag trd;
struct phy_karst_cfg_tag karst;
};
int rwnx_parse_configfile(struct rwnx_hw *rwnx_hw, const char *filename,
struct rwnx_conf_file *config);
int rwnx_parse_phy_configfile(struct rwnx_hw *rwnx_hw, const char *filename,
struct rwnx_phy_conf_file *config, int path);
#endif /* _RWNX_CFGFILE_H_ */

View File

@ -0,0 +1,539 @@
/**
******************************************************************************
*
* rwnx_cmds.c
*
* Handles queueing (push to IPC, ack/cfm from IPC) of commands issued to
* LMAC FW
*
* Copyright (C) RivieraWaves 2014-2019
*
******************************************************************************
*/
#include <linux/list.h>
#include "rwnx_cmds.h"
#include "rwnx_defs.h"
#include "rwnx_strs.h"
//#define CREATE_TRACE_POINTS
#include "rwnx_events.h"
#include "aicwf_txrxif.h"
#ifdef AICWF_SDIO_SUPPORT
#include "aicwf_sdio.h"
#else
#include "aicwf_usb.h"
#endif
/**
*
*/
extern int aicwf_sdio_writeb(struct aic_sdio_dev *sdiodev, uint regaddr, u8 val);
void rwnx_cmd_free(struct rwnx_cmd *cmd);
static void cmd_dump(const struct rwnx_cmd *cmd)
{
printk(KERN_CRIT "tkn[%d] flags:%04x result:%3d cmd:%4d-%-24s - reqcfm(%4d-%-s)\n",
cmd->tkn, cmd->flags, cmd->result, cmd->id, RWNX_ID2STR(cmd->id),
cmd->reqid, cmd->reqid != (lmac_msg_id_t)-1 ? RWNX_ID2STR(cmd->reqid) : "none");
}
/**
*
*/
static void cmd_complete(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
{
//RWNX_DBG(RWNX_FN_ENTRY_STR);
lockdep_assert_held(&cmd_mgr->lock);
list_del(&cmd->list);
cmd_mgr->queue_sz--;
cmd->flags |= RWNX_CMD_FLAG_DONE;
if (cmd->flags & RWNX_CMD_FLAG_NONBLOCK) {
rwnx_cmd_free(cmd);//kfree(cmd);
} else {
if (RWNX_CMD_WAIT_COMPLETE(cmd->flags)) {
cmd->result = 0;
complete(&cmd->complete);
}
}
}
int cmd_mgr_queue_force_defer(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
{
bool defer_push = false;
RWNX_DBG(RWNX_FN_ENTRY_STR);
#ifdef CREATE_TRACE_POINTS
trace_msg_send(cmd->id);
#endif
spin_lock_bh(&cmd_mgr->lock);
if (cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) {
printk(KERN_CRIT"cmd queue crashed\n");
cmd->result = -EPIPE;
spin_unlock_bh(&cmd_mgr->lock);
return -EPIPE;
}
#ifndef CONFIG_RWNX_FHOST
if (!list_empty(&cmd_mgr->cmds)) {
if (cmd_mgr->queue_sz == cmd_mgr->max_queue_sz) {
printk(KERN_CRIT"Too many cmds (%d) already queued\n",
cmd_mgr->max_queue_sz);
cmd->result = -ENOMEM;
spin_unlock_bh(&cmd_mgr->lock);
return -ENOMEM;
}
}
#endif
cmd->flags |= RWNX_CMD_FLAG_WAIT_PUSH;
defer_push = true;
if (cmd->flags & RWNX_CMD_FLAG_REQ_CFM)
cmd->flags |= RWNX_CMD_FLAG_WAIT_CFM;
cmd->tkn = cmd_mgr->next_tkn++;
cmd->result = -EINTR;
if (!(cmd->flags & RWNX_CMD_FLAG_NONBLOCK))
init_completion(&cmd->complete);
list_add_tail(&cmd->list, &cmd_mgr->cmds);
cmd_mgr->queue_sz++;
spin_unlock_bh(&cmd_mgr->lock);
WAKE_CMD_WORK(cmd_mgr);
return 0;
}
static int cmd_mgr_queue(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
{
#ifdef AICWF_SDIO_SUPPORT
int ret;
struct aic_sdio_dev *sdiodev = container_of(cmd_mgr, struct aic_sdio_dev, cmd_mgr);
#endif
#ifdef AICWF_USB_SUPPORT
struct aic_usb_dev *usbdev = container_of(cmd_mgr, struct aic_usb_dev, cmd_mgr);
#endif
bool defer_push = false;
//RWNX_DBG(RWNX_FN_ENTRY_STR);
#ifdef CREATE_TRACE_POINTS
trace_msg_send(cmd->id);
#endif
spin_lock_bh(&cmd_mgr->lock);
if (cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) {
printk(KERN_CRIT"cmd queue crashed\n");
cmd->result = -EPIPE;
spin_unlock_bh(&cmd_mgr->lock);
return -EPIPE;
}
#ifndef CONFIG_RWNX_FHOST
if (!list_empty(&cmd_mgr->cmds)) {
struct rwnx_cmd *last;
if (cmd_mgr->queue_sz == cmd_mgr->max_queue_sz) {
printk(KERN_CRIT"Too many cmds (%d) already queued\n",
cmd_mgr->max_queue_sz);
cmd->result = -ENOMEM;
spin_unlock_bh(&cmd_mgr->lock);
return -ENOMEM;
}
last = list_entry(cmd_mgr->cmds.prev, struct rwnx_cmd, list);
if (last->flags & (RWNX_CMD_FLAG_WAIT_ACK | RWNX_CMD_FLAG_WAIT_PUSH | RWNX_CMD_FLAG_WAIT_CFM)) {
#if 0 // queue even NONBLOCK command.
if (cmd->flags & RWNX_CMD_FLAG_NONBLOCK) {
printk(KERN_CRIT"cmd queue busy\n");
cmd->result = -EBUSY;
spin_unlock_bh(&cmd_mgr->lock);
return -EBUSY;
}
#endif
cmd->flags |= RWNX_CMD_FLAG_WAIT_PUSH;
defer_push = true;
}
}
#endif
#if 0
cmd->flags |= RWNX_CMD_FLAG_WAIT_ACK;
#endif
if (cmd->flags & RWNX_CMD_FLAG_REQ_CFM)
cmd->flags |= RWNX_CMD_FLAG_WAIT_CFM;
cmd->tkn = cmd_mgr->next_tkn++;
cmd->result = -EINTR;
if (!(cmd->flags & RWNX_CMD_FLAG_NONBLOCK))
init_completion(&cmd->complete);
list_add_tail(&cmd->list, &cmd_mgr->cmds);
cmd_mgr->queue_sz++;
if (cmd->a2e_msg->id == ME_TRAFFIC_IND_REQ
#ifdef AICWF_ARP_OFFLOAD
|| cmd->a2e_msg->id == MM_SET_ARPOFFLOAD_REQ
#endif
) {
defer_push = true;
cmd->flags |= RWNX_CMD_FLAG_WAIT_PUSH;
//printk("defer push: tkn=%d\r\n", cmd->tkn);
}
spin_unlock_bh(&cmd_mgr->lock);
if (!defer_push) {
//printk("queue:id=%x, param_len=%u\n",cmd->a2e_msg->id, cmd->a2e_msg->param_len);
#ifdef AICWF_SDIO_SUPPORT
aicwf_set_cmd_tx((void *)(sdiodev), cmd->a2e_msg, sizeof(struct lmac_msg) + cmd->a2e_msg->param_len);
#else
aicwf_set_cmd_tx((void *)(usbdev), cmd->a2e_msg, sizeof(struct lmac_msg) + cmd->a2e_msg->param_len);
#endif
//rwnx_ipc_msg_push(rwnx_hw, cmd, RWNX_CMD_A2EMSG_LEN(cmd->a2e_msg));
kfree(cmd->a2e_msg);
} else {
if(cmd_mgr->queue_sz <= 1){
WAKE_CMD_WORK(cmd_mgr);
}
return 0;
}
if (!(cmd->flags & RWNX_CMD_FLAG_NONBLOCK)) {
#ifdef CONFIG_RWNX_FHOST
if (wait_for_completion_killable(&cmd->complete)) {
cmd->result = -EINTR;
spin_lock_bh(&cmd_mgr->lock);
cmd_complete(cmd_mgr, cmd);
spin_unlock_bh(&cmd_mgr->lock);
/* TODO: kill the cmd at fw level */
}
#else
unsigned long tout = msecs_to_jiffies(RWNX_80211_CMD_TIMEOUT_MS * cmd_mgr->queue_sz);
if (!wait_for_completion_timeout(&cmd->complete, tout)) {
printk(KERN_CRIT"cmd timed-out\n");
#ifdef AICWF_SDIO_SUPPORT
ret = aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.wakeup_reg, 2);
if (ret < 0) {
sdio_err("reg:%d write failed!\n", sdiodev->sdio_reg.wakeup_reg);
}
#endif
cmd_dump(cmd);
spin_lock_bh(&cmd_mgr->lock);
cmd_mgr->state = RWNX_CMD_MGR_STATE_CRASHED;
if (!(cmd->flags & RWNX_CMD_FLAG_DONE)) {
cmd->result = -ETIMEDOUT;
cmd_complete(cmd_mgr, cmd);
}
spin_unlock_bh(&cmd_mgr->lock);
} else {
rwnx_cmd_free(cmd);//kfree(cmd);
if (!list_empty(&cmd_mgr->cmds))
WAKE_CMD_WORK(cmd_mgr);
}
#endif
} else {
cmd->result = 0;
}
return 0;
}
/**
*
*/
static int cmd_mgr_llind(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
{
struct rwnx_cmd *cur, *acked = NULL, *next = NULL;
RWNX_DBG(RWNX_FN_ENTRY_STR);
spin_lock_bh(&cmd_mgr->lock);
list_for_each_entry(cur, &cmd_mgr->cmds, list) {
if (!acked) {
if (cur->tkn == cmd->tkn) {
if (WARN_ON_ONCE(cur != cmd)) {
cmd_dump(cmd);
}
acked = cur;
continue;
}
}
if (cur->flags & RWNX_CMD_FLAG_WAIT_PUSH) {
next = cur;
break;
}
}
if (!acked) {
printk(KERN_CRIT "Error: acked cmd not found\n");
} else {
cmd->flags &= ~RWNX_CMD_FLAG_WAIT_ACK;
if (RWNX_CMD_WAIT_COMPLETE(cmd->flags))
cmd_complete(cmd_mgr, cmd);
}
if (next) {
#if 0 //there is no ack
struct rwnx_hw *rwnx_hw = container_of(cmd_mgr, struct rwnx_hw, cmd_mgr);
next->flags &= ~RWNX_CMD_FLAG_WAIT_PUSH;
rwnx_ipc_msg_push(rwnx_hw, next, RWNX_CMD_A2EMSG_LEN(next->a2e_msg));
kfree(next->a2e_msg);
#endif
}
spin_unlock(&cmd_mgr->lock);
return 0;
}
void cmd_mgr_task_process(struct work_struct *work)
{
struct rwnx_cmd_mgr *cmd_mgr = container_of(work, struct rwnx_cmd_mgr, cmdWork);
struct rwnx_cmd *cur, *next = NULL;
unsigned long tout;
RWNX_DBG(RWNX_FN_ENTRY_STR);
while (1) {
next = NULL;
spin_lock_bh(&cmd_mgr->lock);
list_for_each_entry(cur, &cmd_mgr->cmds, list) {
if (cur->flags & RWNX_CMD_FLAG_WAIT_PUSH) { //just judge the first
next = cur;
}
break;
}
spin_unlock_bh(&cmd_mgr->lock);
if (next == NULL)
break;
if (next) {
#ifdef AICWF_SDIO_SUPPORT
struct aic_sdio_dev *sdiodev = container_of(cmd_mgr, struct aic_sdio_dev, cmd_mgr);
#endif
#ifdef AICWF_USB_SUPPORT
struct aic_usb_dev *usbdev = container_of(cmd_mgr, struct aic_usb_dev, cmd_mgr);
#endif
next->flags &= ~RWNX_CMD_FLAG_WAIT_PUSH;
//printk("cmd_process, cmd->id=%d, tkn=%d\r\n",next->reqid, next->tkn);
//rwnx_ipc_msg_push(rwnx_hw, next, RWNX_CMD_A2EMSG_LEN(next->a2e_msg));
#ifdef AICWF_SDIO_SUPPORT
aicwf_set_cmd_tx((void *)(sdiodev), next->a2e_msg, sizeof(struct lmac_msg) + next->a2e_msg->param_len);
#else
aicwf_set_cmd_tx((void *)(usbdev), next->a2e_msg, sizeof(struct lmac_msg) + next->a2e_msg->param_len);
#endif
kfree(next->a2e_msg);
tout = msecs_to_jiffies(RWNX_80211_CMD_TIMEOUT_MS * cmd_mgr->queue_sz);
if (!wait_for_completion_timeout(&next->complete, tout)) {
printk(KERN_CRIT"cmd timed-out\n");
#ifdef AICWF_SDIO_SUPPORT
if (aicwf_sdio_writeb(sdiodev, sdiodev->sdio_reg.wakeup_reg, 2) < 0) {
sdio_err("reg:%d write failed!\n", sdiodev->sdio_reg.wakeup_reg);
}
#endif
cmd_dump(next);
spin_lock_bh(&cmd_mgr->lock);
cmd_mgr->state = RWNX_CMD_MGR_STATE_CRASHED;
if (!(next->flags & RWNX_CMD_FLAG_DONE)) {
next->result = -ETIMEDOUT;
cmd_complete(cmd_mgr, next);
}
spin_unlock_bh(&cmd_mgr->lock);
} else
rwnx_cmd_free(next);//kfree(next);
}
}
}
static int cmd_mgr_run_callback(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd,
struct rwnx_cmd_e2amsg *msg, msg_cb_fct cb)
{
int res;
if (!cb) {
return 0;
}
//RWNX_DBG(RWNX_FN_ENTRY_STR);
//spin_lock_bh(&rwnx_hw->cb_lock);
res = cb(rwnx_hw, cmd, msg);
//spin_unlock_bh(&rwnx_hw->cb_lock);
return res;
}
/**
*
*/
static int cmd_mgr_msgind(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd_e2amsg *msg,
msg_cb_fct cb)
{
#ifdef AICWF_SDIO_SUPPORT
struct aic_sdio_dev *sdiodev = container_of(cmd_mgr, struct aic_sdio_dev, cmd_mgr);
struct rwnx_hw *rwnx_hw = sdiodev->rwnx_hw;
#endif
#ifdef AICWF_USB_SUPPORT
struct aic_usb_dev *usbdev = container_of(cmd_mgr, struct aic_usb_dev, cmd_mgr);
struct rwnx_hw *rwnx_hw = usbdev->rwnx_hw;
#endif
struct rwnx_cmd *cmd, *pos;
bool found = false;
// RWNX_DBG(RWNX_FN_ENTRY_STR);
#ifdef CREATE_TRACE_POINTS
trace_msg_recv(msg->id);
#endif
//printk("cmd->id=%x\n", msg->id);
spin_lock_bh(&cmd_mgr->lock);
list_for_each_entry_safe(cmd, pos, &cmd_mgr->cmds, list) {
if (cmd->reqid == msg->id &&
(cmd->flags & RWNX_CMD_FLAG_WAIT_CFM)) {
if (!cmd_mgr_run_callback(rwnx_hw, cmd, msg, cb)) {
found = true;
cmd->flags &= ~RWNX_CMD_FLAG_WAIT_CFM;
if (WARN((msg->param_len > RWNX_CMD_E2AMSG_LEN_MAX),
"Unexpect E2A msg len %d > %d\n", msg->param_len,
RWNX_CMD_E2AMSG_LEN_MAX)) {
msg->param_len = RWNX_CMD_E2AMSG_LEN_MAX;
}
if (cmd->e2a_msg && msg->param_len)
memcpy(cmd->e2a_msg, &msg->param, msg->param_len);
if (RWNX_CMD_WAIT_COMPLETE(cmd->flags))
cmd_complete(cmd_mgr, cmd);
break;
}
}
}
spin_unlock_bh(&cmd_mgr->lock);
if (!found)
cmd_mgr_run_callback(rwnx_hw, NULL, msg, cb);
return 0;
}
/**
*
*/
static void cmd_mgr_print(struct rwnx_cmd_mgr *cmd_mgr)
{
struct rwnx_cmd *cur;
spin_lock_bh(&cmd_mgr->lock);
RWNX_DBG("q_sz/max: %2d / %2d - next tkn: %d\n",
cmd_mgr->queue_sz, cmd_mgr->max_queue_sz,
cmd_mgr->next_tkn);
list_for_each_entry(cur, &cmd_mgr->cmds, list) {
cmd_dump(cur);
}
spin_unlock_bh(&cmd_mgr->lock);
}
static void cmd_mgr_drain(struct rwnx_cmd_mgr *cmd_mgr)
{
struct rwnx_cmd *cur, *nxt;
RWNX_DBG(RWNX_FN_ENTRY_STR);
spin_lock_bh(&cmd_mgr->lock);
list_for_each_entry_safe(cur, nxt, &cmd_mgr->cmds, list) {
list_del(&cur->list);
cmd_mgr->queue_sz--;
if (!(cur->flags & RWNX_CMD_FLAG_NONBLOCK))
complete(&cur->complete);
}
spin_unlock_bh(&cmd_mgr->lock);
}
void rwnx_cmd_mgr_init(struct rwnx_cmd_mgr *cmd_mgr)
{
RWNX_DBG(RWNX_FN_ENTRY_STR);
INIT_LIST_HEAD(&cmd_mgr->cmds);
cmd_mgr->state = RWNX_CMD_MGR_STATE_INITED;
spin_lock_init(&cmd_mgr->lock);
cmd_mgr->max_queue_sz = RWNX_CMD_MAX_QUEUED;
cmd_mgr->queue = &cmd_mgr_queue;
cmd_mgr->print = &cmd_mgr_print;
cmd_mgr->drain = &cmd_mgr_drain;
cmd_mgr->llind = &cmd_mgr_llind;
cmd_mgr->msgind = &cmd_mgr_msgind;
INIT_WORK(&cmd_mgr->cmdWork, cmd_mgr_task_process);
cmd_mgr->cmd_wq = create_singlethread_workqueue("cmd_wq");
if (!cmd_mgr->cmd_wq) {
txrx_err("insufficient memory to create cmd workqueue.\n");
return;
}
}
void rwnx_cmd_mgr_deinit(struct rwnx_cmd_mgr *cmd_mgr)
{
cmd_mgr->print(cmd_mgr);
cmd_mgr->drain(cmd_mgr);
cmd_mgr->print(cmd_mgr);
flush_workqueue(cmd_mgr->cmd_wq);
destroy_workqueue(cmd_mgr->cmd_wq);
memset(cmd_mgr, 0, sizeof(*cmd_mgr));
}
void aicwf_set_cmd_tx(void *dev, struct lmac_msg *msg, uint len)
{
u8 *buffer = NULL;
u16 index = 0;
#ifdef AICWF_SDIO_SUPPORT
struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *)dev;
struct aicwf_bus *bus = sdiodev->bus_if;
#else
struct aic_usb_dev *usbdev = (struct aic_usb_dev *)dev;
struct aicwf_bus *bus = NULL;
if (!usbdev->state) {
printk("down msg \n");
return;
}
bus = usbdev->bus_if;
#endif
buffer = bus->cmd_buf;
memset(buffer, 0, CMD_BUF_MAX);
buffer[0] = (len+4) & 0x00ff;
buffer[1] = ((len+4) >> 8) &0x0f;
buffer[2] = 0x11;
if (sdiodev->chipid == PRODUCT_ID_AIC8801 || sdiodev->chipid == PRODUCT_ID_AIC8800DC ||
sdiodev->chipid == PRODUCT_ID_AIC8800DW)
buffer[3] = 0x0;
else if (sdiodev->chipid == PRODUCT_ID_AIC8800D80)
buffer[3] = crc8_ponl_107(&buffer[0], 3); // crc8
index += 4;
//there is a dummy word
index += 4;
//make sure little endian
put_u16(&buffer[index], msg->id);
index += 2;
put_u16(&buffer[index], msg->dest_id);
index += 2;
put_u16(&buffer[index], msg->src_id);
index += 2;
put_u16(&buffer[index], msg->param_len);
index += 2;
memcpy(&buffer[index], (u8 *)msg->param, msg->param_len);
aicwf_bus_txmsg(bus, buffer, len + 8);
}

View File

@ -0,0 +1,124 @@
/**
******************************************************************************
*
* rwnx_cmds.h
*
* Copyright (C) RivieraWaves 2014-2019
*
******************************************************************************
*/
#ifndef _RWNX_CMDS_H_
#define _RWNX_CMDS_H_
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/module.h>
#include "lmac_msg.h"
#ifdef CONFIG_RWNX_SDM
#define RWNX_80211_CMD_TIMEOUT_MS (20 * 300)
#elif defined(CONFIG_RWNX_FHOST)
#define RWNX_80211_CMD_TIMEOUT_MS (10000)
#else
#ifdef AICWF_USB_SUPPORT
#define RWNX_80211_CMD_TIMEOUT_MS 2000//300
#else
#define RWNX_80211_CMD_TIMEOUT_MS 3000//500//300
#endif
#endif
#define RWNX_CMD_FLAG_NONBLOCK BIT(0)
#define RWNX_CMD_FLAG_REQ_CFM BIT(1)
#define RWNX_CMD_FLAG_WAIT_PUSH BIT(2)
#define RWNX_CMD_FLAG_WAIT_ACK BIT(3)
#define RWNX_CMD_FLAG_WAIT_CFM BIT(4)
#define RWNX_CMD_FLAG_DONE BIT(5)
/* ATM IPC design makes it possible to get the CFM before the ACK,
* otherwise this could have simply been a state enum */
#define RWNX_CMD_WAIT_COMPLETE(flags) \
(!(flags & (RWNX_CMD_FLAG_WAIT_ACK | RWNX_CMD_FLAG_WAIT_CFM)))
#define RWNX_CMD_MAX_QUEUED 16
#ifdef CONFIG_RWNX_FHOST
#include "ipc_fhost.h"
#define rwnx_cmd_e2amsg ipc_fhost_msg
#define rwnx_cmd_a2emsg ipc_fhost_msg
#define RWNX_CMD_A2EMSG_LEN(m) (m->param_len)
#define RWNX_CMD_E2AMSG_LEN_MAX IPC_FHOST_MSG_BUF_SIZE
struct rwnx_term_stream;
#else /* !CONFIG_RWNX_FHOST*/
#include "ipc_shared.h"
#define rwnx_cmd_e2amsg ipc_e2a_msg
#define rwnx_cmd_a2emsg lmac_msg
#define RWNX_CMD_A2EMSG_LEN(m) (sizeof(struct lmac_msg) + m->param_len)
#define RWNX_CMD_E2AMSG_LEN_MAX (IPC_E2A_MSG_PARAM_SIZE * 4)
#endif /* CONFIG_RWNX_FHOST*/
struct rwnx_hw;
struct rwnx_cmd;
typedef int (*msg_cb_fct)(struct rwnx_hw *rwnx_hw, struct rwnx_cmd *cmd,
struct rwnx_cmd_e2amsg *msg);
static inline void put_u16(u8 *buf, u16 data)
{
buf[0] = (u8)(data&0x00ff);
buf[1] = (u8)((data >> 8)&0x00ff);
}
enum rwnx_cmd_mgr_state {
RWNX_CMD_MGR_STATE_DEINIT,
RWNX_CMD_MGR_STATE_INITED,
RWNX_CMD_MGR_STATE_CRASHED,
};
struct rwnx_cmd {
struct list_head list;
lmac_msg_id_t id;
lmac_msg_id_t reqid;
struct rwnx_cmd_a2emsg *a2e_msg;
char *e2a_msg;
u32 tkn;
u16 flags;
struct completion complete;
u32 result;
u8 used;
int array_id;
#ifdef CONFIG_RWNX_FHOST
struct rwnx_term_stream *stream;
#endif
};
struct rwnx_cmd_mgr {
enum rwnx_cmd_mgr_state state;
spinlock_t lock;
u32 next_tkn;
u32 queue_sz;
u32 max_queue_sz;
struct list_head cmds;
int (*queue)(struct rwnx_cmd_mgr *, struct rwnx_cmd *);
int (*llind)(struct rwnx_cmd_mgr *, struct rwnx_cmd *);
int (*msgind)(struct rwnx_cmd_mgr *, struct rwnx_cmd_e2amsg *, msg_cb_fct);
void (*print)(struct rwnx_cmd_mgr *);
void (*drain)(struct rwnx_cmd_mgr *);
struct work_struct cmdWork;
struct workqueue_struct *cmd_wq;
};
#define WAKE_CMD_WORK(cmd_mgr) \
do { \
queue_work((cmd_mgr)->cmd_wq, &cmd_mgr->cmdWork); \
} while (0)
void rwnx_cmd_mgr_init(struct rwnx_cmd_mgr *cmd_mgr);
void rwnx_cmd_mgr_deinit(struct rwnx_cmd_mgr *cmd_mgr);
int cmd_mgr_queue_force_defer(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd);
void aicwf_set_cmd_tx(void *dev, struct lmac_msg *msg, uint len);
#endif /* _RWNX_CMDS_H_ */

View File

@ -0,0 +1,446 @@
/**
******************************************************************************
*
* @file rwnx_compat.h
*
* Ensure driver compilation for linux 3.16 to 3.19
*
* To avoid too many #if LINUX_VERSION_CODE if the code, when prototype change
* between different kernel version:
* - For external function, define a macro whose name is the function name with
* _compat suffix and prototype (actually the number of parameter) of the
* latest version. Then latest version this macro simply call the function
* and for older kernel version it call the function adapting the api.
* - For internal function (e.g. cfg80211_ops) do the same but the macro name
* doesn't need to have the _compat suffix when the function is not used
* directly by the driver
*
* Copyright (C) RivieraWaves 2018
*
******************************************************************************
*/
#ifndef _RWNX_COMPAT_H_
#define _RWNX_COMPAT_H_
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
#error "Minimum kernel version supported is 3.10"
#endif
/* Generic */
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
#define __bf_shf(x) (__builtin_ffsll(x) - 1)
#define FIELD_PREP(_mask, _val) \
(((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask))
#else
#include <linux/bitfield.h>
#endif
/* CFG80211 */
//because android kernel 5.15 uses kernel 6.0 or 6.1 kernel api
#ifdef ANDROID_PLATFORM
#define HIGH_KERNEL_VERSION KERNEL_VERSION(5, 15, 41)
#define HIGH_KERNEL_VERSION2 KERNEL_VERSION(5, 15, 41)
#define HIGH_KERNEL_VERSION3 KERNEL_VERSION(5, 15, 104)
#define HIGH_KERNEL_VERSION4 KERNEL_VERSION(6, 1, 0)
#else
#define HIGH_KERNEL_VERSION KERNEL_VERSION(6, 0, 0)
#define HIGH_KERNEL_VERSION2 KERNEL_VERSION(6, 1, 0)
#define HIGH_KERNEL_VERSION3 KERNEL_VERSION(6, 3, 0)
#define HIGH_KERNEL_VERSION4 KERNEL_VERSION(6, 3, 0)
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 60)
#define IEEE80211_MAX_AMPDU_BUF IEEE80211_MAX_AMPDU_BUF_HE
#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB
#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB
#define IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 20, 0)
#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_MASK
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
#define IEEE80211_RADIOTAP_HE 23
#define IEEE80211_RADIOTAP_HE_MU 24
struct ieee80211_radiotap_he {
__le16 data1, data2, data3, data4, data5, data6;
};
enum ieee80211_radiotap_he_bits {
IEEE80211_RADIOTAP_HE_DATA1_FORMAT_MASK = 3,
IEEE80211_RADIOTAP_HE_DATA1_FORMAT_SU = 0,
IEEE80211_RADIOTAP_HE_DATA1_FORMAT_EXT_SU = 1,
IEEE80211_RADIOTAP_HE_DATA1_FORMAT_MU = 2,
IEEE80211_RADIOTAP_HE_DATA1_FORMAT_TRIG = 3,
IEEE80211_RADIOTAP_HE_DATA1_BSS_COLOR_KNOWN = 0x0004,
IEEE80211_RADIOTAP_HE_DATA1_BEAM_CHANGE_KNOWN = 0x0008,
IEEE80211_RADIOTAP_HE_DATA1_UL_DL_KNOWN = 0x0010,
IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN = 0x0020,
IEEE80211_RADIOTAP_HE_DATA1_DATA_DCM_KNOWN = 0x0040,
IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN = 0x0080,
IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN = 0x0100,
IEEE80211_RADIOTAP_HE_DATA1_STBC_KNOWN = 0x0200,
IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE_KNOWN = 0x0400,
IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE2_KNOWN = 0x0800,
IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE3_KNOWN = 0x1000,
IEEE80211_RADIOTAP_HE_DATA1_SPTL_REUSE4_KNOWN = 0x2000,
IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN = 0x4000,
IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN = 0x8000,
IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_KNOWN = 0x0001,
IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN = 0x0002,
IEEE80211_RADIOTAP_HE_DATA2_NUM_LTF_SYMS_KNOWN = 0x0004,
IEEE80211_RADIOTAP_HE_DATA2_PRE_FEC_PAD_KNOWN = 0x0008,
IEEE80211_RADIOTAP_HE_DATA2_TXBF_KNOWN = 0x0010,
IEEE80211_RADIOTAP_HE_DATA2_PE_DISAMBIG_KNOWN = 0x0020,
IEEE80211_RADIOTAP_HE_DATA2_TXOP_KNOWN = 0x0040,
IEEE80211_RADIOTAP_HE_DATA2_MIDAMBLE_KNOWN = 0x0080,
IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET = 0x3f00,
IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET_KNOWN = 0x4000,
IEEE80211_RADIOTAP_HE_DATA2_PRISEC_80_SEC = 0x8000,
IEEE80211_RADIOTAP_HE_DATA3_BSS_COLOR = 0x003f,
IEEE80211_RADIOTAP_HE_DATA3_BEAM_CHANGE = 0x0040,
IEEE80211_RADIOTAP_HE_DATA3_UL_DL = 0x0080,
IEEE80211_RADIOTAP_HE_DATA3_DATA_MCS = 0x0f00,
IEEE80211_RADIOTAP_HE_DATA3_DATA_DCM = 0x1000,
IEEE80211_RADIOTAP_HE_DATA3_CODING = 0x2000,
IEEE80211_RADIOTAP_HE_DATA3_LDPC_XSYMSEG = 0x4000,
IEEE80211_RADIOTAP_HE_DATA3_STBC = 0x8000,
IEEE80211_RADIOTAP_HE_DATA4_SU_MU_SPTL_REUSE = 0x000f,
IEEE80211_RADIOTAP_HE_DATA4_MU_STA_ID = 0x7ff0,
IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE1 = 0x000f,
IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE2 = 0x00f0,
IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE3 = 0x0f00,
IEEE80211_RADIOTAP_HE_DATA4_TB_SPTL_REUSE4 = 0xf000,
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC = 0x000f,
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_20MHZ = 0,
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_40MHZ = 1,
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_80MHZ = 2,
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_160MHZ = 3,
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_26T = 4,
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_52T = 5,
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_106T = 6,
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_242T = 7,
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_484T = 8,
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_996T = 9,
IEEE80211_RADIOTAP_HE_DATA5_DATA_BW_RU_ALLOC_2x996T = 10,
IEEE80211_RADIOTAP_HE_DATA5_GI = 0x0030,
IEEE80211_RADIOTAP_HE_DATA5_GI_0_8 = 0,
IEEE80211_RADIOTAP_HE_DATA5_GI_1_6 = 1,
IEEE80211_RADIOTAP_HE_DATA5_GI_3_2 = 2,
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE = 0x00c0,
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN = 0,
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_1X = 1,
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X = 2,
IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X = 3,
IEEE80211_RADIOTAP_HE_DATA5_NUM_LTF_SYMS = 0x0700,
IEEE80211_RADIOTAP_HE_DATA5_PRE_FEC_PAD = 0x3000,
IEEE80211_RADIOTAP_HE_DATA5_TXBF = 0x4000,
IEEE80211_RADIOTAP_HE_DATA5_PE_DISAMBIG = 0x8000,
IEEE80211_RADIOTAP_HE_DATA6_NSTS = 0x000f,
IEEE80211_RADIOTAP_HE_DATA6_DOPPLER = 0x0010,
IEEE80211_RADIOTAP_HE_DATA6_TXOP = 0x7f00,
IEEE80211_RADIOTAP_HE_DATA6_MIDAMBLE_PDCTY = 0x8000,
};
struct ieee80211_radiotap_he_mu {
__le16 flags1, flags2;
u8 ru_ch1[4];
u8 ru_ch2[4];
};
enum ieee80211_radiotap_he_mu_bits {
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS = 0x000f,
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS_KNOWN = 0x0010,
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM = 0x0020,
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM_KNOWN = 0x0040,
IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_CTR_26T_RU_KNOWN = 0x0080,
IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_RU_KNOWN = 0x0100,
IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH2_RU_KNOWN = 0x0200,
IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU_KNOWN = 0x1000,
IEEE80211_RADIOTAP_HE_MU_FLAGS1_CH1_CTR_26T_RU = 0x2000,
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_COMP_KNOWN = 0x4000,
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN = 0x8000,
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW = 0x0003,
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_20MHZ = 0x0000,
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_40MHZ = 0x0001,
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_80MHZ = 0x0002,
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_160MHZ = 0x0003,
IEEE80211_RADIOTAP_HE_MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN = 0x0004,
IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP = 0x0008,
IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS = 0x00f0,
IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW = 0x0300,
IEEE80211_RADIOTAP_HE_MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN = 0x0400,
IEEE80211_RADIOTAP_HE_MU_FLAGS2_CH2_CTR_26T_RU = 0x0800,
};
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)
#define rwnx_cfg80211_add_iface(wiphy, name, name_assign_type, type, params) \
rwnx_cfg80211_add_iface(wiphy, name, type, u32 *flags, params)
#else
#define rwnx_cfg80211_add_iface(wiphy, name, name_assign_type, type, params) \
rwnx_cfg80211_add_iface(wiphy, name, name_assign_type, type, u32 *flags, params)
#endif
#define rwnx_cfg80211_change_iface(wiphy, dev, type, params) \
rwnx_cfg80211_change_iface(wiphy, dev, type, u32 *flags, params)
#define CCFS0(vht) vht->center_freq_seg1_idx
#define CCFS1(vht) vht->center_freq_seg2_idx
#else
#define CCFS0(vht) vht->center_freq_seg0_idx
#define CCFS1(vht) vht->center_freq_seg1_idx
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
#define cfg80211_cqm_rssi_notify(dev, event, level, gfp) \
cfg80211_cqm_rssi_notify(dev, event, gfp)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
#define ieee80211_amsdu_to_8023s(skb, list, addr, iftype, extra_headroom, check_da, check_sa) \
ieee80211_amsdu_to_8023s(skb, list, addr, iftype, extra_headroom, false)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)
#define NUM_NL80211_BANDS IEEE80211_NUM_BANDS
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
#define cfg80211_disconnected(dev, reason, ie, len, local, gfp) \
cfg80211_disconnected(dev, reason, ie, len, gfp)
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) && !(defined CONFIG_VENDOR_RWNX)
#define ieee80211_chandef_to_operating_class(chan_def, op_class) 0
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
#define SURVEY_INFO_TIME SURVEY_INFO_CHANNEL_TIME
#define SURVEY_INFO_TIME_BUSY SURVEY_INFO_CHANNEL_TIME_BUSY
#define SURVEY_INFO_TIME_EXT_BUSY SURVEY_INFO_CHANNEL_TIME_EXT_BUSY
#define SURVEY_INFO_TIME_RX SURVEY_INFO_CHANNEL_TIME_RX
#define SURVEY_INFO_TIME_TX SURVEY_INFO_CHANNEL_TIME_TX
#define SURVEY_TIME(s) s->channel_time
#define SURVEY_TIME_BUSY(s) s->channel_time_busy
#else
#define SURVEY_TIME(s) s->time
#define SURVEY_TIME_BUSY(s) s->time_busy
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)
#define cfg80211_ch_switch_started_notify(dev, chandef, count)
#define WLAN_BSS_COEX_INFORMATION_REQUEST BIT(0)
#define WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING BIT(2)
#define WLAN_EXT_CAPA4_TDLS_BUFFER_STA BIT(4)
#define WLAN_EXT_CAPA4_TDLS_PEER_PSM BIT(5)
#define WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH BIT(6)
#define WLAN_EXT_CAPA5_TDLS_CH_SW_PROHIBITED BIT(7)
#define NL80211_FEATURE_TDLS_CHANNEL_SWITCH 0
#define STA_TDLS_INITIATOR(sta) 0
#define REGULATORY_IGNORE_STALE_KICKOFF 0
#else
#define STA_TDLS_INITIATOR(sta) sta->tdls_initiator
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
#define cfg80211_rx_mgmt(wdev, freq, rssi, buf, len, flags) \
cfg80211_rx_mgmt(wdev, freq, rssi, buf, len, flags, GFP_ATOMIC)
#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)
#define cfg80211_rx_mgmt(wdev, freq, rssi, buf, len, flags) \
cfg80211_rx_mgmt(wdev, freq, rssi, buf, len, GFP_ATOMIC)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
#if 0
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
#define rwnx_cfg80211_tdls_mgmt(wiphy, dev, peer, act, tok, status, peer_capability, initiator, buf, len) \
rwnx_cfg80211_tdls_mgmt(wiphy, dev, peer, act, tok, status, peer_capability, buf, len)
#else
#define rwnx_cfg80211_tdls_mgmt(wiphy, dev, peer, act, tok, status, peer_capability, initiator, buf, len) \
rwnx_cfg80211_tdls_mgmt(wiphy, dev, peer, act, tok, status, buf, len)
#endif
#endif
#include <linux/types.h>
struct ieee80211_wmm_ac_param {
u8 aci_aifsn; /* AIFSN, ACM, ACI */
u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */
__le16 txop_limit;
} __packed;
struct ieee80211_wmm_param_ie {
u8 element_id; /* Element ID: 221 (0xdd); */
u8 len; /* Length: 24 */
/* required fields for WMM version 1 */
u8 oui[3]; /* 00:50:f2 */
u8 oui_type; /* 2 */
u8 oui_subtype; /* 1 */
u8 version; /* 1 for WMM version 1.0 */
u8 qos_info; /* AP/STA specific QoS info */
u8 reserved; /* 0 */
/* AC_BE, AC_BK, AC_VI, AC_VO */
struct ieee80211_wmm_ac_param ac[4];
} __packed;
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
enum {
IEEE80211_HE_MCS_SUPPORT_0_7 = 0,
IEEE80211_HE_MCS_SUPPORT_0_9 = 1,
IEEE80211_HE_MCS_SUPPORT_0_11 = 2,
IEEE80211_HE_MCS_NOT_SUPPORTED = 3,
};
#endif
/* MAC80211 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0)
#define rwnx_ops_mgd_prepare_tx(hw, vif, duration) \
rwnx_ops_mgd_prepare_tx(hw, vif)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
#define RX_ENC_HT(s) (s->flag |= RX_FLAG_HT)
#define RX_ENC_HT_GF(s) (s->flag |= (RX_FLAG_HT | RX_FLAG_HT_GF))
#define RX_ENC_VHT(s) (s->flag |= RX_FLAG_HT)
#define RX_ENC_HE(s) (s->flag |= RX_FLAG_HT)
#define RX_ENC_FLAG_SHORT_GI(s) (s->flag |= RX_FLAG_SHORT_GI)
#define RX_ENC_FLAG_SHORT_PRE(s) (s->flag |= RX_FLAG_SHORTPRE)
#define RX_ENC_FLAG_LDPC(s) (s->flag |= RX_FLAG_LDPC)
#define RX_BW_40MHZ(s) (s->flag |= RX_FLAG_40MHZ)
#define RX_BW_80MHZ(s) (s->vht_flag |= RX_VHT_FLAG_80MHZ)
#define RX_BW_160MHZ(s) (s->vht_flag |= RX_VHT_FLAG_160MHZ)
#define RX_NSS(s) s->vht_nss
#else
#define RX_ENC_HT(s) (s->encoding = RX_ENC_HT)
#define RX_ENC_HT_GF(s) { s->encoding = RX_ENC_HT; \
s->enc_flags |= RX_ENC_FLAG_HT_GF; }
#define RX_ENC_VHT(s) (s->encoding = RX_ENC_VHT)
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
#define RX_ENC_HE(s) (s->encoding = RX_ENC_VHT)
#else
#define RX_ENC_HE(s) (s->encoding = RX_ENC_HE)
#endif
#define RX_ENC_FLAG_SHORT_GI(s) (s->enc_flags |= RX_ENC_FLAG_SHORT_GI)
#define RX_ENC_FLAG_SHORT_PRE(s) (s->enc_flags |= RX_ENC_FLAG_SHORTPRE)
#define RX_ENC_FLAG_LDPC(s) (s->enc_flags |= RX_ENC_FLAG_LDPC)
#define RX_BW_40MHZ(s) (s->bw = RATE_INFO_BW_40)
#define RX_BW_80MHZ(s) (s->bw = RATE_INFO_BW_80)
#define RX_BW_160MHZ(s) (s->bw = RATE_INFO_BW_160)
#define RX_NSS(s) s->nss
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
#define ieee80211_cqm_rssi_notify(vif, event, level, gfp) \
ieee80211_cqm_rssi_notify(vif, event, gfp)
#endif
#ifndef CONFIG_VENDOR_RWNX_AMSDUS_TX
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0))
#define rwnx_ops_ampdu_action(hw, vif, params) \
rwnx_ops_ampdu_action(hw, vif, enum ieee80211_ampdu_mlme_action action, \
struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size)
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0))
#define rwnx_ops_ampdu_action(hw, vif, params) \
rwnx_ops_ampdu_action(hw, vif, enum ieee80211_ampdu_mlme_action action, \
struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size, \
bool amsdu)
#endif
#endif /* CONFIG_VENDOR_RWNX_AMSDUS_TX */
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
#define IEEE80211_HW_SUPPORT_FAST_XMIT 0
#define ieee80211_hw_check(hw, feat) (hw->flags & IEEE80211_HW_##feat)
#define ieee80211_hw_set(hw, feat) {hw->flags |= IEEE80211_HW_##feat; }
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)
#define rwnx_ops_sw_scan_start(hw, vif, mac_addr) \
rwnx_ops_sw_scan_start(hw)
#define rwnx_ops_sw_scan_complete(hw, vif) \
rwnx_ops_sw_scan_complete(hw)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
#define rwnx_ops_hw_scan(hw, vif, hw_req) \
rwnx_ops_hw_scan(hw, vif, struct cfg80211_scan_request *req)
#endif
/* NET */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
#define rwnx_select_queue(dev, skb, sb_dev) \
rwnx_select_queue(dev, skb)
#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
#define rwnx_select_queue(dev, skb, sb_dev) \
rwnx_select_queue(dev, skb, void *accel_priv, select_queue_fallback_t fallback)
#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)
#define rwnx_select_queue(dev, skb, sb_dev) \
rwnx_select_queue(dev, skb, sb_dev, select_queue_fallback_t fallback)
#else
#define rwnx_select_queue(dev, skb, sb_dev) \
rwnx_select_queue(dev, skb, sb_dev)
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0)) && !(defined CONFIG_VENDOR_RWNX)
#define sk_pacing_shift_update(sk, shift)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
#define alloc_netdev_mqs(size, name, assign, setup, txqs, rxqs) \
alloc_netdev_mqs(size, name, setup, txqs, rxqs)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
#define NET_NAME_UNKNOWN 0
#endif
/* TRACE */
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
#define trace_print_symbols_seq ftrace_print_symbols_seq
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
#define trace_seq_buffer_ptr(p) (p->buffer + p->len)
#endif
/* TIME */
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
#define time64_to_tm(t, o, tm) time_to_tm((time_t)t, o, tm)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)
#define ktime_get_real_seconds get_seconds
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
typedef __s64 time64_t;
#endif
#endif /* _RWNX_COMPAT_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,202 @@
/**
******************************************************************************
*
* @file rwnx_debugfs.h
*
* @brief Miscellaneous utility function definitions
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#ifndef _RWNX_DEBUGFS_H_
#define _RWNX_DEBUGFS_H_
#include <linux/version.h>
#include <linux/workqueue.h>
#include <linux/if_ether.h>
#include "rwnx_fw_trace.h"
struct rwnx_hw;
struct rwnx_sta;
/* some macros taken from iwlwifi */
/* TODO: replace with generic read and fill read buffer in open to avoid double
* reads */
#define DEBUGFS_ADD_FILE(name, parent, mode) do { \
if (!debugfs_create_file(#name, mode, parent, rwnx_hw, \
&rwnx_dbgfs_##name##_ops)) \
goto err; \
} while (0)
#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
struct dentry *__tmp; \
__tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \
parent, ptr); \
if (IS_ERR(__tmp) || !__tmp) \
goto err; \
} while (0)
#define DEBUGFS_ADD_X64(name, parent, ptr) do { \
struct dentry *__tmp; \
__tmp = debugfs_create_x64(#name, S_IWUSR | S_IRUSR, \
parent, ptr); \
if (IS_ERR(__tmp) || !__tmp) \
goto err; \
} while (0)
#define DEBUGFS_ADD_U64(name, parent, ptr, mode) do { \
struct dentry *__tmp; \
__tmp = debugfs_create_u64(#name, mode, \
parent, ptr); \
if (IS_ERR(__tmp) || !__tmp) \
goto err; \
} while (0)
#define DEBUGFS_ADD_X32(name, parent, ptr) do { \
struct dentry *__tmp; \
__tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR, \
parent, ptr); \
if (IS_ERR(__tmp) || !__tmp) \
goto err; \
} while (0)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)
#define DEBUGFS_ADD_U32(name, parent, ptr, mode) do { \
debugfs_create_u32(#name, mode, \
parent, ptr); \
} while (0)
#else
#define DEBUGFS_ADD_U32(name, parent, ptr, mode) do { \
struct dentry *__tmp; \
__tmp = debugfs_create_u32(#name, mode, \
parent, ptr); \
if (IS_ERR(__tmp) || !__tmp) \
goto err; \
} while (0)
#endif
/* file operation */
#define DEBUGFS_READ_FUNC(name) \
static ssize_t rwnx_dbgfs_##name##_read(struct file *file, \
char __user *user_buf, \
size_t count, loff_t *ppos);
#define DEBUGFS_WRITE_FUNC(name) \
static ssize_t rwnx_dbgfs_##name##_write(struct file *file, \
const char __user *user_buf,\
size_t count, loff_t *ppos);
#define DEBUGFS_OPEN_FUNC(name) \
static int rwnx_dbgfs_##name##_open(struct inode *inode, \
struct file *file);
#define DEBUGFS_RELEASE_FUNC(name) \
static int rwnx_dbgfs_##name##_release(struct inode *inode, \
struct file *file);
#define DEBUGFS_READ_FILE_OPS(name) \
DEBUGFS_READ_FUNC(name); \
static const struct file_operations rwnx_dbgfs_##name##_ops = { \
.read = rwnx_dbgfs_##name##_read, \
.open = simple_open, \
.llseek = generic_file_llseek, \
};
#define DEBUGFS_WRITE_FILE_OPS(name) \
DEBUGFS_WRITE_FUNC(name); \
static const struct file_operations rwnx_dbgfs_##name##_ops = { \
.write = rwnx_dbgfs_##name##_write, \
.open = simple_open, \
.llseek = generic_file_llseek, \
};
#define DEBUGFS_READ_WRITE_FILE_OPS(name) \
DEBUGFS_READ_FUNC(name); \
DEBUGFS_WRITE_FUNC(name); \
static const struct file_operations rwnx_dbgfs_##name##_ops = { \
.write = rwnx_dbgfs_##name##_write, \
.read = rwnx_dbgfs_##name##_read, \
.open = simple_open, \
.llseek = generic_file_llseek, \
};
#define DEBUGFS_READ_WRITE_OPEN_RELEASE_FILE_OPS(name) \
DEBUGFS_READ_FUNC(name); \
DEBUGFS_WRITE_FUNC(name); \
DEBUGFS_OPEN_FUNC(name); \
DEBUGFS_RELEASE_FUNC(name); \
static const struct file_operations rwnx_dbgfs_##name##_ops = { \
.write = rwnx_dbgfs_##name##_write, \
.read = rwnx_dbgfs_##name##_read, \
.open = rwnx_dbgfs_##name##_open, \
.release = rwnx_dbgfs_##name##_release, \
.llseek = generic_file_llseek, \
};
#ifdef CONFIG_RWNX_DEBUGFS
struct rwnx_debugfs {
unsigned long long rateidx;
struct dentry *dir;
bool trace_prst;
char helper_cmd[64];
//struct work_struct helper_work;
bool helper_scheduled;
spinlock_t umh_lock;
bool unregistering;
#ifndef CONFIG_RWNX_FHOST
struct rwnx_fw_log fw_log;
#endif /* CONFIG_RWNX_FHOST */
#ifdef CONFIG_RWNX_FULLMAC
struct work_struct rc_stat_work;
uint8_t rc_sta[NX_REMOTE_STA_MAX];
uint8_t rc_write;
uint8_t rc_read;
struct dentry *dir_rc;
struct dentry *dir_sta[NX_REMOTE_STA_MAX];
int rc_config[NX_REMOTE_STA_MAX];
struct list_head rc_config_save;
#endif
};
#ifdef CONFIG_RWNX_FULLMAC
// Max duration in msecs to save rate config for a sta after disconnection
#define RC_CONFIG_DUR 600000
struct rwnx_rc_config_save {
struct list_head list;
unsigned long timestamp;
int rate;
u8 mac_addr[ETH_ALEN];
};
#endif
int rwnx_dbgfs_register(struct rwnx_hw *rwnx_hw, const char *name);
void rwnx_dbgfs_unregister(struct rwnx_hw *rwnx_hw);
#ifdef CONFIG_RWNX_FULLMAC
void rwnx_dbgfs_register_rc_stat(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta);
void rwnx_dbgfs_unregister_rc_stat(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta);
#endif
#else
struct rwnx_debugfs {
};
static inline int rwnx_dbgfs_register(struct rwnx_hw *rwnx_hw, const char *name) { return 0; }
static inline void rwnx_dbgfs_unregister(struct rwnx_hw *rwnx_hw) {}
#ifdef CONFIG_RWNX_FULLMAC
static inline void rwnx_dbgfs_register_rc_stat(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta) {}
static inline void rwnx_dbgfs_unregister_rc_stat(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta) {}
#endif
#endif /* CONFIG_RWNX_DEBUGFS */
#endif /* _RWNX_DEBUGFS_H_ */

View File

@ -0,0 +1,746 @@
/**
******************************************************************************
*
* @file rwnx_defs.h
*
* @brief Main driver structure declarations for fullmac driver
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#ifndef _RWNX_DEFS_H_
#define _RWNX_DEFS_H_
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/dmapool.h>
#include <linux/skbuff.h>
#include <net/cfg80211.h>
#include <linux/slab.h>
#include "rwnx_mod_params.h"
#include "rwnx_debugfs.h"
#include "rwnx_tx.h"
#include "rwnx_rx.h"
#include "rwnx_radar.h"
#include "rwnx_utils.h"
#include "rwnx_mu_group.h"
#include "rwnx_platform.h"
#include "rwnx_cmds.h"
#ifdef CONFIG_GKI
#include "rwnx_gki.h"
#endif
#include "rwnx_compat.h"
#ifdef CONFIG_FILTER_TCP_ACK
#include "aicwf_tcp_ack.h"
#endif
#ifdef AICWF_SDIO_SUPPORT
#include "aicwf_sdio.h"
#include "sdio_host.h"
#endif
#ifdef AICWF_USB_SUPPORT
#include "usb_host.h"
#endif
#ifdef CONFIG_BR_SUPPORT
#include "aic_br_ext.h"
#endif /* CONFIG_BR_SUPPORT */
#define WPI_HDR_LEN 18
#define WPI_PN_LEN 16
#define WPI_PN_OFST 2
#define WPI_MIC_LEN 16
#define WPI_KEY_LEN 32
#define WPI_SUBKEY_LEN 16 // WPI key is actually two 16bytes key
#define LEGACY_PS_ID 0
#define UAPSD_ID 1
#define PS_SP_INTERRUPTED 255
#define MAC_ADDR_LEN 6
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) || defined(CONFIG_VHT_FOR_OLD_KERNEL)
enum nl80211_ac {
NL80211_AC_VO,
NL80211_AC_VI,
NL80211_AC_BE,
NL80211_AC_BK,
NL80211_NUM_ACS
};
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) || defined(CONFIG_VHT_FOR_OLD_KERNEL)
struct ieee80211_vht_operation {
u8 vht_op_info_chwidth;
u8 vht_op_info_chan_center_freq_seg1_idx;
u8 vht_op_info_chan_center_freq_seg2_idx;
__le16 vht_basic_mcs_set;
} __packed;
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) || defined(CONFIG_VHT_FOR_OLD_KERNEL)
#define IEEE80211_RADIOTAP_VHT 21
#define IEEE80211_RADIOTAP_VHT_KNOWN_GI 0x0004
#define IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH 0x0040
#define IEEE80211_RADIOTAP_VHT_FLAG_STBC 0x01
#define IEEE80211_RADIOTAP_VHT_FLAG_SGI 0x04
#define NL80211_FEATURE_CELL_BASE_REG_HINTS 1 << 3
#define NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL 1 << 4
#define NL80211_FEATURE_SAE 1 << 5
#define NL80211_FEATURE_LOW_PRIORITY_SCAN 1 << 6
#define NL80211_FEATURE_SCAN_FLUSH 1 << 7
#define NL80211_FEATURE_AP_SCAN 1 << 8
#define NL80211_FEATURE_VIF_TXPOWER 1 << 9
#define NL80211_FEATURE_NEED_OBSS_SCAN 1 << 10
#define NL80211_FEATURE_P2P_GO_CTWIN 1 << 11
#define NL80211_FEATURE_P2P_GO_OPPPS 1 << 12
/* 802.11ac VHT Capabilities */
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 0x00000001
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 0x00000002
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008
#define IEEE80211_VHT_CAP_RXLDPC 0x00000010
#define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020
#define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040
#define IEEE80211_VHT_CAP_TXSTBC 0x00000080
#define IEEE80211_VHT_CAP_RXSTBC_1 0x00000100
#define IEEE80211_VHT_CAP_RXSTBC_2 0x00000200
#define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300
#define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400
#define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800
#define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000
#define IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX 0x00006000
#define IEEE80211_VHT_CAP_SOUNDING_DIMENTION_MAX 0x00030000
#define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000
#define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000
#define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000
#define IEEE80211_VHT_CAP_HTC_VHT 0x00400000
#define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT 23
#define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK \
(7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT)
#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB 0x08000000
#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB 0x0c000000
#define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000
#define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000
enum ieee80211_vht_mcs_support {
IEEE80211_VHT_MCS_SUPPORT_0_7 = 0,
IEEE80211_VHT_MCS_SUPPORT_0_8 = 1,
IEEE80211_VHT_MCS_SUPPORT_0_9 = 2,
IEEE80211_VHT_MCS_NOT_SUPPORTED = 3,
};
enum nl80211_chan_width {
NL80211_CHAN_WIDTH_20_NOHT,
NL80211_CHAN_WIDTH_20,
NL80211_CHAN_WIDTH_40,
NL80211_CHAN_WIDTH_80,
NL80211_CHAN_WIDTH_80P80,
NL80211_CHAN_WIDTH_160,
};
struct cfg80211_chan_def {
struct ieee80211_channel *chan;
enum nl80211_chan_width width;
u32 center_freq1;
u32 center_freq2;
};
enum nl80211_mesh_power_mode {
NL80211_MESH_POWER_UNKNOWN,
NL80211_MESH_POWER_ACTIVE,
NL80211_MESH_POWER_LIGHT_SLEEP,
NL80211_MESH_POWER_DEEP_SLEEP,
__NL80211_MESH_POWER_AFTER_LAST,
NL80211_MESH_POWER_MAX = __NL80211_MESH_POWER_AFTER_LAST - 1
};
#endif
/**
* struct rwnx_bcn - Information of the beacon in used (AP mode)
*
* @head: head portion of beacon (before TIM IE)
* @tail: tail portion of beacon (after TIM IE)
* @ies: extra IEs (not used ?)
* @head_len: length of head data
* @tail_len: length of tail data
* @ies_len: length of extra IEs data
* @tim_len: length of TIM IE
* @len: Total beacon len (head + tim + tail + extra)
* @dtim: dtim period
*/
struct rwnx_bcn {
u8 *head;
u8 *tail;
u8 *ies;
size_t head_len;
size_t tail_len;
size_t ies_len;
size_t tim_len;
size_t len;
u8 dtim;
};
/**
* struct rwnx_key - Key information
*
* @hw_idx: Idx of the key from hardware point of view
*/
struct rwnx_key {
u8 hw_idx;
};
/**
* Structure containing information about a Mesh Path
*/
struct rwnx_mesh_path {
struct list_head list; /* For rwnx_vif.mesh_paths */
u8 path_idx; /* Path Index */
struct mac_addr tgt_mac_addr; /* Target MAC Address */
struct rwnx_sta *p_nhop_sta; /* Pointer to the Next Hop STA */
};
struct rwnx_mesh_proxy {
struct list_head list; /* For rwnx_vif.mesh_proxy */
struct mac_addr ext_sta_addr; /* Address of the External STA */
struct mac_addr proxy_addr; /* Proxy MAC Address */
bool local; /* Indicate if interface is a proxy for the device */
};
/**
* struct rwnx_csa - Information for CSA (Channel Switch Announcement)
*
* @vif: Pointer to the vif doing the CSA
* @bcn: Beacon to use after CSA
* @elem: IPC buffer to send the new beacon to the fw
* @chandef: defines the channel to use after the switch
* @count: Current csa counter
* @status: Status of the CSA at fw level
* @ch_idx: Index of the new channel context
* @work: work scheduled at the end of CSA
*/
struct rwnx_csa {
struct rwnx_vif *vif;
struct rwnx_bcn bcn;
struct rwnx_ipc_elem_var elem;
struct cfg80211_chan_def chandef;
int count;
int status;
int ch_idx;
struct work_struct work;
};
struct apm_probe_sta {
u8 sta_mac_addr[6];
u8 vif_idx;
u64 probe_id;
struct work_struct apmprobestaWork;
struct workqueue_struct *apmprobesta_wq;
};
/// Possible States of the TDLS link.
enum tdls_status_tag {
/// TDLS link is not active (no TDLS peer connected)
TDLS_LINK_IDLE,
/// TDLS Setup Request transmitted
TDLS_SETUP_REQ_TX,
/// TDLS Setup Response transmitted
TDLS_SETUP_RSP_TX,
/// TDLS link is active (TDLS peer connected)
TDLS_LINK_ACTIVE,
/// TDLS Max Number of states.
TDLS_STATE_MAX
};
/*
* Structure used to save information relative to the TDLS peer.
* This is also linked within the rwnx_hw vifs list.
*
*/
struct rwnx_tdls {
bool active; /* Indicate if TDLS link is active */
bool initiator; /* Indicate if TDLS peer is the TDLS initiator */
bool chsw_en; /* Indicate if channel switch is enabled */
u8 last_tid; /* TID of the latest MPDU transmitted over the
TDLS direct link to the TDLS STA */
u16 last_sn; /* Sequence number of the latest MPDU transmitted
over the TDLS direct link to the TDLS STA */
bool ps_on; /* Indicate if the power save is enabled on the
TDLS STA */
bool chsw_allowed; /* Indicate if TDLS channel switch is allowed */
};
/**
* enum rwnx_ap_flags - AP flags
*
* @RWNX_AP_ISOLATE Isolate clients (i.e. Don't brige packets transmitted by
* one client for another one)
*/
enum rwnx_ap_flags {
RWNX_AP_ISOLATE = BIT(0),
};
/*
* Structure used to save information relative to the managed interfaces.
* This is also linked within the rwnx_hw vifs list.
*
*/
struct rwnx_vif {
struct list_head list;
struct rwnx_hw *rwnx_hw;
struct wireless_dev wdev;
struct net_device *ndev;
struct net_device_stats net_stats;
struct rwnx_key key[6];
unsigned long drv_flags;
atomic_t drv_conn_state;
u8 drv_vif_index; /* Identifier of the VIF in driver */
u8 vif_index; /* Identifier of the station in FW */
u8 ch_index; /* Channel context identifier */
bool up; /* Indicate if associated netdev is up
(i.e. Interface is created at fw level) */
bool use_4addr; /* Should we use 4addresses mode */
bool is_resending; /* Indicate if a frame is being resent on this interface */
bool user_mpm; /* In case of Mesh Point VIF, indicate if MPM is handled by userspace */
bool roc_tdls; /* Indicate if the ROC has been called by a
TDLS station */
u8 tdls_status; /* Status of the TDLS link */
bool tdls_chsw_prohibited; /* Indicate if TDLS Channel Switch is prohibited */
bool wep_enabled; /* 1 if WEP is enabled */
bool wep_auth_err; /* 1 if auth status code is not supported auth alg when WEP enabled */
enum nl80211_auth_type last_auth_type; /* Authentication type (algorithm) sent in the last connection
when WEP enabled */
union {
struct {
struct rwnx_sta *ap; /* Pointer to the peer STA entry allocated for
the AP */
struct rwnx_sta *tdls_sta; /* Pointer to the TDLS station */
bool external_auth; /* Indicate if external authentication is in progress */
u32 group_cipher_type;
u32 paired_cipher_type;
//connected network info start
char ssid[33];//ssid max is 32, but this has one spare for '\0'
int ssid_len;
u8 bssid[ETH_ALEN];
u32 conn_owner_nlportid;
bool is_roam;
//connected network info end
} sta;
struct {
u16 flags; /* see rwnx_ap_flags */
struct list_head sta_list; /* List of STA connected to the AP */
struct rwnx_bcn bcn; /* beacon */
u8 bcmc_index; /* Index of the BCMC sta to use */
#if (defined CONFIG_HE_FOR_OLD_KERNEL) || (defined CONFIG_VHT_FOR_OLD_KERNEL)
u8 aic_index;
#endif
struct rwnx_csa *csa;
struct list_head mpath_list; /* List of Mesh Paths used on this interface */
struct list_head proxy_list; /* List of Proxies Information used on this interface */
bool create_path; /* Indicate if we are waiting for a MESH_CREATE_PATH_CFM
message */
int generation; /* Increased each time the list of Mesh Paths is updated */
enum nl80211_mesh_power_mode mesh_pm; /* mesh power save mode currently set in firmware */
enum nl80211_mesh_power_mode next_mesh_pm; /* mesh power save mode for next peer */
} ap;
struct {
struct rwnx_vif *master; /* pointer on master interface */
struct rwnx_sta *sta_4a;
} ap_vlan;
};
u8_l key_has_add;
u8_l is_p2p_vif;
struct apm_probe_sta sta_probe;
#ifdef CONFIG_BR_SUPPORT
spinlock_t br_ext_lock;
/* unsigned int macclone_completed; */
struct nat25_network_db_entry *nethash[NAT25_HASH_SIZE];
int pppoe_connection_in_progress;
unsigned char pppoe_addr[MACADDRLEN];
unsigned char scdb_mac[MACADDRLEN];
unsigned char scdb_ip[4];
struct nat25_network_db_entry *scdb_entry;
unsigned char br_mac[MACADDRLEN];
unsigned char br_ip[4];
struct br_ext_info ethBrExtInfo;
#endif /* CONFIG_BR_SUPPORT */
};
#define RWNX_VIF_TYPE(rwnx_vif) (rwnx_vif->wdev.iftype)
/**
* Structure used to store information relative to PS mode.
*
* @active: True when the sta is in PS mode.
* If false, other values should be ignored
* @pkt_ready: Number of packets buffered for the sta in drv's txq
* (1 counter for Legacy PS and 1 for U-APSD)
* @sp_cnt: Number of packets that remain to be pushed in the service period.
* 0 means that no service period is in progress
* (1 counter for Legacy PS and 1 for U-APSD)
*/
struct rwnx_sta_ps {
bool active;
u16 pkt_ready[2];
u16 sp_cnt[2];
};
/**
* struct rwnx_rx_rate_stats - Store statistics for RX rates
*
* @table: Table indicating how many frame has been receive which each
* rate index. Rate index is the same as the one used by RC algo for TX
* @size: Size of the table array
* @cpt: number of frames received
*/
struct rwnx_rx_rate_stats {
int *table;
int size;
int cpt;
int rate_cnt;
};
/**
* struct rwnx_sta_stats - Structure Used to store statistics specific to a STA
*
* @last_rx: Hardware vector of the last received frame
* @rx_rate: Statistics of the received rates
*/
struct rwnx_sta_stats {
struct hw_vect last_rx;
struct rwnx_rx_rate_stats rx_rate;
};
#if (defined CONFIG_HE_FOR_OLD_KERNEL) || (defined CONFIG_VHT_FOR_OLD_KERNEL)
struct aic_sta {
u8 sta_idx; /* Identifier of the station */
bool he; /* Flag indicating if the station supports HE */
bool vht; /* Flag indicating if the station supports VHT */
};
#endif
/*
* Structure used to save information relative to the managed stations.
*/
struct rwnx_sta {
struct list_head list;
u16 aid; /* association ID */
u8 sta_idx; /* Identifier of the station */
u8 vif_idx; /* Identifier of the VIF (fw id) the station
belongs to */
u8 vlan_idx; /* Identifier of the VLAN VIF (fw id) the station
belongs to (= vif_idx if no vlan in used) */
enum nl80211_band band; /* Band */
enum nl80211_chan_width width; /* Channel width */
u16 center_freq; /* Center frequency */
u32 center_freq1; /* Center frequency 1 */
u32 center_freq2; /* Center frequency 2 */
u8 ch_idx; /* Identifier of the channel
context the station belongs to */
bool qos; /* Flag indicating if the station
supports QoS */
u8 acm; /* Bitfield indicating which queues
have AC mandatory */
u16 uapsd_tids; /* Bitfield indicating which tids are subject to
UAPSD */
u8 mac_addr[ETH_ALEN]; /* MAC address of the station */
struct rwnx_key key;
bool valid; /* Flag indicating if the entry is valid */
struct rwnx_sta_ps ps; /* Information when STA is in PS (AP only) */
#ifdef CONFIG_RWNX_BFMER
struct rwnx_bfmer_report *bfm_report; /* Beamforming report to be used for
VHT TX Beamforming */
#ifdef CONFIG_RWNX_MUMIMO_TX
struct rwnx_sta_group_info group_info; /* MU grouping information for the STA */
#endif /* CONFIG_RWNX_MUMIMO_TX */
#endif /* CONFIG_RWNX_BFMER */
bool ht; /* Flag indicating if the station
supports HT */
bool vht; /* Flag indicating if the station
supports VHT */
u32 ac_param[AC_MAX]; /* EDCA parameters */
struct rwnx_tdls tdls; /* TDLS station information */
struct rwnx_sta_stats stats;
enum nl80211_mesh_power_mode mesh_pm; /* link-specific mesh power save mode */
};
static inline const u8 *rwnx_sta_addr(struct rwnx_sta *rwnx_sta)
{
return rwnx_sta->mac_addr;
}
#ifdef CONFIG_RWNX_SPLIT_TX_BUF
struct rwnx_amsdu_stats {
int done;
int failed;
};
#endif
struct rwnx_stats {
int cfm_balance[NX_TXQ_CNT];
unsigned long last_rx, last_tx; /* jiffies */
int ampdus_tx[IEEE80211_MAX_AMPDU_BUF];
int ampdus_rx[IEEE80211_MAX_AMPDU_BUF];
int ampdus_rx_map[4];
int ampdus_rx_miss;
#ifdef CONFIG_RWNX_SPLIT_TX_BUF
struct rwnx_amsdu_stats amsdus[NX_TX_PAYLOAD_MAX];
#endif
int amsdus_rx[64];
};
struct rwnx_sec_phy_chan {
u16 prim20_freq;
u16 center_freq1;
u16 center_freq2;
enum nl80211_band band;
u8 type;
};
/* Structure that will contains all RoC information received from cfg80211 */
struct rwnx_roc_elem {
struct wireless_dev *wdev;
struct ieee80211_channel *chan;
unsigned int duration;
/* Used to avoid call of CFG80211 callback upon expiration of RoC */
bool mgmt_roc;
/* Indicate if we have switch on the RoC channel */
bool on_chan;
};
/* Structure containing channel survey information received from MAC */
struct rwnx_survey_info {
// Filled
u32 filled;
// Amount of time in ms the radio spent on the channel
u32 chan_time_ms;
// Amount of time the primary channel was sensed busy
u32 chan_time_busy_ms;
// Noise in dbm
s8 noise_dbm;
};
#define RWNX_CH_NOT_SET 0xFF
#define RWNX_INVALID_VIF 0xFF
#define RWNX_INVALID_STA 0xFF
/* Structure containing channel context information */
struct rwnx_chanctx {
struct cfg80211_chan_def chan_def; /* channel description */
u8 count; /* number of vif using this ctxt */
};
/**
* rwnx_phy_info - Phy information
*
* @phy_cnt: Number of phy interface
* @cfg: Configuration send to firmware
* @sec_chan: Channel configuration of the second phy interface (if phy_cnt > 1)
* @limit_bw: Set to true to limit BW on requested channel. Only set to use
* VHT with old radio that don't support 80MHz (deprecated)
*/
struct rwnx_phy_info {
u8 cnt;
struct phy_cfg_tag cfg;
struct rwnx_sec_phy_chan sec_chan;
bool limit_bw;
};
struct defrag_ctrl_info {
struct list_head list;
u8 sta_idx;
u8 tid;
u16 sn;
u8 next_fn;
u16 frm_len;
struct sk_buff *skb;
struct timer_list defrag_timer;
struct rwnx_hw *rwnx_hw;
};
struct amsdu_subframe_hdr {
u8 da[6];
u8 sa[6];
u16 sublen;
};
/* rwnx driver status */
enum rwnx_drv_connect_status {
RWNX_DRV_STATUS_DISCONNECTED = 0,
RWNX_DRV_STATUS_DISCONNECTING,
RWNX_DRV_STATUS_CONNECTING,
RWNX_DRV_STATUS_CONNECTED,
};
struct rwnx_hw {
struct rwnx_mod_params *mod_params;
struct device *dev;
#ifdef AICWF_SDIO_SUPPORT
struct aic_sdio_dev *sdiodev;
#endif
#ifdef AICWF_USB_SUPPORT
struct aic_usb_dev *usbdev;
#endif
struct wiphy *wiphy;
struct list_head vifs;
struct rwnx_vif *vif_table[NX_VIRT_DEV_MAX + NX_REMOTE_STA_MAX]; /* indexed with fw id */
struct rwnx_sta sta_table[NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX];
#if (defined CONFIG_HE_FOR_OLD_KERNEL) || (defined CONFIG_VHT_FOR_OLD_KERNEL)
struct aic_sta aic_table[NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX];
#endif
struct rwnx_survey_info survey[SCAN_CHANNEL_MAX];
struct cfg80211_scan_request *scan_request;
#ifdef CONFIG_SCHED_SCAN
struct cfg80211_sched_scan_request *sched_scan_req;
#endif
struct rwnx_chanctx chanctx_table[NX_CHAN_CTXT_CNT];
u8 cur_chanctx;
u8 monitor_vif; /* FW id of the monitor interface, RWNX_INVALID_VIF if no monitor vif at fw level */
#ifdef CONFIG_FILTER_TCP_ACK
/* tcp ack management */
struct tcp_ack_manage ack_m;
#endif
/* RoC Management */
struct rwnx_roc_elem *roc_elem; /* Information provided by cfg80211 in its remain on channel request */
u32 roc_cookie_cnt; /* Counter used to identify RoC request sent by cfg80211 */
struct rwnx_cmd_mgr *cmd_mgr;
struct rwnx_plat *plat;
spinlock_t tx_lock;
spinlock_t cb_lock;
struct mutex mutex; /* per-device perimeter lock */
struct tasklet_struct task;
struct mm_version_cfm version_cfm; /* Lower layers versions - obtained via MM_VERSION_REQ */
u32 tcp_pacing_shift;
/* IPC */
struct ipc_host_env_tag *ipc_env;
#ifdef AICWF_SDIO_SUPPORT
struct sdio_host_env_tag sdio_env;
#endif
#ifdef AICWF_USB_SUPPORT
struct usb_host_env_tag usb_env;
#endif
struct rwnx_ipc_elem_pool e2amsgs_pool;
struct rwnx_ipc_elem_pool dbgmsgs_pool;
struct rwnx_ipc_elem_pool e2aradars_pool;
struct rwnx_ipc_elem_var pattern_elem;
struct rwnx_ipc_dbgdump_elem dbgdump_elem;
struct rwnx_ipc_elem_pool e2arxdesc_pool;
struct rwnx_ipc_skb_elem *e2aunsuprxvec_elems;
//struct rwnx_ipc_rxbuf_elems rxbuf_elems;
struct rwnx_ipc_elem_var scan_ie;
struct kmem_cache *sw_txhdr_cache;
struct rwnx_debugfs debugfs;
struct rwnx_stats stats;
#ifdef CONFIG_PREALLOC_TXQ
struct rwnx_txq *txq;
#else
struct rwnx_txq txq[NX_NB_TXQ];
#endif
struct rwnx_hwq hwq[NX_TXQ_CNT];
u64 avail_idx_map;
u8 vif_started;
bool adding_sta;
struct rwnx_phy_info phy;
struct rwnx_radar radar;
/* extended capabilities supported */
u8 ext_capa[8];
#ifdef CONFIG_RWNX_MUMIMO_TX
struct rwnx_mu_info mu;
#endif
u8 is_p2p_alive;
u8 is_p2p_connected;
struct timer_list p2p_alive_timer;
struct rwnx_vif *p2p_dev_vif;
atomic_t p2p_alive_timer_count;
bool band_5g_support;
u8_l vendor_info;
bool fwlog_en;
struct list_head defrag_list;
spinlock_t defrag_lock;
struct work_struct apmStalossWork;
struct workqueue_struct *apmStaloss_wq;
u8 apm_vif_idx;
u8 sta_mac_addr[6];
struct wakeup_source *ws_rx;
struct wakeup_source *ws_irqrx;
struct wakeup_source *ws_tx;
struct wakeup_source *ws_pwrctrl;
#ifdef CONFIG_SCHED_SCAN
bool is_sched_scan;
#endif//CONFIG_SCHED_SCAN
};
u8 *rwnx_build_bcn(struct rwnx_bcn *bcn, struct cfg80211_beacon_data *new);
void rwnx_chanctx_link(struct rwnx_vif *vif, u8 idx,
struct cfg80211_chan_def *chandef);
void rwnx_chanctx_unlink(struct rwnx_vif *vif);
int rwnx_chanctx_valid(struct rwnx_hw *rwnx_hw, u8 idx);
extern u8 chip_id;
static inline bool is_multicast_sta(int sta_idx)
{
if((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8801) ||
((g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DC || g_rwnx_plat->sdiodev->chipid == PRODUCT_ID_AIC8800DW) && chip_id < 3))
{
return (sta_idx >= NX_REMOTE_STA_MAX_FOR_OLD_IC);
}else{
return (sta_idx >= NX_REMOTE_STA_MAX);
}
}
struct rwnx_sta *rwnx_get_sta(struct rwnx_hw *rwnx_hw, const u8 *mac_addr);
static inline uint8_t master_vif_idx(struct rwnx_vif *vif)
{
if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_AP_VLAN)) {
return vif->ap_vlan.master->vif_index;
} else {
return vif->vif_index;
}
}
void rwnx_external_auth_enable(struct rwnx_vif *vif);
void rwnx_external_auth_disable(struct rwnx_vif *vif);
#endif /* _RWNX_DEFS_H_ */

View File

@ -0,0 +1,297 @@
/**
******************************************************************************
*
* @file rwnx_dini.c - Add support for dini platform
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#include "rwnx_dini.h"
#include "rwnx_defs.h"
#include "rwnx_irqs.h"
#include "reg_access.h"
/* Config FPGA is accessed via bar0 */
#define CFPGA_DMA0_CTRL_REG 0x02C
#define CFPGA_DMA1_CTRL_REG 0x04C
#define CFPGA_DMA2_CTRL_REG 0x06C
#define CFPGA_UINTR_SRC_REG 0x0E8
#define CFPGA_UINTR_MASK_REG 0x0EC
#define CFPGA_BAR4_HIADDR_REG 0x100
#define CFPGA_BAR4_LOADDR_REG 0x104
#define CFPGA_BAR4_LOADDR_MASK_REG 0x110
#define CFPGA_BAR_TOUT 0x120
#define CFPGA_DMA_CTRL_ENABLE 0x00001400
#define CFPGA_DMA_CTRL_DISABLE 0x00001000
#define CFPGA_DMA_CTRL_CLEAR 0x00001800
#define CFPGA_DMA_CTRL_REREAD_TIME_MASK (BIT(10) - 1)
#define CFPGA_BAR4_LOADDR_MASK_MAX 0xFF000000
#define CFPGA_PCIEX_IT 0x00000001
#define CFPGA_ALL_ITS 0x0000000F
/* Programmable BAR4 Window start address */
#define CPU_RAM_WINDOW_HIGH 0x00000000
#define CPU_RAM_WINDOW_LOW 0x00000000
#define AHB_BRIDGE_WINDOW_HIGH 0x00000000
#define AHB_BRIDGE_WINDOW_LOW 0x60000000
struct rwnx_dini {
u8 *pci_bar0_vaddr;
u8 *pci_bar4_vaddr;
};
static const u32 mv_cfg_fpga_dma_ctrl_regs[] = {
CFPGA_DMA0_CTRL_REG,
CFPGA_DMA1_CTRL_REG,
CFPGA_DMA2_CTRL_REG
};
/* This also clears running transactions */
static void dini_dma_on(struct rwnx_dini *rwnx_dini)
{
int i;
u32 reread_time;
volatile void *reg;
for (i = 0; i < ARRAY_SIZE(mv_cfg_fpga_dma_ctrl_regs); i++) {
reg = rwnx_dini->pci_bar0_vaddr + mv_cfg_fpga_dma_ctrl_regs[i];
reread_time = readl(reg) & CFPGA_DMA_CTRL_REREAD_TIME_MASK;
writel(CFPGA_DMA_CTRL_CLEAR | reread_time, reg);
writel(CFPGA_DMA_CTRL_ENABLE | reread_time, reg);
}
}
/* This also clears running transactions */
static void dini_dma_off(struct rwnx_dini *rwnx_dini)
{
int i;
u32 reread_time;
volatile void *reg;
for (i = 0; i < ARRAY_SIZE(mv_cfg_fpga_dma_ctrl_regs); i++) {
reg = rwnx_dini->pci_bar0_vaddr + mv_cfg_fpga_dma_ctrl_regs[i];
reread_time = readl(reg) & CFPGA_DMA_CTRL_REREAD_TIME_MASK;
writel(CFPGA_DMA_CTRL_DISABLE | reread_time, reg);
writel(CFPGA_DMA_CTRL_CLEAR | reread_time, reg);
}
}
/* Configure address range for BAR4.
* By default BAR4_LOADDR_MASK value is 0xFF000000, then there is no need to
* change it because the addresses we need to access are covered by this mask
*/
static void dini_set_bar4_win(u32 low, u32 high, struct rwnx_dini *rwnx_dini)
{
writel(low, rwnx_dini->pci_bar0_vaddr + CFPGA_BAR4_LOADDR_REG);
writel(high, rwnx_dini->pci_bar0_vaddr + CFPGA_BAR4_HIADDR_REG);
writel(CFPGA_BAR4_LOADDR_MASK_MAX,
rwnx_dini->pci_bar0_vaddr + CFPGA_BAR4_LOADDR_MASK_REG);
}
/**
* Enable User Interrupts of CFPGA that trigger PCIe IRQs on PCIE_10
* and request the corresponding IRQ line
*/
int rwnx_cfpga_irq_enable(struct rwnx_hw *rwnx_hw)
{
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
unsigned int cfpga_uintr_mask;
volatile void *reg;
int ret;
/* sched_setscheduler on ONESHOT threaded irq handler for BCNs ? */
ret = request_irq(rwnx_hw->plat->pci_dev->irq, rwnx_irq_hdlr, 0, "rwnx", rwnx_hw);
if (ret)
return ret;
reg = rwnx_dini->pci_bar0_vaddr + CFPGA_UINTR_MASK_REG;
cfpga_uintr_mask = readl(reg);
writel(cfpga_uintr_mask | CFPGA_PCIEX_IT, reg);
return ret;
}
/**
* Disable User Interrupts of CFPGA that trigger PCIe IRQs on PCIE_10
* and free the corresponding IRQ line
*/
int rwnx_cfpga_irq_disable(struct rwnx_hw *rwnx_hw)
{
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
unsigned int cfpga_uintr_mask;
volatile void *reg;
reg = rwnx_dini->pci_bar0_vaddr + CFPGA_UINTR_MASK_REG;
cfpga_uintr_mask = readl(reg);
writel(cfpga_uintr_mask & ~CFPGA_PCIEX_IT, reg);
free_irq(rwnx_hw->plat->pci_dev->irq, rwnx_hw);
return 0;
}
static int rwnx_dini_platform_enable(struct rwnx_hw *rwnx_hw)
{
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
#ifdef CONFIG_RWNX_SDM
writel(0x0000FFFF, rwnx_dini->pci_bar0_vaddr + CFPGA_BAR_TOUT);
#endif
dini_dma_on(rwnx_dini);
return rwnx_cfpga_irq_enable(rwnx_hw);
}
static int rwnx_dini_platform_disable(struct rwnx_hw *rwnx_hw)
{
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
int ret;
ret = rwnx_cfpga_irq_disable(rwnx_hw);
dini_dma_off(rwnx_dini);
return ret;
}
static void rwnx_dini_platform_deinit(struct rwnx_plat *rwnx_plat)
{
struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
pci_disable_device(rwnx_plat->pci_dev);
iounmap(rwnx_dini->pci_bar0_vaddr);
iounmap(rwnx_dini->pci_bar4_vaddr);
pci_release_regions(rwnx_plat->pci_dev);
kfree(rwnx_plat);
}
static u8 *rwnx_dini_get_address(struct rwnx_plat *rwnx_plat, int addr_name,
unsigned int offset)
{
struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
if (WARN(addr_name >= RWNX_ADDR_MAX, "Invalid address %d", addr_name))
return NULL;
if (addr_name == RWNX_ADDR_CPU)
dini_set_bar4_win(CPU_RAM_WINDOW_LOW, CPU_RAM_WINDOW_HIGH, rwnx_dini);
else
dini_set_bar4_win(AHB_BRIDGE_WINDOW_LOW, AHB_BRIDGE_WINDOW_HIGH, rwnx_dini);
return rwnx_dini->pci_bar4_vaddr + offset;
}
static void rwnx_dini_ack_irq(struct rwnx_plat *rwnx_plat)
{
struct rwnx_dini *rwnx_dini = (struct rwnx_dini *)rwnx_plat->priv;
writel(CFPGA_ALL_ITS, rwnx_dini->pci_bar0_vaddr + CFPGA_UINTR_SRC_REG);
}
static const u32 rwnx_dini_config_reg[] = {
NXMAC_DEBUG_PORT_SEL_ADDR,
SYSCTRL_DIAG_CONF_ADDR,
RF_V6_DIAGPORT_CONF1_ADDR,
RF_v6_PHYDIAG_CONF1_ADDR,
};
static int rwnx_dini_get_config_reg(struct rwnx_plat *rwnx_plat, const u32 **list)
{
if (!list)
return 0;
*list = rwnx_dini_config_reg;
return ARRAY_SIZE(rwnx_dini_config_reg);
}
/**
* rwnx_dini_platform_init - Initialize the DINI platform
*
* @pci_dev PCI device
* @rwnx_plat Pointer on struct rwnx_stat * to be populated
*
* @return 0 on success, < 0 otherwise
*
* Allocate and initialize a rwnx_plat structure for the dini platform.
*/
int rwnx_dini_platform_init(struct pci_dev *pci_dev, struct rwnx_plat **rwnx_plat)
{
struct rwnx_dini *rwnx_dini;
u16 pci_cmd;
int ret = 0;
*rwnx_plat = kzalloc(sizeof(struct rwnx_plat) + sizeof(struct rwnx_dini),
GFP_KERNEL);
if (!*rwnx_plat)
return -ENOMEM;
rwnx_dini = (struct rwnx_dini *)(*rwnx_plat)->priv;
/* Hotplug fixups */
pci_read_config_word(pci_dev, PCI_COMMAND, &pci_cmd);
pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
pci_write_config_word(pci_dev, PCI_COMMAND, pci_cmd);
//pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES >> 2);
ret = pci_enable_device(pci_dev);
if (ret) {
dev_err(&(pci_dev->dev), "pci_enable_device failed\n");
goto out_enable;
}
pci_set_master(pci_dev);
#if 0
ret = pci_request_regions(pci_dev, KBUILD_MODNAME);
if (ret) {
dev_err(&(pci_dev->dev), "pci_request_regions failed\n");
goto out_request;
}
#endif
rwnx_dini->pci_bar0_vaddr = (u8 *)pci_ioremap_bar(pci_dev, 0);
if (!rwnx_dini->pci_bar0_vaddr) {
dev_err(&(pci_dev->dev), "pci_ioremap_bar(%d) failed\n", 0);
ret = -ENOMEM;
goto out_bar0;
}
rwnx_dini->pci_bar4_vaddr = (u8 *)pci_ioremap_bar(pci_dev, 4);
if (!rwnx_dini->pci_bar4_vaddr) {
dev_err(&(pci_dev->dev), "pci_ioremap_bar(%d) failed\n", 4);
ret = -ENOMEM;
goto out_bar4;
}
(*rwnx_plat)->enable = rwnx_dini_platform_enable;
(*rwnx_plat)->disable = rwnx_dini_platform_disable;
(*rwnx_plat)->deinit = rwnx_dini_platform_deinit;
(*rwnx_plat)->get_address = rwnx_dini_get_address;
(*rwnx_plat)->ack_irq = rwnx_dini_ack_irq;
(*rwnx_plat)->get_config_reg = rwnx_dini_get_config_reg;
#ifdef CONFIG_RWNX_SDM
writel(0x0000FFFF, rwnx_dini->pci_bar0_vaddr + CFPGA_BAR_TOUT);
#endif
return 0;
out_bar4:
iounmap(rwnx_dini->pci_bar0_vaddr);
out_bar0:
pci_release_regions(pci_dev);
//out_request:
pci_disable_device(pci_dev);
out_enable:
kfree(*rwnx_plat);
return ret;
}

View File

@ -0,0 +1,20 @@
/**
****************************************************************************************
*
* @file rwnx_dini.h
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#ifndef _RWNX_DINI_H_
#define _RWNX_DINI_H_
#include <linux/pci.h>
#include "rwnx_platform.h"
int rwnx_dini_platform_init(struct pci_dev *pci_dev,
struct rwnx_plat **rwnx_plat);
#endif /* _RWNX_DINI_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
/**
******************************************************************************
*
* @file rwnx_fw_trace.c
*
* Copyright (C) RivieraWaves 2017-2019
*
******************************************************************************
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include "rwnx_fw_trace.h"
#include "aicwf_debug.h"
int rwnx_fw_log_init(struct rwnx_fw_log *fw_log)
{
u8 *buf = kmalloc(FW_LOG_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
fw_log->buf.data = buf;
fw_log->buf.start = fw_log->buf.data;
fw_log->buf.size = 0;
fw_log->buf.end = fw_log->buf.data;
fw_log->buf.dataend = fw_log->buf.data + FW_LOG_SIZE;
spin_lock_init(&fw_log->lock);
AICWFDBG(LOGINFO, "fw_log_init: %lx, %lx\n", (unsigned long)fw_log->buf.start, (unsigned long)(fw_log->buf.dataend));
return 0;
}
void rwnx_fw_log_deinit(struct rwnx_fw_log *fw_log)
{
if (!fw_log)
return;
if (fw_log->buf.data)
kfree(fw_log->buf.data);
fw_log->buf.start = NULL;
fw_log->buf.end = NULL;
fw_log->buf.size = 0;
}

View File

@ -0,0 +1,35 @@
/**
******************************************************************************
*
* rwnx_fw_trace.h
*
* Copyright (C) RivieraWaves 2017-2019
*
******************************************************************************
*/
#ifndef _RWNX_FW_TRACE_H_
#define _RWNX_FW_TRACE_H_
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#define FW_LOG_SIZE (10240)
struct rwnx_fw_log_buf {
uint8_t *data;
uint8_t *start;
uint8_t *end;
uint8_t *dataend;
uint32_t size;
};
struct rwnx_fw_log {
struct rwnx_fw_log_buf buf;
spinlock_t lock;
};
int rwnx_fw_log_init(struct rwnx_fw_log *fw_log);
void rwnx_fw_log_deinit(struct rwnx_fw_log *fw_log);
#endif /* _RWNX_FW_TRACE_H_ */

View File

@ -0,0 +1,408 @@
#include <linux/version.h>
#ifdef ANDROID_PLATFORM
#include "net/wireless/core.h"
#endif
#include <include/linux/types.h>
#undef NL80211_MCGRP_MLME
#define NL80211_MCGRP_MLME 3
//#if IS_ENABLED(CONFIG_GKI_OPT_FEATURES) && IS_ENABLED(CONFIG_ANDROID) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0))
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0))
static struct genl_family rwnx_nl80211_fam;
static bool __rwnx_cfg80211_unexpected_frame(struct net_device *dev, u8 cmd,
const u8 *addr, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct sk_buff *msg;
void *hdr;
u32 nlportid = READ_ONCE(wdev->ap_unexpected_nlportid);
if (!nlportid)
return false;
msg = nlmsg_new(100, gfp);
if (!msg)
return true;
hdr = genlmsg_put(msg, 0, 0, &rwnx_nl80211_fam, 0, cmd);
if (!hdr) {
nlmsg_free(msg);
return true;
}
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
goto nla_put_failure;
genlmsg_end(msg, hdr);
genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
return true;
nla_put_failure:
nlmsg_free(msg);
return true;
}
bool rwnx_cfg80211_rx_spurious_frame(struct net_device *dev,
const u8 *addr, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
bool ret;
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
wdev->iftype != NL80211_IFTYPE_P2P_GO)) {
return false;
}
ret = __rwnx_cfg80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
addr, gfp);
return ret;
}
bool rwnx_cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
const u8 *addr, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
bool ret;
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
wdev->iftype != NL80211_IFTYPE_P2P_GO &&
wdev->iftype != NL80211_IFTYPE_AP_VLAN)) {
return false;
}
ret = __rwnx_cfg80211_unexpected_frame(dev,
NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
addr, gfp);
return ret;
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0))
void rwnx_cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
const u8 *ie, u8 ie_len,
int sig_dbm, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct sk_buff *msg;
void *hdr;
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_MESH_POINT))
return;
msg = nlmsg_new(100 + ie_len, gfp);
if (!msg)
return;
hdr = genlmsg_put(msg, 0, 0, &rwnx_nl80211_fam, 0, NL80211_CMD_NEW_PEER_CANDIDATE);
if (!hdr) {
nlmsg_free(msg);
return;
}
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
(ie_len && ie &&
nla_put(msg, NL80211_ATTR_IE, ie_len, ie)) ||
(sig_dbm &&
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)))
goto nla_put_failure;
genlmsg_end(msg, hdr);
#define NL80211_MCGRP_MLME 3
genlmsg_multicast_netns(&rwnx_nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
NL80211_MCGRP_MLME, gfp);
return;
nla_put_failure:
nlmsg_free(msg);
}
#endif
void rwnx_cfg80211_report_obss_beacon(struct wiphy *wiphy,
const u8 *frame, size_t len,
int freq, int sig_dbm)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct sk_buff *msg;
void *hdr;
struct cfg80211_beacon_registration *reg;
spin_lock_bh(&rdev->beacon_registrations_lock);
list_for_each_entry(reg, &rdev->beacon_registrations, list) {
msg = nlmsg_new(len + 100, GFP_ATOMIC);
if (!msg) {
spin_unlock_bh(&rdev->beacon_registrations_lock);
return;
}
hdr = genlmsg_put(msg, 0, 0, &rwnx_nl80211_fam, 0, NL80211_CMD_FRAME);
if (!hdr)
goto nla_put_failure;
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
(freq &&
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
(sig_dbm &&
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
nla_put(msg, NL80211_ATTR_FRAME, len, frame))
goto nla_put_failure;
genlmsg_end(msg, hdr);
genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid);
}
spin_unlock_bh(&rdev->beacon_registrations_lock);
return;
nla_put_failure:
spin_unlock_bh(&rdev->beacon_registrations_lock);
nlmsg_free(msg);
}
static int rwnx_nl80211_send_chandef(struct sk_buff *msg,
const struct cfg80211_chan_def *chandef)
{
if (WARN_ON(!cfg80211_chandef_valid(chandef)))
return -EINVAL;
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
chandef->chan->center_freq))
return -ENOBUFS;
switch (chandef->width) {
case NL80211_CHAN_WIDTH_20_NOHT:
case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_40:
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
cfg80211_get_chandef_type(chandef)))
return -ENOBUFS;
break;
default:
break;
}
if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width))
return -ENOBUFS;
if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1))
return -ENOBUFS;
if (chandef->center_freq2 &&
nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2))
return -ENOBUFS;
return 0;
}
void rwnx_cfg80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
struct cfg80211_chan_def *chandef,
gfp_t gfp,
enum nl80211_commands notif,
u8 count)
{
struct sk_buff *msg;
void *hdr;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
if (!msg)
return;
hdr = genlmsg_put(msg, 0, 0, &rwnx_nl80211_fam, 0, notif);
if (!hdr) {
nlmsg_free(msg);
return;
}
if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
goto nla_put_failure;
if (rwnx_nl80211_send_chandef(msg, chandef))
goto nla_put_failure;
if ((notif == NL80211_CMD_CH_SWITCH_STARTED_NOTIFY) &&
(nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT, count)))
goto nla_put_failure;
genlmsg_end(msg, hdr);
genlmsg_multicast_netns(&rwnx_nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
NL80211_MCGRP_MLME, gfp);
return;
nla_put_failure:
nlmsg_free(msg);
}
void rwnx_cfg80211_ch_switch_started_notify(struct net_device *dev,
struct cfg80211_chan_def *chandef,
u8 count
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
, bool quiet
#endif
)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
rwnx_cfg80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL,
NL80211_CMD_CH_SWITCH_STARTED_NOTIFY, count);
}
int rwnx_regulatory_set_wiphy_regd_sync_rtnl(struct wiphy *wiphy,
struct ieee80211_regdomain *rd)
{
wiphy_apply_custom_regulatory(wiphy, rd);
return 0;
}
void rwnx_skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list)
{
unsigned long flags;
struct sk_buff *prev = old;
struct sk_buff *next = prev->next;
spin_lock_irqsave(&list->lock, flags);
WRITE_ONCE(newsk->next, next);
WRITE_ONCE(newsk->prev, prev);
WRITE_ONCE(next->prev, newsk);
WRITE_ONCE(prev->next, newsk);
list->qlen++;
spin_unlock_irqrestore(&list->lock, flags);
}
bool rwnx_ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
u8 *op_class)
{
u8 vht_opclass;
u32 freq = chandef->center_freq1;
if (freq >= 2412 && freq <= 2472) {
if (chandef->width > NL80211_CHAN_WIDTH_40)
return false;
/* 2.407 GHz, channels 1..13 */
if (chandef->width == NL80211_CHAN_WIDTH_40) {
if (freq > chandef->chan->center_freq)
*op_class = 83; /* HT40+ */
else
*op_class = 84; /* HT40- */
} else {
*op_class = 81;
}
return true;
}
if (freq == 2484) {
/* channel 14 is only for IEEE 802.11b */
if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT)
return false;
*op_class = 82; /* channel 14 */
return true;
}
switch (chandef->width) {
case NL80211_CHAN_WIDTH_80:
vht_opclass = 128;
break;
case NL80211_CHAN_WIDTH_160:
vht_opclass = 129;
break;
case NL80211_CHAN_WIDTH_80P80:
vht_opclass = 130;
break;
case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_5:
return false; /* unsupported for now */
default:
vht_opclass = 0;
break;
}
/* 5 GHz, channels 36..48 */
if (freq >= 5180 && freq <= 5240) {
if (vht_opclass) {
*op_class = vht_opclass;
} else if (chandef->width == NL80211_CHAN_WIDTH_40) {
if (freq > chandef->chan->center_freq)
*op_class = 116;
else
*op_class = 117;
} else {
*op_class = 115;
}
return true;
}
/* 5 GHz, channels 52..64 */
if (freq >= 5260 && freq <= 5320) {
if (vht_opclass) {
*op_class = vht_opclass;
} else if (chandef->width == NL80211_CHAN_WIDTH_40) {
if (freq > chandef->chan->center_freq)
*op_class = 119;
else
*op_class = 120;
} else {
*op_class = 118;
}
return true;
}
/* 5 GHz, channels 100..144 */
if (freq >= 5500 && freq <= 5720) {
if (vht_opclass) {
*op_class = vht_opclass;
} else if (chandef->width == NL80211_CHAN_WIDTH_40) {
if (freq > chandef->chan->center_freq)
*op_class = 122;
else
*op_class = 123;
} else {
*op_class = 121;
}
return true;
}
/* 5 GHz, channels 149..169 */
if (freq >= 5745 && freq <= 5845) {
if (vht_opclass) {
*op_class = vht_opclass;
} else if (chandef->width == NL80211_CHAN_WIDTH_40) {
if (freq > chandef->chan->center_freq)
*op_class = 126;
else
*op_class = 127;
} else if (freq <= 5805) {
*op_class = 124;
} else {
*op_class = 125;
}
return true;
}
/* 56.16 GHz, channel 1..4 */
if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) {
if (chandef->width >= NL80211_CHAN_WIDTH_40)
return false;
*op_class = 180;
return true;
}
/* not supported yet */
return false;
}
int rwnx_call_usermodehelper(const char *path, char **argv, char **envp, int wait)
{
return -1;
}
#endif

View File

@ -0,0 +1,72 @@
#ifndef __RWNX_GKI_H
#define __RWNX_GKI_H
#ifdef ANDROID_PLATFORM
#include "net/wireless/core.h"
#endif
//#if IS_ENABLED(CONFIG_GKI_OPT_FEATURES) && IS_ENABLED(CONFIG_ANDROID) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0))
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0))
bool rwnx_cfg80211_rx_spurious_frame(struct net_device *dev,
const u8 *addr, gfp_t gfp);
bool rwnx_cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
const u8 *addr, gfp_t gfp);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0))
void rwnx_cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
const u8 *ie, u8 ie_len,
int sig_dbm, gfp_t gfp);
#endif
void rwnx_cfg80211_report_obss_beacon(struct wiphy *wiphy,
const u8 *frame, size_t len,
int freq, int sig_dbm);
void rwnx_cfg80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
struct cfg80211_chan_def *chandef,
gfp_t gfp,
enum nl80211_commands notif,
u8 count);
void rwnx_cfg80211_ch_switch_started_notify(struct net_device *dev,
struct cfg80211_chan_def *chandef,
u8 count
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
, bool quiet
#endif
);
int rwnx_regulatory_set_wiphy_regd_sync_rtnl(struct wiphy *wiphy,
struct ieee80211_regdomain *rd);
void rwnx_skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list);
bool rwnx_ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
u8 *op_class);
int rwnx_call_usermodehelper(const char *path, char **argv, char **envp, int wait);
#else
#define rwnx_cfg80211_rx_spurious_frame cfg80211_rx_spurious_frame
#define rwnx_cfg80211_rx_unexpected_4addr_frame cfg80211_rx_unexpected_4addr_frame
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0))
#define rwnx_cfg80211_notify_new_peer_candidate cfg80211_notify_new_peer_candidate
#endif
#define rwnx_cfg80211_report_obss_beacon cfg80211_report_obss_beacon
#define rwnx_cfg80211_ch_switch_notify cfg80211_ch_switch_notify
#define rwnx_cfg80211_ch_switch_started_notify cfg80211_ch_switch_started_notify
#define rwnx_regulatory_set_wiphy_regd_sync_rtnl regulatory_set_wiphy_regd_sync_rtnl
#define rwnx_skb_append skb_append
#define rwnx_ieee80211_chandef_to_operating_class ieee80211_chandef_to_operating_class
#define rwnx_call_usermodehelper call_usermodehelper
#endif
#endif

View File

@ -0,0 +1,65 @@
/**
******************************************************************************
*
* @file rwnx_irqs.c
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#include <linux/interrupt.h>
#include "rwnx_defs.h"
#include "ipc_host.h"
#include "rwnx_prof.h"
/**
* rwnx_irq_hdlr - IRQ handler
*
* Handler registerd by the platform driver
*/
irqreturn_t rwnx_irq_hdlr(int irq, void *dev_id)
{
struct rwnx_hw *rwnx_hw = (struct rwnx_hw *)dev_id;
disable_irq_nosync(irq);
tasklet_schedule(&rwnx_hw->task);
return IRQ_HANDLED;
}
/**
* rwnx_task - Bottom half for IRQ handler
*
* Read irq status and process accordingly
*/
void rwnx_task(unsigned long data)
{
struct rwnx_hw *rwnx_hw = (struct rwnx_hw *)data;
#if 0
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
u32 status, statuses = 0;
/* Ack unconditionnally in case ipc_host_get_status does not see the irq */
rwnx_plat->ack_irq(rwnx_plat);
while ((status = ipc_host_get_status(rwnx_hw->ipc_env))) {
statuses |= status;
/* All kinds of IRQs will be handled in one shot (RX, MSG, DBG, ...)
* this will ack IPC irqs not the cfpga irqs */
ipc_host_irq(rwnx_hw->ipc_env, status);
rwnx_plat->ack_irq(rwnx_plat);
}
#endif
//if (statuses & IPC_IRQ_E2A_RXDESC)
// rwnx_hw->stats.last_rx = now;
//if (statuses & IPC_IRQ_E2A_TXCFM)
// rwnx_hw->stats.last_tx = now;
spin_lock_bh(&rwnx_hw->tx_lock);
rwnx_hwq_process_all(rwnx_hw);
spin_unlock_bh(&rwnx_hw->tx_lock);
#if 0
enable_irq(rwnx_platform_get_irq(rwnx_plat));
#endif
}

View File

@ -0,0 +1,20 @@
/**
******************************************************************************
*
* @file rwnx_irqs.h
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#ifndef _RWNX_IRQS_H_
#define _RWNX_IRQS_H_
#include <linux/interrupt.h>
/* IRQ handler to be registered by platform driver */
irqreturn_t rwnx_irq_hdlr(int irq, void *dev_id);
void rwnx_task(unsigned long data);
#endif /* _RWNX_IRQS_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
/**
******************************************************************************
*
* @file rwnx_main.h
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#ifndef _RWNX_MAIN_H_
#define _RWNX_MAIN_H_
#include "rwnx_defs.h"
typedef struct _android_wifi_priv_cmd {
char *buf;
int used_len;
int total_len;
} android_wifi_priv_cmd;
#ifdef CONFIG_COMPAT
typedef struct _compat_android_wifi_priv_cmd {
compat_caddr_t buf;
int used_len;
int total_len;
} compat_android_wifi_priv_cmd;
#endif /* CONFIG_COMPAT */
int rwnx_cfg80211_init(struct rwnx_plat *rwnx_plat, void **platform_data);
void rwnx_cfg80211_deinit(struct rwnx_hw *rwnx_hw);
extern int testmode;
extern u8 chip_sub_id;
extern u8 chip_mcu_id;
extern u8 chip_id;
#define CHIP_ID_H_MASK 0xC0
#define IS_CHIP_ID_H() ((chip_id & CHIP_ID_H_MASK) == CHIP_ID_H_MASK)
#endif /* _RWNX_MAIN_H_ */

View File

@ -0,0 +1,42 @@
/**
****************************************************************************************
*
* @file rwnx_mesh.c
*
* Copyright (C) RivieraWaves 2016-2019
*
****************************************************************************************
*/
/**
* INCLUDE FILES
****************************************************************************************
*/
#include "rwnx_mesh.h"
/**
* FUNCTION DEFINITIONS
****************************************************************************************
*/
struct rwnx_mesh_proxy *rwnx_get_mesh_proxy_info(struct rwnx_vif *p_rwnx_vif, u8 *p_sta_addr, bool local)
{
struct rwnx_mesh_proxy *p_mesh_proxy = NULL;
struct rwnx_mesh_proxy *p_cur_proxy;
/* Look for proxied devices with provided address */
list_for_each_entry(p_cur_proxy, &p_rwnx_vif->ap.proxy_list, list) {
if (p_cur_proxy->local != local) {
continue;
}
if (!memcmp(&p_cur_proxy->ext_sta_addr, p_sta_addr, ETH_ALEN)) {
p_mesh_proxy = p_cur_proxy;
break;
}
}
/* Return the found information */
return p_mesh_proxy;
}

View File

@ -0,0 +1,45 @@
/**
****************************************************************************************
*
* @file rwnx_mesh.h
*
* @brief VHT Beamformer function declarations
*
* Copyright (C) RivieraWaves 2016-2019
*
****************************************************************************************
*/
#ifndef _RWNX_MESH_H_
#define _RWNX_MESH_H_
/**
* INCLUDE FILES
****************************************************************************************
*/
#include "rwnx_defs.h"
/**
* DEFINES
****************************************************************************************
*/
/**
* TYPE DEFINITIONS
****************************************************************************************
*/
/**
* FUNCTION DECLARATIONS
****************************************************************************************
*/
/**
****************************************************************************************
* @brief TODO [LT]
****************************************************************************************
*/
struct rwnx_mesh_proxy *rwnx_get_mesh_proxy_info(struct rwnx_vif *p_rwnx_vif, u8 *p_sta_addr, bool local);
#endif /* _RWNX_MESH_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,70 @@
/**
******************************************************************************
*
* @file rwnx_mod_params.h
*
* @brief Declaration of module parameters
*
* Copyright (C) RivieraWaves 2012-2021
*
******************************************************************************
*/
#ifndef _RWNX_MOD_PARAM_H_
#define _RWNX_MOD_PARAM_H_
struct rwnx_mod_params {
bool ht_on;
bool vht_on;
bool he_on;
int mcs_map;
int he_mcs_map;
bool he_ul_on;
bool ldpc_on;
bool stbc_on;
bool gf_rx_on;
int phy_cfg;
int uapsd_timeout;
bool ap_uapsd_on;
bool sgi;
bool sgi80;
bool use_2040;
bool use_80;
bool custregd;
bool custchan;
int nss;
int amsdu_rx_max;
bool bfmee;
bool bfmer;
bool mesh;
bool murx;
bool mutx;
bool mutx_on;
unsigned int roc_dur_max;
int listen_itv;
bool listen_bcmc;
int lp_clk_ppm;
bool ps_on;
int tx_lft;
int amsdu_maxnb;
int uapsd_queues;
bool tdls;
bool uf;
bool auto_reply;
char *ftl;
bool dpsm;
#ifdef CONFIG_RWNX_FULLMAC
bool ant_div;
#endif /* CONFIG_RWNX_FULLMAC */
};
extern struct rwnx_mod_params rwnx_mod_params;
struct rwnx_hw;
struct wiphy;
int rwnx_handle_dynparams(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy);
void rwnx_custregd(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy);
void rwnx_enable_wapi(struct rwnx_hw *rwnx_hw);
void rwnx_enable_mfp(struct rwnx_hw *rwnx_hw);
#endif /* _RWNX_MOD_PARAM_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,19 @@
/**
****************************************************************************************
*
* @file rwnx_msg_rx.h
*
* @brief RX function declarations
*
* Copyright (C) RivieraWaves 2012-2019
*
****************************************************************************************
*/
#ifndef _RWNX_MSG_RX_H_
#define _RWNX_MSG_RX_H_
void rwnx_rx_handle_msg(struct rwnx_hw *rwnx_hw, struct ipc_e2a_msg *msg);
void rwnx_rx_handle_print(struct rwnx_hw *rwnx_hw, u8 *msg, u32 len);
#endif /* _RWNX_MSG_RX_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,186 @@
/**
****************************************************************************************
*
* @file rwnx_msg_tx.h
*
* @brief TX function declarations
*
* Copyright (C) RivieraWaves 2012-2019
*
****************************************************************************************
*/
#ifndef _RWNX_MSG_TX_H_
#define _RWNX_MSG_TX_H_
#include "rwnx_defs.h"
int rwnx_send_reset(struct rwnx_hw *rwnx_hw);
int rwnx_send_start(struct rwnx_hw *rwnx_hw);
int rwnx_send_version_req(struct rwnx_hw *rwnx_hw, struct mm_version_cfm *cfm);
int rwnx_send_add_if (struct rwnx_hw *rwnx_hw, const unsigned char *mac,
enum nl80211_iftype iftype, bool p2p, struct mm_add_if_cfm *cfm);
int rwnx_send_remove_if (struct rwnx_hw *rwnx_hw, u8 vif_index, bool defer);
int rwnx_send_set_channel(struct rwnx_hw *rwnx_hw, int phy_idx,
struct mm_set_channel_cfm *cfm);
int rwnx_send_key_add(struct rwnx_hw *rwnx_hw, u8 vif_idx, u8 sta_idx, bool pairwise,
u8 *key, u8 key_len, u8 key_idx, u8 cipher_suite,
struct mm_key_add_cfm *cfm);
int rwnx_send_key_del(struct rwnx_hw *rwnx_hw, uint8_t hw_key_idx);
int rwnx_send_bcn(struct rwnx_hw *rwnx_hw, u8 *buf, u8 vif_idx, u16 bcn_len);
int rwnx_send_bcn_change(struct rwnx_hw *rwnx_hw, u8 vif_idx, u32 bcn_addr,
u16 bcn_len, u16 tim_oft, u16 tim_len, u16 *csa_oft);
int rwnx_send_tim_update(struct rwnx_hw *rwnx_hw, u8 vif_idx, u16 aid,
u8 tx_status);
int rwnx_send_roc(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
struct ieee80211_channel *chan, unsigned int duration, struct mm_remain_on_channel_cfm *roc_cfm);
int rwnx_send_cancel_roc(struct rwnx_hw *rwnx_hw);
int rwnx_send_set_power(struct rwnx_hw *rwnx_hw, u8 vif_idx, s8 pwr,
struct mm_set_power_cfm *cfm);
int rwnx_send_set_edca(struct rwnx_hw *rwnx_hw, u8 hw_queue, u32 param,
bool uapsd, u8 inst_nbr);
int rwnx_send_tdls_chan_switch_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
struct rwnx_sta *rwnx_sta, bool sta_initiator,
u8 oper_class, struct cfg80211_chan_def *chandef,
struct tdls_chan_switch_cfm *cfm);
int rwnx_send_tdls_cancel_chan_switch_req(struct rwnx_hw *rwnx_hw,
struct rwnx_vif *rwnx_vif,
struct rwnx_sta *rwnx_sta,
struct tdls_cancel_chan_switch_cfm *cfm);
#ifdef CONFIG_RWNX_P2P_DEBUGFS
int rwnx_send_p2p_oppps_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
u8 ctw, struct mm_set_p2p_oppps_cfm *cfm);
int rwnx_send_p2p_noa_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
int count, int interval, int duration,
bool dyn_noa, struct mm_set_p2p_noa_cfm *cfm);
#endif /* CONFIG_RWNX_P2P_DEBUGFS */
#ifdef AICWF_ARP_OFFLOAD
int rwnx_send_arpoffload_en_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
u32_l ipaddr, u8_l enable);
#endif
int rwnx_send_rf_config_req(struct rwnx_hw *rwnx_hw, u8_l ofst, u8_l sel, u8_l *tbl, u16_l len);
int rwnx_send_rf_calib_req(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm);
int rwnx_send_get_macaddr_req(struct rwnx_hw *rwnx_hw, struct mm_get_mac_addr_cfm *cfm);
#ifdef CONFIG_RWNX_FULLMAC
int rwnx_send_me_config_req(struct rwnx_hw *rwnx_hw);
int rwnx_send_me_chan_config_req(struct rwnx_hw *rwnx_hw);
int rwnx_send_me_set_control_port_req(struct rwnx_hw *rwnx_hw, bool opened,
u8 sta_idx);
int rwnx_send_me_sta_add(struct rwnx_hw *rwnx_hw, struct station_parameters *params,
const u8 *mac, u8 inst_nbr, struct me_sta_add_cfm *cfm);
int rwnx_send_me_sta_del(struct rwnx_hw *rwnx_hw, u8 sta_idx, bool tdls_sta);
int rwnx_send_me_traffic_ind(struct rwnx_hw *rwnx_hw, u8 sta_idx, bool uapsd, u8 tx_status);
int rwnx_send_me_rc_stats(struct rwnx_hw *rwnx_hw, u8 sta_idx,
struct me_rc_stats_cfm *cfm);
int rwnx_send_me_rc_set_rate(struct rwnx_hw *rwnx_hw,
u8 sta_idx,
u16 rate_idx);
int rwnx_send_me_set_ps_mode(struct rwnx_hw *rwnx_hw, u8 ps_mode);
int rwnx_send_me_set_lp_level(struct rwnx_hw *rwnx_hw, u8 lp_level);
int rwnx_send_sm_connect_req(struct rwnx_hw *rwnx_hw,
struct rwnx_vif *rwnx_vif,
struct cfg80211_connect_params *sme,
struct sm_connect_cfm *cfm);
int rwnx_send_sm_disconnect_req(struct rwnx_hw *rwnx_hw,
struct rwnx_vif *rwnx_vif,
u16 reason);
int rwnx_send_sm_external_auth_required_rsp(struct rwnx_hw *rwnx_hw,
struct rwnx_vif *rwnx_vif,
u16 status);
int rwnx_send_apm_start_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
struct cfg80211_ap_settings *settings,
struct apm_start_cfm *cfm,
struct rwnx_ipc_elem_var *elem);
int rwnx_send_apm_stop_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif);
int rwnx_send_scanu_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
struct cfg80211_scan_request *param);
int rwnx_send_scanu_cancel_req(struct rwnx_hw *rwnx_hw,
struct scan_cancel_cfm *cfm);
int rwnx_send_apm_start_cac_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
struct cfg80211_chan_def *chandef,
struct apm_start_cac_cfm *cfm);
int rwnx_send_apm_stop_cac_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif);
int rwnx_send_tdls_peer_traffic_ind_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif);
int rwnx_send_config_monitor_req(struct rwnx_hw *rwnx_hw,
struct cfg80211_chan_def *chandef,
struct me_config_monitor_cfm *cfm);
int rwnx_send_mesh_start_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
const struct mesh_config *conf, const struct mesh_setup *setup,
struct mesh_start_cfm *cfm);
int rwnx_send_mesh_stop_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
struct mesh_stop_cfm *cfm);
int rwnx_send_mesh_update_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
u32 mask, const struct mesh_config *p_mconf, struct mesh_update_cfm *cfm);
int rwnx_send_mesh_peer_info_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
u8 sta_idx, struct mesh_peer_info_cfm *cfm);
void rwnx_send_mesh_peer_update_ntf(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif,
u8 sta_idx, u8 mlink_state);
void rwnx_send_mesh_path_create_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif, u8 *tgt_addr);
int rwnx_send_mesh_path_update_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif, const u8 *tgt_addr,
const u8 *p_nhop_addr, struct mesh_path_update_cfm *cfm);
void rwnx_send_mesh_proxy_add_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *vif, u8 *ext_addr);
#endif /* CONFIG_RWNX_FULLMAC */
#ifdef CONFIG_RWNX_BFMER
#ifdef CONFIG_RWNX_FULLMAC
void rwnx_send_bfmer_enable(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta,
const struct ieee80211_vht_cap *vht_cap);
#endif /* CONFIG_RWNX_FULLMAC */
#ifdef CONFIG_RWNX_MUMIMO_TX
int rwnx_send_mu_group_update_req(struct rwnx_hw *rwnx_hw, struct rwnx_sta *rwnx_sta);
#endif /* CONFIG_RWNX_MUMIMO_TX */
#endif /* CONFIG_RWNX_BFMER */
/* Debug messages */
int rwnx_send_dbg_trigger_req(struct rwnx_hw *rwnx_hw, char *msg);
int rwnx_send_dbg_mem_read_req(struct rwnx_hw *rwnx_hw, u32 mem_addr,
struct dbg_mem_read_cfm *cfm);
int rwnx_send_dbg_mem_write_req(struct rwnx_hw *rwnx_hw, u32 mem_addr,
u32 mem_data);
int rwnx_send_dbg_mem_mask_write_req(struct rwnx_hw *rwnx_hw, u32 mem_addr,
u32 mem_mask, u32 mem_data);
int rwnx_send_dbg_set_mod_filter_req(struct rwnx_hw *rwnx_hw, u32 filter);
#ifdef CONFIG_RFTEST
int rwnx_send_rftest_req(struct rwnx_hw *rwnx_hw, u32_l cmd, u32_l argc, u8_l *argv, struct dbg_rftest_cmd_cfm *cfm);
#endif
#ifdef CONFIG_MCU_MESSAGE
int rwnx_send_dbg_custom_msg_req(struct rwnx_hw *rwnx_hw,
u32 cmd, void *buf, u32 len, u32 action,
struct dbg_custom_msg_cfm *cfm);
#endif
int rwnx_send_dbg_set_sev_filter_req(struct rwnx_hw *rwnx_hw, u32 filter);
int rwnx_send_dbg_get_sys_stat_req(struct rwnx_hw *rwnx_hw,
struct dbg_get_sys_stat_cfm *cfm);
int rwnx_send_dbg_mem_block_write_req(struct rwnx_hw *rwnx_hw, u32 mem_addr,
u32 mem_size, u32 *mem_data);
int rwnx_send_dbg_start_app_req(struct rwnx_hw *rwnx_hw, u32 boot_addr,
u32 boot_type);
int rwnx_send_cfg_rssi_req(struct rwnx_hw *rwnx_hw, u8 vif_index, int rssi_thold, u32 rssi_hyst);
int rwnx_send_disable_agg_req(struct rwnx_hw *rwnx_hw, u8_l agg_disable, u8_l agg_disable_rx, u8_l sta_idx);
int rwnx_send_coex_req(struct rwnx_hw *rwnx_hw, u8_l disable_coexnull, u8_l enable_nullcts);
int rwnx_send_get_sta_info_req(struct rwnx_hw *rwnx_hw, u8_l sta_idx, struct mm_get_sta_info_cfm *cfm);
int rwnx_send_set_stack_start_req(struct rwnx_hw *rwnx_hw, u8_l on, u8_l efuse_valid, u8_l set_vendor_info,
u8_l fwtrace_redir_en, struct mm_set_stack_start_cfm *cfm);
int rwnx_send_txop_req(struct rwnx_hw *rwnx_hw, uint16_t *txop, u8_l long_nav_en, u8_l cfe_en);
int rwnx_send_set_temp_comp_req(struct rwnx_hw *rwnx_hw, struct mm_set_vendor_swconfig_cfm *cfm);
int rwnx_send_vendor_hwconfig_req(struct rwnx_hw *rwnx_hw, uint32_t hwconfig_id, int32_t *param, int32_t *param_out);
int rwnx_send_vendor_swconfig_req(struct rwnx_hw *rwnx_hw, uint32_t swconfig_id, int32_t *param_in, int32_t *param_out);
int rwnx_send_mask_set_ext_flags_req(struct rwnx_hw *rwnx_hw, uint32_t flags_mask, uint32_t flags_val, struct mm_set_vendor_swconfig_cfm *cfm);
int rwnx_send_get_fw_version_req(struct rwnx_hw *rwnx_hw, struct mm_get_fw_version_cfm *cfm);
int rwnx_send_txpwr_idx_req(struct rwnx_hw *rwnx_hw);
int rwnx_send_txpwr_ofst_req(struct rwnx_hw *rwnx_hw);
int rwnx_send_txpwr_ofst2x_req(struct rwnx_hw *rwnx_hw);
int rwnx_send_txpwr_lvl_req(struct rwnx_hw *rwnx_hw);
int rwnx_send_txpwr_lvl_v3_req(struct rwnx_hw *rwnx_hw);
int rwnx_send_txpwr_lvl_adj_req(struct rwnx_hw *rwnx_hw);
#ifdef CONFIG_SDIO_BT
int rwnx_sdio_bt_send_req(struct rwnx_hw *rwnx_hw,uint32_t len, struct sk_buff *skb);
#endif
#endif /* _RWNX_MSG_TX_H_ */

Some files were not shown because too many files have changed in this diff Show More