duos: support AIC8800 WiFi6/BTDM5.4 SoC

aic8800d_linux_sdk_V3.0_2023_1219_3cf85031.7z
This commit is contained in:
carbon
2024-01-09 20:51:31 +08:00
parent e67088f6db
commit bf8aaff39b
145 changed files with 81726 additions and 0 deletions

View File

@ -25,6 +25,12 @@
vbus-gpio = <&portb 6 0>;
};
&wifisd {
status = "okay";
min-frequency = <400000>;
max-frequency = <50000000>;
};
/ {
};

View File

@ -110,6 +110,11 @@ CONFIG_CVITEK_PHY_UAPS=y
# CONFIG_WLAN_VENDOR_ST is not set
# CONFIG_WLAN_VENDOR_TI is not set
# CONFIG_WLAN_VENDOR_ZYDAS is not set
CONFIG_WLAN_VENDOR_AICSEMI=y
CONFIG_AIC8800=y
CONFIG_AIC8800_WLAN_SUPPORT=m
CONFIG_AIC8800_BTLPM_SUPPORT=m
CONFIG_AIC_FW_PATH="/mnt/system/firmware/aic8800"
CONFIG_INPUT=y
# CONFIG_SERIO is not set
# CONFIG_VT is not set

View File

@ -15,5 +15,8 @@ int cvi_board_init(void)
// USB
PINMUX_CONFIG(USB_VBUS_EN, XGPIOB_5);
// WIFI/BT
PINMUX_CONFIG(CLK32K, PWR_GPIO_10);
return 0;
}

View File

@ -1,4 +1,29 @@
#!/bin/sh
function set_gpio()
{
local gpio_num=$1
local gpio_val=$2
local gpio_path="/sys/class/gpio/gpio${gpio_num}"
if test -d ${gpio_path}; then
echo "GPIO ${gpio_num} already exported" >> /tmp/gpio.log 2>&1
else
echo ${gpio_num} > /sys/class/gpio/export
fi
echo out > ${gpio_path}/direction
sleep 0.1
echo ${gpio_val} > ${gpio_path}/value
}
# WIFI Power ON
wifi_power=495
set_gpio ${wifi_power} 1
insmod /mnt/system/ko/aic8800_bsp.ko
sleep 0.5
insmod /mnt/system/ko/aic8800_fdrv.ko
# insmod pwm module
insmod /mnt/system/ko/cv181x_pwm.ko

View File

@ -0,0 +1,110 @@
# AIC USERCONFIG 2022/0803/1707
# txpwr_lvl
enable=1
lvl_11b_11ag_1m_2g4=18
lvl_11b_11ag_2m_2g4=18
lvl_11b_11ag_5m5_2g4=18
lvl_11b_11ag_11m_2g4=18
lvl_11b_11ag_6m_2g4=18
lvl_11b_11ag_9m_2g4=18
lvl_11b_11ag_12m_2g4=18
lvl_11b_11ag_18m_2g4=18
lvl_11b_11ag_24m_2g4=16
lvl_11b_11ag_36m_2g4=16
lvl_11b_11ag_48m_2g4=15
lvl_11b_11ag_54m_2g4=15
lvl_11n_11ac_mcs0_2g4=18
lvl_11n_11ac_mcs1_2g4=18
lvl_11n_11ac_mcs2_2g4=18
lvl_11n_11ac_mcs3_2g4=18
lvl_11n_11ac_mcs4_2g4=16
lvl_11n_11ac_mcs5_2g4=16
lvl_11n_11ac_mcs6_2g4=15
lvl_11n_11ac_mcs7_2g4=15
lvl_11n_11ac_mcs8_2g4=14
lvl_11n_11ac_mcs9_2g4=14
lvl_11ax_mcs0_2g4=18
lvl_11ax_mcs1_2g4=18
lvl_11ax_mcs2_2g4=18
lvl_11ax_mcs3_2g4=18
lvl_11ax_mcs4_2g4=16
lvl_11ax_mcs5_2g4=16
lvl_11ax_mcs6_2g4=15
lvl_11ax_mcs7_2g4=15
lvl_11ax_mcs8_2g4=14
lvl_11ax_mcs9_2g4=14
lvl_11ax_mcs10_2g4=13
lvl_11ax_mcs11_2g4=13
lvl_11a_6m_5g=18
lvl_11a_9m_5g=18
lvl_11a_12m_5g=18
lvl_11a_18m_5g=18
lvl_11a_24m_5g=16
lvl_11a_36m_5g=16
lvl_11a_48m_5g=15
lvl_11a_54m_5g=15
lvl_11n_11ac_mcs0_5g=18
lvl_11n_11ac_mcs1_5g=18
lvl_11n_11ac_mcs2_5g=18
lvl_11n_11ac_mcs3_5g=18
lvl_11n_11ac_mcs4_5g=16
lvl_11n_11ac_mcs5_5g=16
lvl_11n_11ac_mcs6_5g=15
lvl_11n_11ac_mcs7_5g=15
lvl_11n_11ac_mcs8_5g=14
lvl_11n_11ac_mcs9_5g=14
lvl_11ax_mcs0_5g=18
lvl_11ax_mcs1_5g=18
lvl_11ax_mcs2_5g=18
lvl_11ax_mcs3_5g=18
lvl_11ax_mcs4_5g=16
lvl_11ax_mcs5_5g=16
lvl_11ax_mcs6_5g=14
lvl_11ax_mcs7_5g=14
lvl_11ax_mcs8_5g=13
lvl_11ax_mcs9_5g=13
lvl_11ax_mcs10_5g=12
lvl_11ax_mcs11_5g=12
# txpwr_loss
loss_enable=0
loss_value=2
# txpwr_ofst
ofst_enable=0
ofst_2g4_11b_chan_1_4=0
ofst_2g4_11b_chan_5_9=0
ofst_2g4_11b_chan_10_13=0
ofst_2g4_ofdm_highrate_chan_1_4=0
ofst_2g4_ofdm_highrate_chan_5_9=0
ofst_2g4_ofdm_highrate_chan_10_13=0
ofst_2g4_ofdm_lowrate_chan_1_4=0
ofst_2g4_ofdm_lowrate_chan_5_9=0
ofst_2g4_ofdm_lowrate_chan_10_13=0
ofst_5g_ofdm_lowrate_chan_42=0
ofst_5g_ofdm_lowrate_chan_58=0
ofst_5g_ofdm_lowrate_chan_106=0
ofst_5g_ofdm_lowrate_chan_122=0
ofst_5g_ofdm_lowrate_chan_138=0
ofst_5g_ofdm_lowrate_chan_155=0
ofst_5g_ofdm_highrate_chan_42=0
ofst_5g_ofdm_highrate_chan_58=0
ofst_5g_ofdm_highrate_chan_106=0
ofst_5g_ofdm_highrate_chan_122=0
ofst_5g_ofdm_highrate_chan_138=0
ofst_5g_ofdm_highrate_chan_155=0
ofst_5g_ofdm_midrate_chan_42=0
ofst_5g_ofdm_midrate_chan_58=0
ofst_5g_ofdm_midrate_chan_106=0
ofst_5g_ofdm_midrate_chan_122=0
ofst_5g_ofdm_midrate_chan_138=0
ofst_5g_ofdm_midrate_chan_155=0
# xtal cap
xtal_enable=0
xtal_cap=24
xtal_cap_fine=31

View File

@ -49,6 +49,7 @@ source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/zydas/Kconfig"
source "drivers/net/wireless/quantenna/Kconfig"
source "drivers/net/wireless/icommsemi/Kconfig"
source "drivers/net/wireless/aicsemi/Kconfig"
config PCMCIA_RAYCS
tristate "Aviator/Raytheon 2.4GHz wireless support"

View File

@ -21,6 +21,7 @@ obj-$(CONFIG_WLAN_VENDOR_TI) += ti/
obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/
obj-$(CONFIG_WLAN_VENDOR_QUANTENNA) += quantenna/
obj-$(CONFIG_WLAN_VENDOR_ICOMMSEMI) += icommsemi/
obj-$(CONFIG_WLAN_VENDOR_AICSEMI) += aicsemi/
# 16-bit wireless PCMCIA client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o

View File

@ -0,0 +1,16 @@
config WLAN_VENDOR_AICSEMI
bool "AICSEMI devices"
default y
help
If you have a wireless card belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all the
questions about these cards. If you say Y, you will be asked for
your specific card in the following questions.
if WLAN_VENDOR_AICSEMI
source "drivers/net/wireless/aicsemi/aic8800/Kconfig"
endif # WLAN_VENDOR_AICSEMI

View File

@ -0,0 +1,6 @@
#
# Makefile for the Linux Wireless network device drivers for AICSEMI units
#
obj-$(CONFIG_AIC8800) += aic8800/

View File

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

View File

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

View File

@ -0,0 +1,94 @@
CONFIG_AIC8800_BTLPM_SUPPORT := m
CONFIG_AIC8800_WLAN_SUPPORT := m
CONFIG_AIC8800 := m
obj-$(CONFIG_AIC8800_BTLPM_SUPPORT) += aic8800_btlpm/
obj-$(CONFIG_AIC8800_WLAN_SUPPORT) += aic8800_fdrv/
obj-$(CONFIG_AIC8800) += aic8800_bsp/
# Platform support list
CONFIG_PLATFORM_ROCKCHIP = n
CONFIG_PLATFORM_ROCKCHIP2 = n
CONFIG_PLATFORM_ALLWINNER = n
CONFIG_PLATFORM_AMLOGIC = n
CONFIG_PLATFORM_UBUNTU = n
CONFIG_PLATFORM_CVITEK = y
MAKEFLAGS +=-j$(shell nproc)
ifeq ($(CONFIG_PLATFORM_ROCKCHIP), y)
#KDIR = /home/yaya/E/Rockchip/3229/Android7/RK3229_ANDROID7.1_v1.01_20170914/rk3229_Android7.1_v1.01_xml0914/kernel
#ARCH = arm
#CROSS_COMPILE = /home/yaya/E/Rockchip/3229/Android7/RK3229_ANDROID7.1_v1.01_20170914/rk3229_Android7.1_v1.01_xml0914/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-
KDIR = /home/yaya/E/Rockchip/3229/Android9/rk3229_android9.0_box/kernel
ARCH = arm
CROSS_COMPILE = /home/yaya/E/Rockchip/3229/Android9/rk3229_android9.0_box/prebuilts/gcc/linux-x86/arm/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
#KDIR = /home/yaya/E/Rockchip/3399/rk3399-android-10/kernel
#ARCH = arm64
#CROSS_COMPILE = /home/yaya/E/Rockchip/3399/rk3399-android-10/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)
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_ROCKCHIP2
endif
ifeq ($(CONFIG_PLATFORM_ALLWINNER), y)
KDIR = /home/yaya/E/Allwinner/R818/R818/AndroidQ/lichee/kernel/linux-4.9
ARCH = arm64
CROSS_COMPILE = /home/yaya/E/Allwinner/R818/R818/AndroidQ/lichee/out/gcc-linaro-5.3.1-2016.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
ccflags-y += -DANDROID_PLATFORM
endif
ifeq ($(CONFIG_PLATFORM_AMLOGIC), y)
ccflags-y += -DANDROID_PLATFORM
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/
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
ifeq ($(CONFIG_PLATFORM_CVITEK), y)
ARCH ?= riscv
#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 .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,163 @@
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_ONE_TXQ = n
CONFIG_DPD = y
CONFIG_FORCE_DPD_CALIB = y
CONFIG_RESV_MEM_SUPPORT = y
CONFIG_AMSDU_RX ?=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_ONE_TXQ) += -DCONFIG_ONE_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
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 ?= n
CONFIG_PLATFORM_CVITEK ?= y
ifeq ($(CONFIG_PLATFORM_ROCKCHIP), y)
ccflags-$(CONFIG_PLATFORM_ROCKCHIP) += -DCONFIG_PLATFORM_ROCKCHIP
#KDIR ?= /home/yaya/E/Rockchip/3399/rk3399-android-10/kernel
#ARCH ?= arm64
#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3399/rk3399-android-10/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
#KDIR ?= /home/yaya/E/Rockchip/3288/Android10/kernel/kernel/
#ARCH ?= arm
#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3288/Android10/tool/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
#KDIR ?= /home/yaya/E/Rockchip/3229/Android7/RK3229_ANDROID7.1_v1.01_20170914/rk3229_Android7.1_v1.01_xml0914/kernel
#ARCH ?= arm
#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3229/Android7/RK3229_ANDROID7.1_v1.01_20170914/rk3229_Android7.1_v1.01_xml0914/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-
#KDIR ?= /home/yaya/E/Rockchip/3229/Android9/rk3229_android9.0_box/kernel
#ARCH ?= arm
#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3229/Android9/rk3229_android9.0_box/prebuilts/gcc/linux-x86/arm/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
#KDIR ?= /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/kernel
#KDIR ?= /home/yaya/E/Rockchip/3566/oudu/kernel
#KDIR ?= /home/yaya/E/Rockchip/3566/shengteng/kernel
#ARCH ?= arm64
#CROSS_COMPILE ?= ~/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-
#KDIR ?= /home/yaya/E/Rockchip/3328/Android9/SDK/kernel/
#ARCH ?= arm64
#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3328/Android9/SDK/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
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/A133/a133-sdk/android/longan/out/kernel/build/
#ARCH ?= arm64
#CROSS_COMPILE ?= /home/yaya/E/Allwinner/A133/a133-sdk/android/longan/out/gcc-linaro-5.3.1-2016.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
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
ifeq ($(CONFIG_PLATFORM_CVITEK), y)
ARCH ?= riscv
#CROSS_COMPILE ?=
ccflags-$(CONFIG_PLATFORM_CVITEK) += -DCONFIG_PLATFORM_CVITEK
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,207 @@
#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
};
u32 patch_tbl_8800d80[][2] = {
#ifdef USE_5G
{0x00b4, 0xf3010001},
#else
{0x00b4, 0xf3010000},
#endif
#if defined(CONFIG_AMSDU_RX)
{0x170, 0x0100000a}
#endif
#if AIC_IRQ_WAKE_FLAG
{0x00000170, 0x0000010a}, //irqf
#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;
}
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;
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;
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,566 @@
/**
******************************************************************************
*
* 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"
#define RWNX_MAC_CALIB_NAME_8800DC_H_U02 RWNX_MAC_CALIB_BASE_NAME_8800DC"_h_u02.bin"
#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"
#define RWNX_MAC_PATCH_NAME2_8800DC_H_U02 RWNX_MAC_PATCH_BASE_NAME_8800DC"_h_u02.bin"
#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"
#define RWNX_MAC_PATCH_TABLE_8800DC_H_U02 RWNX_MAC_PATCH_TABLE_NAME_8800DC "_h_u02.bin"
#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
#define AICBT_BTPORT_DEFAULT AICBT_BTPORT_UART
#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 AIC_IRQ_WAKE_FLAG 0 // 0: rising edge, 1: falling edge
#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 0 // 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,379 @@
#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",
.wl_fw = "fmacfw.bin"
},
[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"
#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",
.wl_fw = "fmacfw_8800d80_u02.bin"
},
[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,
.irqf = AIC_IRQ_WAKE_FLAG,
};
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);
#ifdef CONFIG_PLATFORM_ROCKCHIP
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)
{
#ifdef CONFIG_PLATFORM_ROCKCHIP
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,147 @@
/**
* 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;
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,463 @@
/**
* 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");
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;
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 "2023_1219_3cf85031"

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,102 @@
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 ?= n
CONFIG_PLATFORM_CVITEK ?= y
CONFIG_SUPPORT_LPM = y
CONFIG_AUTO_PM ?= n
aic8800_btlpm-y := \
aic_bluetooth_main.o \
rfkill.o \
ifeq ($(CONFIG_PLATFORM_UBUNTU), n)
aic8800_btlpm-$(CONFIG_SUPPORT_LPM) += lpm.o
endif
ccflags-y += -DAIC_TRACE_INCLUDE_PATH=$(src)
ccflags-$(CONFIG_AUTO_PM) += -DCONFIG_AUTO_PM
ifeq ($(CONFIG_PLATFORM_ROCKCHIP), y)
KDIR ?= /home/yaya/E/Rockchip/3229/Android9/rk3229_android9.0_box/kernel
ARCH ?= arm
CROSS_COMPILE ?= /home/yaya/E/Rockchip/3229/Android9/rk3229_android9.0_box/prebuilts/gcc/linux-x86/arm/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
#KDIR ?= /home/yaya/E/Rockchip/3229/Android10/SDK/kernel/
#ARCH ?= arm
#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3229/Android10/SDK/prebuilts/gcc/linux-x86/arm/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
#KDIR ?= /home/yaya/E/Rockchip/3288/Android10/kernel/kernel/
#ARCH ?= arm
#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3288/Android10/tool/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux#-gnueabihf-
#KDIR ?= /home/yaya/E/Rockchip/3229/Android7/RK3229_ANDROID7.1_v1.01_20170914/rk3229_Android7.1_v1.01_xml0914/kernel
#ARCH ?= arm
#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3229/Android7/RK3229_ANDROID7.1_v1.01_20170914/rk3229_Android7.1_v1.01_xml0914/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-
#KDIR ?= /home/yaya/E/Rockchip/3328/Android9/SDK/SDK/kernel
#ARCH ?= arm64
#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3328/Android9/SDK/SDK/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
ifeq ($(CONFIG_PLATFORM_CVITEK), y)
ARCH ?= riscv
#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,384 @@
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_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_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
# 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_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_RESV_MEM_SUPPORT) += -DCONFIG_RESV_MEM_SUPPORT
ccflags-$(CONFIG_GKI) += -DCONFIG_GKI
ccflags-$(CONFIG_TEMP_COMP) += -DCONFIG_TEMP_COMP
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
# 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
ccflags-y += -DAIC_TRACE_INCLUDE_PATH=$(src)
ifeq ($(CONFIG_PLATFORM_ROCKCHIP), y)
#KDIR ?= /home/yaya/E/Rockchip/3229/Android7/RK3229_ANDROID7.1_v1.01_20170914/rk3229_Android7.1_v1.01_xml0914/kernel
#ARCH ?= arm
#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3229/Android7/RK3229_ANDROID7.1_v1.01_20170914/rk3229_Android7.1_v1.01_xml0914/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-
#KDIR ?= /home/yaya/E/Rockchip/3399/rk3399-android-10/kernel
#ARCH ?= arm64
#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3399/rk3399-android-10/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
#KDIR ?= /home/yaya/E/Rockchip/3288/Android10/kernel/kernel/
#ARCH ?= arm
#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3288/Android10/tool/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
#KDIR ?= /home/yaya/E/Rockchip/3229/Android9/rk3229_android9.0_box/kernel
#ARCH ?= arm
#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3229/Android9/rk3229_android9.0_box/prebuilts/gcc/linux-x86/arm/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
#KDIR ?= /home/yaya/E/Rockchip/3566/Android/kernel
#ARCH ?= arm64
#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3566/Android/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
#KDIR ?= /home/yaya/E/Rockchip/3328/Android9/SDK/kernel/
#ARCH ?= arm64
#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3328/Android9/SDK/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
#KDIR ?= /home/yaya/E/Rockchip/3566/oudu/kernel
KDIR ?= ~/E/Rockchip/3566/Android11/rk3566_rk3568_android11_oranth/kernel
#KDIR ?= /home/yaya/E/Rockchip/3566/shengteng/kernel
ARCH ?= arm64
CROSS_COMPILE ?= ~/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-
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

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,64 @@
#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_ofst2x_req(rwnx_hw))) {
return -1;
}
if (testmode == 0) {
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,175 @@
/**
* 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
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;
#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);
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);
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;*/
/* marlin 2 */
/*unsigned int fifo_id;
struct sprdwl_msg_list *msglist;*/
/* marlin 3 */
/*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

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