hopes and dreams

This commit is contained in:
Tsubajashi 2025-11-19 01:52:34 +01:00
commit 772a90e391
147 changed files with 80636 additions and 0 deletions

Binary file not shown.

BIN
aic8800d80fdrvpackage.deb Normal file

Binary file not shown.

BIN
control.tar.gz Normal file

Binary file not shown.

BIN
data.tar.gz Normal file

Binary file not shown.

1
debian-binary Normal file
View file

@ -0,0 +1 @@
2.0

View file

@ -0,0 +1,4 @@
KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="5721", SYMLINK+="aicudisk", RUN+="/usr/bin/eject /dev/%k"
KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="5723", SYMLINK+="tendaudisk", RUN+="/usr/bin/eject /dev/%k"
KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="5724", SYMLINK+="ugreenudisk", RUN+="/usr/bin/eject /dev/%k"

View file

@ -0,0 +1,10 @@
config AIC_WLAN_SUPPORT
bool "AIC wireless Support"
default n
help
This is support for aic wireless chip.
if AIC_WLAN_SUPPORT
source "drivers/net/wireless/aic8800/aic8800_fdrv/Kconfig"
source "drivers/net/wireless/aic8800/aic_load_fw/Kconfig"
endif

View file

@ -0,0 +1,80 @@
CONFIG_AIC_LOADFW_SUPPORT := m
CONFIG_AIC8800_WLAN_SUPPORT := m
obj-$(CONFIG_AIC_LOADFW_SUPPORT) += aic_load_fw/
obj-$(CONFIG_AIC8800_WLAN_SUPPORT) += aic8800_fdrv/
########## config option ##########
export CONFIG_USE_FW_REQUEST = n
export CONFIG_PREALLOC_RX_SKB = y
export CONFIG_PREALLOC_TXQ = y
###################################
########## platform support list ##########
export CONFIG_PLATFORM_ROCKCHIP = n
export CONFIG_PLATFORM_ALLWINNER = n
export CONFIG_PLATFORM_AMLOGIC = n
export CONFIG_PLATFORM_HI = n
export CONFIG_PLATFORM_UBUNTU = y
ifeq ($(CONFIG_PLATFORM_ROCKCHIP), y)
ARCH = arm64
KDIR = /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/kernel
CROSS_COMPILE = /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
ccflags-y += -DANDROID_PLATFORM
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_HI), 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
SUBARCH = $(shell uname -m | sed -e s/i.86/i386/ -e s/armv.l/arm/ -e s/aarch64/arm64/ -e s/loongarch64/loongarch/ -e s/loong64/loongarch/)
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
endif
###########################################
MAKEFLAGS +=-j$(shell nproc)
all: modules
modules:
make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
install:
mkdir -p $(MODDESTDIR)
install -p -m 644 aic_load_fw/aic_load_fw.ko $(MODDESTDIR)/
install -p -m 644 aic8800_fdrv/aic8800_fdrv.ko $(MODDESTDIR)/
/sbin/depmod -a ${KVER}
uninstall:
rm -rfv $(MODDESTDIR)/aic_load_fw.ko
rm -rfv $(MODDESTDIR)/aic8800_fdrv.ko
/sbin/depmod -a ${KVER}
clean:
cd aic_load_fw/;make clean;cd ..
cd aic8800_fdrv/;make clean;cd ..
rm -rf modules.order Module.symvers .modules.order.cmd .Module.symvers.cmd .tmp_versions/

View file

@ -0,0 +1,36 @@
config AIC8800_WLAN_SUPPORT
tristate "AIC8800 wlan Support"
help
This is support for aic wifi driver.
#choice
# depends on AIC8800_WLAN_SUPPORT
# prompt "Select 8800 support platform"
#
# config PLATFORM_ROCHCHIP
# bool "PLATFORM_ROCHCHIP"
# depends on AIC8800_WLAN_SUPPORT
#
# config PLATFORM_ALLWINNER
# bool "PLATFORM_ALLWINNER"
# depends on AIC8800_WLAN_SUPPORT
#
# config PLATFORM_AMLOGIC
# bool "PLATFORM_AMLOGIC"
# depends on AIC8800_WLAN_SUPPORT
#
# config PLATFORM_UBUNTU
# bool "PLATFORM_UBUNTU"
# depends on AIC8800_WLAN_SUPPORT
#
#endchoice
#
#config USE_5G
# bool "AIC8800 force enable 5G"
# ---help---
# This is parameter that force enable 5G.
#
#config HE_FOR_OLD_KERNEL
# bool "AIC8800 support AX for old kernel"
# ---help---
# This is parameter that enable AX for old kernel.

View file

@ -0,0 +1,412 @@
EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS)
EXTRA_CFLAGS += -Wno-implicit-fallthrough
#EXTRA_CFLAGS += -Wno-unused-variable
RWNX_VERS_NUM := 6.4.3.0
CONFIG_AIC8800_WLAN_SUPPORT = m
MODULE_NAME = aic8800_fdrv
CONFIG_COUNTRY_CODE = "00"
# Support of bootrom start
CONFIG_START_FROM_BOOTROM = y
# Support of pmic setting, new version bootrom avaliable
CONFIG_PMIC_SETTING ?=n
# Select 8800DC/DW DCDC_VRF mode, check your board
CONFIG_VRF_DCDC_MODE = y
# ROM patch enabled option
CONFIG_ROM_PATCH_EN ?=y
#
# WAITING FOR KCONFIG {
#
CONFIG_RWNX_SOFTMAC ?= n
CONFIG_RWNX_FULLMAC ?= y
CONFIG_RWNX_FHOST ?= n
#
# DEBUG OPTIONS
CONFIG_RWNX_UM_HELPER_DFLT ?= "/dini/dini_bin/rwnx_umh.sh"
CONFIG_AIC_FW_PATH = "/vendor/etc/firmware"
export CONFIG_AIC_FW_PATH
#
# 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 ?= y
#
# } // 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 =n
CONFIG_USB_SUPPORT =y
CONFIG_RX_REORDER =y
CONFIG_ARP_OFFLOAD =y
CONFIG_USE_5G = y
CONFIG_RADAR_OR_IR_DETECT =n
CONFIG_DOWNLOAD_FW =n
CONFIG_RFTEST=y
CONFIG_USB_BT=y
CONFIG_MAC_RANDOM_IF_NO_MAC_IN_EFUSE = y
CONFIG_WPA3_FOR_OLD_KERNEL = n
CONFIG_HE_FOR_OLD_KERNEL = n
CONFIG_VHT_FOR_OLD_KERNEL = n
# CONFIG_COEX = n for BT_ONLY, CONFIG_COEX =y for combo and sw
CONFIG_COEX = y
CONFIG_ALIGN_8BYTES = y
CONFIG_TXRX_THREAD_PRIO = y
CONFIG_USB_ALIGN_DATA = y
CONFIG_RX_TASKLET = n
CONFIG_TX_TASKLET = n
CONFIG_RX_NETIF_RECV_SKB = y
CONFIG_BR_SUPPORT = n
CONFIG_USB_MSG_OUT_EP = y
CONFIG_USB_MSG_IN_EP = y
CONFIG_USB_RX_REASSEMBLE = n
CONFIG_WOWLAN = n
#DCDW support tx aggr, D80 support both
CONFIG_USB_RX_AGGR = n
CONFIG_USB_TX_AGGR = n
CONFIG_USB_NO_TRANS_DMA_MAP = n
CONFIG_GPIO_WAKEUP = n
CONFIG_CREATE_TRACE_POINTS = n
CONFIG_SUPPORT_REALTIME_CHANGE_MAC = y
CONFIG_USE_USB_ZERO_PACKET = y
CONFIG_DEBUG_FS = n
CONFIG_STA_SCAN_WHEN_P2P_WORKING = y
CONFIG_SET_VENDOR_EXTENSION_IE = n
CONFIG_VENDOR_GPIO = n
CONFIG_FWLOG_EN = n
CONFIG_FOR_IPCAM = n
CONFIG_5M10M = n
# Need to set fw path in BOARD_KERNEL_CMDLINE
CONFIG_USE_FW_REQUEST ?= n
CONFIG_USE_P2P0 = n
CONFIG_ONE_TXQ = n
CONFIG_PER_STA_FC = n
CONFIG_PREALLOC_RX_SKB ?= n
CONFIG_PREALLOC_TXQ ?= y
CONFIG_USE_WIRELESS_EXT = y
CONFIG_DPD = y
CONFIG_FORCE_DPD_CALIB = y
CONFIG_LOFT_CALIB = n
CONFIG_GKI = n
CONFIG_SCHED_SCAN = n
CONFIG_TEMP_COMP = n
CONFIG_POWER_LIMIT = n
CONFIG_EXT_FEM_8800DCDW = n
# CONFIG_MCC = n for sta and p2p concurrent in same channel.
CONFIG_MCC = y
CONFIG_LOAD_BT_PATCH_IN_FDRV = n
CONFIG_DYNAMIC_PWR = n
CONFIG_DYNAMIC_PERPWR = n
CONFIG_BAND_STEERING = n
CONFIG_PRBREQ_REPORT = n
#support D80X2 can write rf result to file
CONFIG_WRITE_FILE_D80X2 = n
ifneq ($(CONFIG_WIRELESS_EXT), y)
CONFIG_USE_WIRELESS_EXT = n
endif
ifeq ($(CONFIG_EXT_FEM_8800DCDW), y)
CONFIG_DPD = n
CONFIG_FORCE_DPD_CALIB = n
CONFIG_LOFT_CALIB = y
endif
# Support of MU-MIMO transmission (need FW support)
ifeq ($(CONFIG_RWNX_BFMER), y)
CONFIG_RWNX_MUMIMO_TX ?= n
else
CONFIG_RWNX_MUMIMO_TX = n
endif
# Enable handling of radar event
CONFIG_RWNX_RADAR ?= y
# Enable HW queue for Broadcast/Multicast traffic (need FW support)
CONFIG_RWNX_BCMC ?= y
# Enable Monitor+Data interface support (need FW support)
CONFIG_RWNX_MON_DATA =n
CONFIG_RWNX_MON_XMIT ?= n
CONFIG_RWNX_MON_RXFILTER ?= n
CONFIG_FILTER_TCP_ACK =y
# extra DEBUG config
CONFIG_RWNX_SW_PROFILING ?= n
CONFIG_RWNX_DBG ?= y
BR_NAME = br0
obj-$(CONFIG_AIC8800_WLAN_SUPPORT) := $(MODULE_NAME).o
$(MODULE_NAME)-y := \
rwnx_wakelock.o \
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 \
regdb.o \
md5.o \
aic_vendor.o \
aic_priv_cmd.o \
aicwf_compat_8800dc.o \
aicwf_compat_8800d80.o \
aicwf_compat_8800d80x2.o
$(MODULE_NAME)-$(CONFIG_BAND_STEERING) += aicwf_manager.o \
aicwf_steering.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_USE_WIRELESS_EXT) += aicwf_wext_linux.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=8
#for 8800DCDW u02
ccflags-y += -DNX_REMOTE_STA_MAX_FOR_OLD_IC=8
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_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_WPA3_FOR_OLD_KERNEL) += -DCONFIG_WPA3_FOR_OLD_KERNEL
ccflags-$(CONFIG_HE_FOR_OLD_KERNEL) += -DCONFIG_HE_FOR_OLD_KERNEL
ccflags-$(CONFIG_VHT_FOR_OLD_KERNEL) += -DCONFIG_VHT_FOR_OLD_KERNEL
ccflags-$(CONFIG_COEX) += -DCONFIG_COEX
ccflags-y += -DCONFIG_RWNX_FULLMAC
ccflags-y += -I$(src)/.
ccflags-$(CONFIG_RWNX_RADAR) += -DCONFIG_RWNX_RADAR
ccflags-$(CONFIG_RWNX_MON_DATA) += -DCONFIG_RWNX_MON_DATA
ccflags-$(CONFIG_RWNX_MON_XMIT) += -DCONFIG_RWNX_MON_XMIT
ccflags-$(CONFIG_RWNX_MON_RXFILTER) += -DCONFIG_RWNX_MON_RXFILTER
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-$(CONFIG_MCC) += -DCONFIG_MCC
ccflags-$(CONFIG_LOAD_BT_PATCH_IN_FDRV) += -DCONFIG_LOAD_BT_PATCH_IN_FDRV
ccflags-$(CONFIG_DYNAMIC_PWR) += -DCONFIG_DYNAMIC_PWR
ccflags-$(CONFIG_DYNAMIC_PERPWR) += -DCONFIG_DYNAMIC_PERPWR
ccflags-$(CONFIG_BAND_STEERING) += -DCONFIG_BAND_STEERING
ccflags-$(CONFIG_PRBREQ_REPORT) += -DCONFIG_PRBREQ_REPORT
ccflags-$(CONFIG_WRITE_FILE_D80X2) += -DRF_WRITE_FILE
ifeq ($(CONFIG_SDIO_SUPPORT), y)
ccflags-y += -DAICWF_SDIO_SUPPORT
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_USE_5G) += -DUSE_5G
ccflags-$(CONFIG_RADAR_OR_IR_DETECT) += -DCONFIG_RADAR_OR_IR_DETECT
ccflags-$(CONFIG_DOWNLOAD_FW) += -DCONFIG_DOWNLOAD_FW
ccflags-$(CONFIG_USB_BT) += -DCONFIG_USB_BT
ccflags-$(CONFIG_ALIGN_8BYTES) += -DCONFIG_ALIGN_8BYTES
ccflags-$(CONFIG_TXRX_THREAD_PRIO) += -DCONFIG_TXRX_THREAD_PRIO
ccflags-$(CONFIG_USB_ALIGN_DATA) += -DCONFIG_USB_ALIGN_DATA
ccflags-$(CONFIG_MAC_RANDOM_IF_NO_MAC_IN_EFUSE) += -DCONFIG_MAC_RANDOM_IF_NO_MAC_IN_EFUSE
ccflags-$(CONFIG_VENDOR_GPIO) += -DCONFIG_VENDOR_GPIO
ccflags-y += -DDEFAULT_COUNTRY_CODE=""\$(CONFIG_COUNTRY_CODE)"\"
ccflags-$(CONFIG_RX_NETIF_RECV_SKB) += -DCONFIG_RX_NETIF_RECV_SKB
ccflags-$(CONFIG_USB_MSG_OUT_EP) += -DCONFIG_USB_MSG_OUT_EP
ccflags-$(CONFIG_USB_MSG_IN_EP) += -DCONFIG_USB_MSG_IN_EP
ccflags-$(CONFIG_USB_RX_REASSEMBLE) += -DCONFIG_USB_RX_REASSEMBLE
ccflags-$(CONFIG_USB_RX_AGGR) += -DCONFIG_USB_RX_AGGR
ccflags-$(CONFIG_USB_TX_AGGR) += -DCONFIG_USB_TX_AGGR
ccflags-$(CONFIG_USB_NO_TRANS_DMA_MAP) += -DCONFIG_USB_NO_TRANS_DMA_MAP
ccflags-$(CONFIG_GPIO_WAKEUP) += -DCONFIG_GPIO_WAKEUP
ccflags-$(CONFIG_CREATE_TRACE_POINTS) += -DCREATE_TRACE_POINTS
ccflags-$(CONFIG_RX_TASKLET) += -DCONFIG_RX_TASKLET
ccflags-$(CONFIG_TX_TASKLET) += -DCONFIG_TX_TASKLET
ccflags-$(CONFIG_USE_USB_ZERO_PACKET) += -DCONFIG_USE_USB_ZERO_PACKET
ccflags-$(CONFIG_STA_SCAN_WHEN_P2P_WORKING) += -DCONFIG_STA_SCAN_WHEN_P2P_WORKING
ccflags-$(CONFIG_SUPPORT_REALTIME_CHANGE_MAC) += -DCONFIG_SUPPORT_REALTIME_CHANGE_MAC
ccflags-$(CONFIG_SET_VENDOR_EXTENSION_IE) += -DCONFIG_SET_VENDOR_EXTENSION_IE
ccflags-$(CONFIG_FWLOG_EN) += -DCONFIG_FWLOG_EN
ccflags-$(CONFIG_FOR_IPCAM) += -DCONFIG_FOR_IPCAM -DCONFIG_ONE_TXQ
ccflags-$(CONFIG_5M10M) += -DCONFIG_5M10M
ccflags-$(CONFIG_USE_FW_REQUEST) += -DCONFIG_USE_FW_REQUEST
ccflags-$(CONFIG_USE_P2P0) += -DCONFIG_USE_P2P0
ccflags-$(CONFIG_ONE_TXQ) += -DCONFIG_ONE_TXQ
ccflags-$(CONFIG_PER_STA_FC) += -DCONFIG_PER_STA_FC
ccflags-$(CONFIG_PREALLOC_RX_SKB) += -DCONFIG_PREALLOC_RX_SKB
ccflags-$(CONFIG_PREALLOC_TXQ) += -DCONFIG_PREALLOC_TXQ
ccflags-$(CONFIG_USE_WIRELESS_EXT) += -DCONFIG_USE_WIRELESS_EXT
ccflags-$(CONFIG_DPD) += -DCONFIG_DPD
ccflags-$(CONFIG_FORCE_DPD_CALIB) += -DCONFIG_FORCE_DPD_CALIB -DCONFIG_DPD
ccflags-$(CONFIG_LOFT_CALIB) += -DCONFIG_LOFT_CALIB
ccflags-$(CONFIG_GKI) += -DCONFIG_GKI
ccflags-$(CONFIG_SCHED_SCAN) += -DCONFIG_SCHED_SCAN
ccflags-$(CONFIG_FILTER_TCP_ACK) += -DCONFIG_FILTER_TCP_ACK
ccflags-$(CONFIG_TEMP_COMP) += -DCONFIG_TEMP_COMP
ccflags-$(CONFIG_POWER_LIMIT) += -DCONFIG_POWER_LIMIT
ccflags-$(CONFIG_EXT_FEM_8800DCDW) += -DCONFIG_EXT_FEM_8800DCDW
ccflags-$(CONFIG_WOWLAN) += -DCONFIG_WOWLAN
MAKEFLAGS +=-j$(shell nproc)
# Platform support list
CONFIG_PLATFORM_ROCKCHIP ?= n
CONFIG_PLATFORM_ALLWINNER ?= n
CONFIG_PLATFORM_AMLOGIC ?= n
CONFIG_PLATFORM_HI ?= n
CONFIG_PLATFORM_UBUNTU ?= y
ifeq ($(CONFIG_PLATFORM_ROCKCHIP), y)
ARCH := arm64
KDIR ?= /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/kernel
CROSS_COMPILE := /home/yaya/E/Rockchip/3566/firefly/Android11.0/Firefly-RK356X_Android11.0_git_20210824/RK356X_Android11.0/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
ccflags-y += -DANDROID_PLATFORM
ccflags-y += -DCONFIG_PLATFORM_ROCKCHIP
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_HI), y)
ccflags-y += -DANDROID_PLATFORM
ccflags-y += -DCONFIG_PLATFORM_HI
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
#KDIR ?= ~/D/Workspace/CyberQuantum/Linux/linux-4.15/
PWD ?= $(shell pwd)
KVER ?= $(shell uname -r)
MODDESTDIR ?= /lib/modules/$(KVER)/kernel/drivers/net/wireless/aic8800
SUBARCH = $(shell uname -m | sed -e s/i.86/i386/ -e s/armv.l/arm/ -e s/aarch64/arm64/)
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
endif
all: modules
modules:
# make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) LLVM=1 LLVM_IAS=1 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 .modules.order.cmd .Module.symvers.cmd

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_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,64 @@
/**
******************************************************************************
*
* @file private_cmd.h
*
* Copyright (C) Aicsemi 2018-2024
*
******************************************************************************
*/
#ifndef _AIC_PRIV_CMD_H_
#define _AIC_PRIV_CMD_H_
#include "rwnx_defs.h"
typedef struct _android_wifi_priv_cmd {
char *buf;
int used_len;
int total_len;
} android_wifi_priv_cmd;
struct aicwf_cs_info {
u8_l phymode;
u8_l bandwidth;
u16_l freq;
s8_l rssi;
s8_l snr;
s8_l noise;
u8_l txpwr;
//chanutil
u16_l chan_time_ms;
u16_l chan_time_busy_ms;
char countrycode[4];
u8_l rxnss;
u8_l rxmcs;
u8_l txnss;
u8_l txmcs;
u32_l tx_phyrate;
u32_l rx_phyrate;
u32_l tx_ack_succ_stat;
u32_l tx_ack_fail_stat;
u16_l chan_tx_busy_time;
};
#ifdef CONFIG_COMPAT
typedef struct _compat_android_wifi_priv_cmd {
compat_caddr_t buf;
int used_len;
int total_len;
} compat_android_wifi_priv_cmd;
#endif /* CONFIG_COMPAT */
int android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd);
int get_cs_info(struct rwnx_vif *vif, u8 *mac_addr, u8 *val);
#endif /* _AIC_PRIV_CMD_H_ */

File diff suppressed because it is too large Load diff

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,96 @@
#include "rwnx_main.h"
#include "rwnx_msg_tx.h"
#include "reg_access.h"
#define FW_USERCONFIG_NAME_8800D80 "aic_userconfig_8800d80.txt"
#define FW_POWERLIMIT_NAME_8800D80 "aic_powerlimit_8800d80.txt"
extern char aic_fw_path[200];
int rwnx_request_firmware_common(struct rwnx_hw *rwnx_hw,
u32** buffer, const char *filename);
void rwnx_plat_userconfig_parsing(char *buffer, int size);
void rwnx_release_firmware_common(u32** buffer);
int aicwf_set_rf_config_8800d80(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm)
{
int ret = 0;
if ((ret = rwnx_send_txpwr_lvl_v3_req(rwnx_hw))) {
return -1;
}
if ((ret = rwnx_send_txpwr_lvl_adj_req(rwnx_hw))) {
return -1;
}
if ((ret = rwnx_send_txpwr_ofst2x_req(rwnx_hw))) {
return -1;
}
if ((ret = rwnx_send_rf_calib_req(rwnx_hw, cfm))) {
return -1;
}
return 0 ;
}
int rwnx_plat_userconfig_load_8800d80(struct rwnx_hw *rwnx_hw){
int size;
u32 *dst=NULL;
char *filename = FW_USERCONFIG_NAME_8800D80;
#ifndef ANDROID_PLATFORM
sprintf(aic_fw_path, "%s/%s", aic_fw_path, "aic8800D80");
#endif
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_parsing((char *)dst, size);
rwnx_release_firmware_common(&dst);
AICWFDBG(LOGINFO, "userconfig download complete\n\n");
return 0;
}
#ifdef CONFIG_POWER_LIMIT
extern char country_code[];
int rwnx_plat_powerlimit_load_8800d80(struct rwnx_hw *rwnx_hw)
{
int size;
u32 *dst=NULL;
char *filename = FW_POWERLIMIT_NAME_8800D80;
AICWFDBG(LOGINFO, "powerlimit 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 cfg file\n");
dst = NULL;
return 0;
}
AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size);
/* parsing the file */
rwnx_plat_powerlimit_parsing((char *)dst, size, country_code);
rwnx_release_firmware_common(&dst);
AICWFDBG(LOGINFO, "powerlimit download complete\n\n");
return 0;
}
#endif

View file

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

View file

@ -0,0 +1,97 @@
#include "rwnx_main.h"
#include "rwnx_msg_tx.h"
#include "reg_access.h"
#define FW_USERCONFIG_NAME_8800D80X2 "aic_userconfig_8800d80x2.txt"
#define FW_POWERLIMIT_NAME_8800D80X2 "aic_powerlimit_8800d80x2.txt"
extern char aic_fw_path[200];
int rwnx_request_firmware_common(struct rwnx_hw *rwnx_hw,
u32** buffer, const char *filename);
void rwnx_plat_userconfig_parsing_8800d80x2(char *buffer, int size);
void rwnx_plat_userconfig_parsing(char *buffer, int size);
void rwnx_release_firmware_common(u32** buffer);
int aicwf_set_rf_config_8800d80x2(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm)
{
int ret = 0;
if ((ret = rwnx_send_txpwr_lvl_v4_req(rwnx_hw))) {
return -1;
}
if ((ret = rwnx_send_txpwr_lvl_adj_req(rwnx_hw))) {
return -1;
}
if ((ret = rwnx_send_txpwr_ofst2x_v2_req(rwnx_hw))) {
return -1;
}
if ((ret = rwnx_send_rf_calib_req(rwnx_hw, cfm))) {
return -1;
}
return 0 ;
}
int rwnx_plat_userconfig_load_8800d80x2(struct rwnx_hw *rwnx_hw){
int size;
u32 *dst=NULL;
char *filename = FW_USERCONFIG_NAME_8800D80X2;
#ifndef ANDROID_PLATFORM
sprintf(aic_fw_path, "%s/%s", aic_fw_path, "aic8800D80X2");
#endif
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_parsing_8800d80x2((char *)dst, size);
rwnx_release_firmware_common(&dst);
AICWFDBG(LOGINFO, "userconfig download complete\n\n");
return 0;
}
#ifdef CONFIG_POWER_LIMIT
extern char country_code[];
int rwnx_plat_powerlimit_load_8800d80x2(struct rwnx_hw *rwnx_hw)
{
int size;
u32 *dst=NULL;
char *filename = FW_POWERLIMIT_NAME_8800D80X2;
AICWFDBG(LOGINFO, "powerlimit 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 cfg file\n");
dst = NULL;
return 0;
}
AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size);
/* parsing the file */
rwnx_plat_powerlimit_parsing((char *)dst, size, country_code);
rwnx_release_firmware_common(&dst);
AICWFDBG(LOGINFO, "powerlimit download complete\n\n");
return 0;
}
#endif

View file

@ -0,0 +1,9 @@
#include <linux/types.h>
int rwnx_plat_userconfig_load_8800d80x2(struct rwnx_hw *rwnx_hw);
#ifdef CONFIG_POWER_LIMIT
int rwnx_plat_powerlimit_load_8800d80x2(struct rwnx_hw *rwnx_hw);
#endif
int aicwf_set_rf_config_8800d80x2(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,62 @@
#include <linux/types.h>
#if defined(CONFIG_DPD) || defined(CONFIG_LOFT_CALIB)
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)
#endif
#ifdef CONFIG_DPD
extern rf_misc_ram_lite_t dpd_res;
#endif
#ifdef CONFIG_LOFT_CALIB
extern rf_misc_ram_lite_t loft_res_local;
#endif
int aicwf_patch_table_load(struct rwnx_hw *rwnx_hw, char *filename);
void aicwf_patch_config_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 aicwf_misc_ram_init_8800dc(struct rwnx_hw *rwnx_hw);
#if defined(CONFIG_DPD) || defined(CONFIG_LOFT_CALIB)
int aicwf_misc_ram_valid_check_8800dc(struct rwnx_hw *rwnx_hw, int *valid_out);
int aicwf_plat_calib_load_8800dc(struct rwnx_hw *rwnx_hw);
#endif
#ifdef CONFIG_DPD
int aicwf_dpd_calib_8800dc(struct rwnx_hw *rwnx_hw, rf_misc_ram_lite_t *dpd_res);
int aicwf_dpd_result_apply_8800dc(struct rwnx_hw *rwnx_hw, rf_misc_ram_lite_t *dpd_res);
#ifndef CONFIG_FORCE_DPD_CALIB
int aicwf_dpd_result_load_8800dc(struct rwnx_hw *rwnx_hw, rf_misc_ram_lite_t *dpd_res);
int aicwf_dpd_result_write_8800dc(void *buf, int buf_len);
#endif
#endif
#ifdef CONFIG_LOFT_CALIB
int aicwf_loft_calib_8800dc(struct rwnx_hw *rwnx_hw, rf_misc_ram_lite_t *loft_res);
int aicwf_loft_result_apply_8800dc(struct rwnx_hw *rwnx_hw, rf_misc_ram_lite_t *loft_res);
#endif
int aicwf_plat_patch_load_8800dc(struct rwnx_hw *rwnx_hw);
int aicwf_plat_rftest_load_8800dc(struct rwnx_hw *rwnx_hw);
int rwnx_plat_userconfig_load_8800dc(struct rwnx_hw *rwnx_hw);
int rwnx_plat_userconfig_load_8800dw(struct rwnx_hw *rwnx_hw);
#ifdef CONFIG_POWER_LIMIT
int rwnx_plat_powerlimit_load_8800dcdw(struct rwnx_hw *rwnx_hw, uint16_t chip_id);
#endif
void system_config_8800dc(struct rwnx_hw *rwnx_hw);

View file

@ -0,0 +1,53 @@
#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 LOGSTEER 0x0020
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,601 @@
/**
******************************************************************************
*
* Copyright (C) 2020 AIC semiconductor.
*
* @file aicwf_manager.c
*
* @brief netlink msg definitions
*
******************************************************************************
*/
#include <linux/module.h>
#include <linux/netlink.h>
#include <net/sock.h>
#include "aicwf_manager.h"
#include "lmac_mac.h"
#include "aicwf_debug.h"
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
#define MAC_ARG(x) ((u8_l *)(x))[0], ((u8_l *)(x))[1], ((u8_l *)(x))[2], ((u8_l *)(x))[3], ((u8_l *)(x))[4], ((u8_l *)(x))[5]
#define MANAGER_STR "[MANAGER] USB "
static struct sock *nl_sock = NULL;
static struct rwnx_vif *nl_rwnx_vif[PHY_BAND_MAX][CONFIG_IFACE_NUMBER] = {{NULL}};
static u8_l nl_hook[PHY_BAND_MAX][CONFIG_IFACE_NUMBER] = {{0}};
static u8_l nl_daemon_on = 0;
#define FREQ_2G_MIN 2412
#define FREQ_2G_MAX 2484
#define FREQ_5G_MIN 5170
#define FREQ_5G_MAX 5825
#define FREQ_6G_MIN 5925
#define FREQ_6G_MAX 7125
static int freq_to_channel(int freq)
{
if (freq >= FREQ_2G_MIN && freq <= FREQ_2G_MAX) {
if (freq == 2484) {
return 14;
} else {
return (freq - 2412) / 5 + 1;
}
} else if (freq >= FREQ_5G_MIN && freq <= FREQ_5G_MAX) {
return (freq - 5000) / 5;
} else if (freq >= FREQ_6G_MIN && freq <= FREQ_6G_MAX) {
return (freq - 5950) / 5;
} else {
AICWFDBG(LOGERROR, MANAGER_STR"aic Unsupported frequency: %d MHz\n", freq);
return -1;
}
}
void aicwf_nl_recv_msg(struct sk_buff *skb)
{
struct rwnx_vif *rwnx_vif;
struct rwnx_sta *sta = NULL;
u8_l rwnx_hook = 0;
u8_l band;
u8_l ssid;
struct nlmsghdr *nlh = NULL;
struct b_nl_message *msg = NULL;
struct b_elm_header *hdr = NULL;
struct b_elm_intf *intf = NULL;
struct b_elm_sta_info *sta_info = NULL;
struct b_elm_roam_info *roam_info = NULL;
u32 offset = 0;
if (skb == NULL) {
AICWFDBG(LOGERROR, MANAGER_STR"skb is null.\n");
return;
}
nlh = (struct nlmsghdr *)skb->data;
msg = (struct b_nl_message *)NLMSG_DATA(nlh);
AICWFDBG(LOGSTEER, MANAGER_STR"%s, %d\n", __func__, msg->type);
/* message type */
switch(msg->type) {
case AIC_NL_DAEMON_ON_TYPE:
nl_daemon_on = 1;
AICWFDBG(LOGSTEER, MANAGER_STR"AIC_NL_DAEMON_ON_TYPE\n");
for (band = 0; band < PHY_BAND_MAX; band++) {
for (ssid = 0; ssid < CONFIG_IFACE_NUMBER; ssid++) {
rwnx_vif = nl_rwnx_vif[band][ssid];
rwnx_hook = nl_hook[band][ssid];
if (!rwnx_hook) {
AICWFDBG(LOGSTEER, MANAGER_STR"%s, !rwnx_hook, %d,%d\n", __func__, band, ssid);
continue;
}
if (rwnx_vif == NULL || rwnx_vif->up == false) {
AICWFDBG(LOGSTEER, MANAGER_STR"%s, !rwnx_vif, %d,%d\n", __func__, band, ssid);
continue;
}
#ifdef CONFIG_BAND_STEERING
aicwf_band_steering_init(rwnx_vif);
#endif
spin_lock_bh(&rwnx_vif->rwnx_hw->cb_lock);
list_for_each_entry(sta, &rwnx_vif->ap.sta_list, list){
if (sta->valid)
aicwf_nl_send_new_sta_msg(rwnx_vif, sta->mac_addr);
}
spin_unlock_bh(&rwnx_vif->rwnx_hw->cb_lock);
}
}
break;
case AIC_NL_DAEMON_OFF_TYPE:
nl_daemon_on = 0;
break;
#ifdef CONFIG_BAND_STEERING
case AIC_NL_B_STEER_BLOCK_ADD_TYPE:
case AIC_NL_B_STEER_BLOCK_DEL_TYPE:
while (offset < msg->len) {
hdr = (struct b_elm_header *)(msg->content + offset);
offset += ELM_HEADER_LEN;
switch(hdr->id) {
case AIC_ELM_INTF_ID:
intf = (struct b_elm_intf *)(msg->content + offset);
break;
case AIC_ELM_STA_INFO_ID:
sta_info = (struct b_elm_sta_info *)(msg->content + offset);
break;
default:
AICWFDBG(LOGERROR, MANAGER_STR"unknown element id.\n");
break;
}
offset += hdr->len;
}
if (intf && sta_info) {
band = intf->band;
ssid = intf->ssid;
AICWFDBG(LOGSTEER, MANAGER_STR"STEER_BLOCK band: %d, ssid: %d\n", band, ssid);
rwnx_vif = nl_rwnx_vif[band][ssid];
rwnx_hook = nl_hook[band][ssid];
if (!rwnx_hook) {
AICWFDBG(LOGSTEER, MANAGER_STR"rwnx_hook is null p1.\n");
break;
}
if (rwnx_vif == NULL || rwnx_vif->up == false) {
AICWFDBG(LOGSTEER, MANAGER_STR"rwnx_vif is null/down p1.\n");
break;
}
if (msg->type == AIC_NL_B_STEER_BLOCK_ADD_TYPE)
aicwf_band_steering_block_entry_add(rwnx_vif, sta_info->mac);
else if (msg->type == AIC_NL_B_STEER_BLOCK_DEL_TYPE)
aicwf_band_steering_block_entry_del(rwnx_vif, sta_info->mac);
}
break;
case AIC_NL_B_STEER_ROAM_TYPE:
while (offset < msg->len) {
hdr = (struct b_elm_header *)(msg->content + offset);
offset += ELM_HEADER_LEN;
/* element type: should handle wrong length */
switch(hdr->id) {
case AIC_ELM_INTF_ID:
intf = (struct b_elm_intf *)(msg->content + offset);
break;
case AIC_ELM_ROAM_INFO_ID:
roam_info = (struct b_elm_roam_info *)(msg->content + offset);
break;
default:
AICWFDBG(LOGERROR, MANAGER_STR"unknown element id.\n");
break;
}
offset += hdr->len;
}
if (intf && roam_info) {
band = intf->band;
ssid = intf->ssid;
rwnx_vif = nl_rwnx_vif[band][ssid];
rwnx_hook = nl_hook[band][ssid];
if (!rwnx_hook) {
AICWFDBG(LOGERROR, MANAGER_STR"rwnx_hook is null p2.\n");
break;
}
if (rwnx_vif == NULL || rwnx_vif->up == false) {
AICWFDBG(LOGERROR, MANAGER_STR"rwnx_vif is null/down p2.\n");
break;
}
AICWFDBG(LOGSTEER, MANAGER_STR"AIC_NL_B_STEER_ROAM_TYPE (hostapd_cli)!\n");
AICWFDBG(LOGSTEER, MANAGER_STR"sta_mac="MAC_FMT"\n", MAC_ARG(roam_info->sta_mac));
AICWFDBG(LOGSTEER, MANAGER_STR"bss_mac="MAC_FMT" bss_ch=%u method=%s\n",
MAC_ARG(roam_info->bss_mac),
roam_info->bss_ch,
roam_info->method == 0 ? "11V" : "Deauth");
if (roam_info->method == 1)
aicwf_band_steering_roam_block_entry_add(rwnx_vif, roam_info->sta_mac);
}
break;
#endif
default:
AICWFDBG(LOGERROR, MANAGER_STR"unknown message type.\n");
break;
}
return;
}
void aicwf_nl_send_msg(void *msg, u32 msg_len)
{
struct nlmsghdr *nlh = NULL;
struct sk_buff *skb = NULL;
u32 skb_len;
s32 err;
skb_len = NLMSG_SPACE(NL_MAX_MSG_SIZE);
skb = __dev_alloc_skb(skb_len, GFP_ATOMIC);
if (!skb) {
AICWFDBG(LOGERROR, MANAGER_STR"allocate skb failed.\n");
goto func_return;
}
nlh = nlmsg_put(skb, 0, 0, 0, NL_MAX_MSG_SIZE, 0);
if (!nlh) {
AICWFDBG(LOGERROR, MANAGER_STR"put netlink header failed.\n");
kfree_skb(skb);
goto func_return;
}
NETLINK_CB(skb).portid = 0;
NETLINK_CB(skb).dst_group = 0;
memset(NLMSG_DATA(nlh), 0, msg_len);
memcpy(NLMSG_DATA(nlh), (u8_l *)msg, msg_len);
if (!nl_sock) {
AICWFDBG(LOGERROR, MANAGER_STR"[%s %u] nl_sock is NULL\n", __FUNCTION__, __LINE__);
goto msg_fail_skb;
}
err = netlink_unicast(nl_sock, skb, NL_AIC_MANAGER_PID, MSG_DONTWAIT);
if (err < 0) {
/* netlink_unicast() already kfree_skb */
AICWFDBG(LOGSTEER, MANAGER_STR"send netlink unicast failed.\n");
goto func_return;
}
func_return:
return;
msg_fail_skb:
kfree_skb(skb);
}
static void aicwf_netlink_set_msg(
struct b_nl_message *msg, u32 *msg_len, void *elm, u32 elm_len)
{
memcpy(msg->content + (*msg_len), elm, elm_len);
(*msg_len) += elm_len;
return;
}
void aicwf_nl_send_del_sta_msg(struct rwnx_vif *rwnx_vif, u8_l *mac)
{
u32 msg_len = 0;
struct b_nl_message msg = {0};
struct b_elm_header hdr = {0};
struct b_elm_intf intf = {{0}};
struct b_elm_sta_info sta_info = {{0}};
if (!nl_daemon_on)
return;
AICWFDBG(LOGSTEER, MANAGER_STR"%s, "MAC_FMT"\n", __func__, MAC_ARG(mac));
/* element header */
hdr.id = AIC_ELM_INTF_ID;
hdr.len = ELM_INTF_LEN;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&hdr, ELM_HEADER_LEN);
/* element: AIC_ELM_INTF_ID */
intf.root = 0; /* TBD */
intf.band = rwnx_vif->ap.band;
intf.ssid = rwnx_vif->rwnx_hw->iface_idx;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&intf, ELM_INTF_LEN);
/* element header */
hdr.id = AIC_ELM_STA_INFO_ID;
hdr.len = ELM_STA_INFO_LEN;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&hdr, ELM_HEADER_LEN);
/* element: AIC_ELM_STA_INFO_ID */
memcpy(sta_info.mac, mac, 6);
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&sta_info, ELM_STA_INFO_LEN);
/* finish message */
msg.type = AIC_NL_DEL_STA_TYPE;
msg.len = msg_len;
/* length += (type + len) */
msg_len += 8;
aicwf_nl_send_msg((void *)&msg, msg_len);
return;
}
void aicwf_nl_send_new_sta_msg(struct rwnx_vif *rwnx_vif, u8_l *mac)
{
u32 msg_len = 0;
struct b_nl_message msg = {0};
struct b_elm_header hdr = {0};
struct b_elm_intf intf = {{0}};
struct b_elm_sta_info sta_info = {{0}};
if (!nl_daemon_on)
return;
AICWFDBG(LOGSTEER, MANAGER_STR"%s, "MAC_FMT"\n", __func__, MAC_ARG(mac));
/* element header */
hdr.id = AIC_ELM_INTF_ID;
hdr.len = ELM_INTF_LEN;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&hdr, ELM_HEADER_LEN);
/* element: AIC_ELM_INTF_ID */
intf.root = 0; /* TBD */
intf.band = rwnx_vif->ap.band;
intf.ssid = rwnx_vif->rwnx_hw->iface_idx;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&intf, ELM_INTF_LEN);
/* element header */
hdr.id = AIC_ELM_STA_INFO_ID;
hdr.len = ELM_STA_INFO_LEN;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&hdr, ELM_HEADER_LEN);
/* element: AIC_ELM_STA_INFO_ID */
memcpy(sta_info.mac, mac, 6);
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&sta_info, ELM_STA_INFO_LEN);
/* finish message */
msg.type = AIC_NL_NEW_STA_TYPE;
msg.len = msg_len;
/* length += (type + len) */
msg_len += 8;
aicwf_nl_send_msg((void *)&msg, msg_len);
return;
}
void aicwf_nl_send_intf_rpt_msg(struct rwnx_vif *rwnx_vif)
{
u32 msg_len = 0;
struct b_nl_message msg = {0};
struct b_elm_header hdr = {0};
struct b_elm_intf intf = {{0}};
struct b_elm_intf_info intf_info = {0};
if (!nl_daemon_on)
return;
/* element header */
hdr.id = AIC_ELM_INTF_ID;
hdr.len = ELM_INTF_LEN;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&hdr, ELM_HEADER_LEN);
/* element: AIC_ELM_INTF_ID */
memcpy(intf.mac, rwnx_vif->ndev->dev_addr, 6);
intf.root = 0; /* TBD */
intf.band = rwnx_vif->ap.band;
intf.ssid = rwnx_vif->rwnx_hw->iface_idx;
memcpy(intf.name, rwnx_vif->ndev->name, 16);
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&intf, ELM_INTF_LEN);
/* element header */
hdr.id = AIC_ELM_INTF_INFO_ID;
hdr.len = ELM_INTF_INFO_LEN;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&hdr, ELM_HEADER_LEN);
/* element: AIC_ELM_INTF_INFO_ID */
intf_info.ch = freq_to_channel(rwnx_vif->ap.freq);
intf_info.tx_tp = 0; /* TBD */
intf_info.rx_tp = 0; /* TBD */
intf_info.bss_info = 0;
intf_info.reg_class = (rwnx_vif->ap.band == 0) ? 81 : 128;
intf_info.phy_type = 7;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&intf_info, ELM_INTF_INFO_LEN);
/* finish message */
msg.type = AIC_NL_INTF_RPT_TYPE;
msg.len = msg_len;
/* length += (type + len) */
msg_len += 8;
aicwf_nl_send_msg((void *)&msg, msg_len);
return;
}
void aicwf_nl_send_sta_rpt_msg(struct rwnx_vif *rwnx_vif, struct rwnx_sta *sta)
{
u32 msg_len = 0;
struct b_nl_message msg = {0};
struct b_elm_header hdr = {0};
struct b_elm_intf intf = {{0}};
struct b_elm_sta_info sta_info = {{0}};
struct b_elm_sta_info_ext sta_info_ext = {{0}};
if (!nl_daemon_on)
return;
/* element header */
hdr.id = AIC_ELM_INTF_ID;
hdr.len = ELM_INTF_LEN;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&hdr, ELM_HEADER_LEN);
/* element: AIC_ELM_INTF_ID */
memcpy(intf.mac, rwnx_vif->ndev->dev_addr, 6);
intf.root = 0; /* TBD */
intf.band = rwnx_vif->ap.band;
intf.ssid = rwnx_vif->rwnx_hw->iface_idx;
memcpy(intf.name, rwnx_vif->ndev->name, 16);
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&intf, ELM_INTF_LEN);
/* element header */
hdr.id = AIC_ELM_STA_INFO_ID;
hdr.len = ELM_STA_INFO_LEN;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&hdr, ELM_HEADER_LEN);
/* element: AIC_ELM_STA_INFO_ID */
memcpy(sta_info.mac, sta->mac_addr, 6);
sta_info.rssi = sta->rssi;
sta_info.link_time = sta->link_time;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&sta_info, ELM_STA_INFO_LEN);
/* element header */
hdr.id = AIC_ELM_STA_INFO_EXT_ID;
hdr.len = ELM_STA_INFO_EXT_LEN;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&hdr, ELM_HEADER_LEN);
/* element: AIC_ELM_STA_INFO_EXT_ID */
memcpy(sta_info_ext.mac, sta->mac_addr, 6);
sta_info_ext.supported_band = sta->support_band;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&sta_info_ext, ELM_STA_INFO_EXT_LEN);
/* finish message */
msg.type = AIC_NL_STA_RPT_TYPE;
msg.len = msg_len;
/* length += (type + len) */
msg_len += 8;
aicwf_nl_send_msg((void *)&msg, msg_len);
return;
}
void aicwf_nl_send_frame_rpt_msg(struct rwnx_vif *rwnx_vif, u16_l frame_type, u8_l *sa, s8_l rssi)
{
u32 msg_len = 0;
struct b_nl_message msg = {0};
struct b_elm_header hdr = {0};
struct b_elm_frame_info frame_info = {0};
struct b_elm_intf intf = {{0}};
if (!nl_daemon_on)
return;
//AICWFDBG(LOGSTEER, "[NETLINK] %s, sta: "MAC_FMT"\n", __func__, MAC_ARG(sa));
/* TBD */
if (frame_type == WIFI_PROBEREQ && rssi <= LOW_RSSI_IGNORE) {
AICWFDBG(LOGSTEER, MANAGER_STR"WIFI_PROBEREQ <= %d, ignore\n", LOW_RSSI_IGNORE);
return;
}
/* element header */
hdr.id = AIC_ELM_INTF_ID;
hdr.len = ELM_INTF_LEN;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&hdr, ELM_HEADER_LEN);
/* element: AIC_ELM_INTF_ID */
intf.root = 0; /* TBD */
intf.band = rwnx_vif->ap.band;
intf.ssid = rwnx_vif->rwnx_hw->iface_idx;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&intf, ELM_INTF_LEN);
/* element header */
hdr.id = AIC_ELM_FRAME_INFO_ID;
hdr.len = ELM_FRAME_INFO_LEN;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&hdr, ELM_HEADER_LEN);
/* element: AIC_ELM_FRAME_INFO_ID */
frame_info.frame_type = frame_type;
memcpy(frame_info.sa, sa, 6);
frame_info.rssi = rssi;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&frame_info, ELM_FRAME_INFO_LEN);
/* finish message */
msg.type = AIC_NL_FRAME_RPT_TYPE;
msg.len = msg_len;
/* length += (type + len) */
msg_len += 8;
aicwf_nl_send_msg((void *)&msg, msg_len);
return;
}
void aicwf_nl_send_time_tick_msg(struct rwnx_vif *rwnx_vif)
{
u32 msg_len = 0;
struct b_nl_message msg = {0};
struct b_elm_header hdr = {0};
struct b_elm_intf intf = {{0}};
if (!nl_daemon_on)
return;
/* element header */
hdr.id = AIC_ELM_INTF_ID;
hdr.len = ELM_INTF_LEN;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&hdr, ELM_HEADER_LEN);
/* element: AIC_ELM_INTF_ID */
intf.root = 0; /* TBD */
intf.band = rwnx_vif->ap.band;
intf.ssid = rwnx_vif->rwnx_hw->iface_idx;
aicwf_netlink_set_msg(&msg, &msg_len, (void *)&intf, ELM_INTF_LEN);
/* finish message */
msg.type = AIC_NL_TIME_TICK_TYPE;
msg.len = msg_len;
/* length += (type + len) */
msg_len += 8;
aicwf_nl_send_msg((void *)&msg, msg_len);
return;
}
void aicwf_nl_hook(struct rwnx_vif *rwnx_vif, u8_l band, u8_l ssid)
{
AICWFDBG(LOGSTEER, MANAGER_STR"%s band:%d, ssid:%d\n", __func__, band, ssid);
nl_hook[band][ssid] = 1;
nl_rwnx_vif[band][ssid] = rwnx_vif;
return;
}
void aicwf_nl_hook_deinit(u8_l band, u8_l ssid)
{
AICWFDBG(LOGSTEER, MANAGER_STR"%s band:%d, ssid:%d\n", __func__, band, ssid);
nl_hook[band][ssid] = 0;
nl_rwnx_vif[band][ssid] = NULL;
return;
}
void aicwf_nl_init(void)
{
if (nl_sock) {
AICWFDBG(LOGSTEER, MANAGER_STR"netlink already init.\n");
return;
}
struct netlink_kernel_cfg cfg = {
.input = aicwf_nl_recv_msg,
};
nl_sock = netlink_kernel_create(&init_net, NL_AIC_PROTOCOL, &cfg);
if (!nl_sock)
AICWFDBG(LOGERROR, MANAGER_STR"create netlink falied.\n");
return;
}
void aicwf_nl_deinit(void)
{
if(nl_sock)
{
netlink_kernel_release(nl_sock);
nl_sock = NULL;
}
AICWFDBG(LOGSTEER, MANAGER_STR"[aicwf_nl_deinit] delete nl_sock netlink succeed.\n");
return;
}

View file

@ -0,0 +1,146 @@
#ifndef _AICWF_MANAGER_H_
#define _AICWF_MANAGER_H_
#include "lmac_types.h"
#include "rwnx_defs.h"
#define DRV_WLAN_MANAGER_VER "v1.0"
/* TBD */
#define CONFIG_IFACE_NUMBER 1
#define NL_AIC_PROTOCOL_FRT_DRV 28
#define NL_AIC_PROTOCOL_SEC_DRV 29
#define NL_AIC_PROTOCOL NL_AIC_PROTOCOL_SEC_DRV
#define NL_AIC_MANAGER_PID 5185
#define NL_MAX_MSG_SIZE 768
/* Netlink Message Type List */
#define AIC_NL_DAEMON_ON_TYPE 1
#define AIC_NL_DAEMON_OFF_TYPE 2
#define AIC_NL_DAEMON_ALIVE_TYPE 3
#define AIC_NL_DEL_STA_TYPE 4
#define AIC_NL_NEW_STA_TYPE 5
#define AIC_NL_INTF_RPT_TYPE 6
#define AIC_NL_STA_RPT_TYPE 7
#define AIC_NL_FRAME_RPT_TYPE 8
#define AIC_NL_TIME_TICK_TYPE 9
#define AIC_NL_PRIV_INFO_CMD_TYPE 10
#ifdef CONFIG_BAND_STEERING
#define AIC_NL_B_STEER_CMD_TYPE 11
#define AIC_NL_B_STEER_BLOCK_ADD_TYPE 12
#define AIC_NL_B_STEER_BLOCK_DEL_TYPE 13
#define AIC_NL_B_STEER_ROAM_TYPE 14
#endif
#define AIC_NL_GENERAL_CMD_TYPE 100
#define AIC_NL_CUSTOMER_TYPE 101
#define AIC_NL_CONFIG_UPDATE_TYPE 102
/* Element ID */
#define AIC_ELM_INTF_ID 1
#define AIC_ELM_INTF_INFO_ID 2
#define AIC_ELM_FRAME_INFO_ID 3
#define AIC_ELM_STA_INFO_ID 4
#define AIC_ELM_ROAM_INFO_ID 5
#define AIC_ELM_BUFFER_ID 6
#define AIC_ELM_STA_INFO_EXT_ID 7
#define LOW_RSSI_IGNORE (-85)
struct b_nl_message {
u32_l type;
u32_l len;
u8_l content[NL_MAX_MSG_SIZE];
};
struct b_elm_header {
u8_l id;
u8_l len;
};
struct b_elm_intf {
u8_l mac[6];
u8_l root;
u8_l band;
u8_l ssid;
s8_l name[16];
};
struct b_elm_intf_info {
u16_l ch;
u8_l ch_clm;
u8_l ch_noise;
u32_l tx_tp;
u32_l rx_tp;
u32_l assoc_sta_num;
/* self neighbor report info */
u32_l bss_info;
u8_l reg_class;
u8_l phy_type;
};
struct b_elm_frame_info {
u16_l frame_type;
u8_l sa[6];
s8_l rssi;
};
struct b_elm_sta_info {
u8_l mac[6];
s8_l rssi;
u32_l link_time;
u32_l tx_tp; /* kbits */
u32_l rx_tp; /* kbits */
};
struct b_elm_roam_info {
u8_l sta_mac[6]; /* station mac */
u8_l bss_mac[6]; /* target bss mac */
u16_l bss_ch; /* target bss channel */
u8_l method; /* 0: 11V, 1: Deauth */
};
struct b_elm_buffer {
u8_l buf[255];
};
struct b_elm_sta_info_ext {
u8_l mac[6];
u8_l supported_band; /* bit0:2g bit1:5g */
u8_l empty[119]; /* for future use */
};
/* Element Size List */
#define ELM_HEADER_LEN (sizeof(struct b_elm_header))
#define ELM_INTF_LEN (sizeof(struct b_elm_intf))
#define ELM_INTF_INFO_LEN (sizeof(struct b_elm_intf_info))
#define ELM_FRAME_INFO_LEN (sizeof(struct b_elm_frame_info))
#define ELM_STA_INFO_LEN (sizeof(struct b_elm_sta_info))
#define ELM_ROAM_INFO_LEN (sizeof(struct b_elm_roam_info))
#define ELM_BUFFER_LEN (sizeof(struct b_elm_buffer))
#define ELM_STA_INFO_EXT_LEN (sizeof(struct b_elm_sta_info_ext))
void aicwf_nl_send_del_sta_msg(struct rwnx_vif *rwnx_vif, u8_l *mac);
void aicwf_nl_send_new_sta_msg(struct rwnx_vif *rwnx_vif, u8_l *mac);
void aicwf_nl_send_intf_rpt_msg(struct rwnx_vif *rwnx_vif);
void aicwf_nl_send_sta_rpt_msg(struct rwnx_vif *rwnx_vif, struct rwnx_sta *sta);
void aicwf_nl_send_frame_rpt_msg(struct rwnx_vif *rwnx_vif, u16_l frame_type, u8_l *sa, s8_l rssi);
void aicwf_nl_send_time_tick_msg(struct rwnx_vif *rwnx_vif);
void aicwf_nl_hook(struct rwnx_vif *rwnx_vif, u8_l band, u8_l iface_id);
void aicwf_nl_hook_deinit(u8_l band, u8_l ssid);
void aicwf_nl_init(void);
void aicwf_nl_deinit(void);
void aicwf_wlan_manager_recv_msg(struct b_nl_message *msg);
void aicwf_nl_recv_msg(struct sk_buff *skb);
void aicwf_nl_send_msg(void *msg, u32_l msg_len);
#endif

View file

@ -0,0 +1,27 @@
#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;
};
extern struct rx_buff *aicwf_prealloc_rxbuff_alloc(spinlock_t *lock);
extern void aicwf_prealloc_rxbuff_free(struct rx_buff *rxbuff, spinlock_t *lock);
extern int aicwf_prealloc_init(void);
extern void aicwf_prealloc_exit(void);
extern int aicwf_rxbuff_size_get(void);
#endif
#endif /* _AICWF_RX_PREALLOC_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,99 @@
/**
* 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"
#define AICWF_SDIO_NAME "aicwf_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_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;
struct rwnx_hw;
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;
//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;
};
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_pwrctl_timer(struct aic_sdio_dev *sdiodev, uint duration);
int aicwf_sdio_pwr_stctl(struct aic_sdio_dev *sdiodev, uint target);
int aicwf_sdio_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);
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);
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);
#ifdef CONFIG_PLATFORM_NANOPI
extern void extern_wifi_set_enable(int is_on);
extern void sdio_reinit(void);
#endif /*CONFIG_PLATFORM_NANOPI*/
#endif /* AICWF_SDIO_SUPPORT */
#endif /*_AICWF_SDMMC_H_*/

View file

@ -0,0 +1,217 @@
/**
******************************************************************************
*
* Copyright (C) 2020 AIC semiconductor.
*
* @file aicwf_steering.c
*
* @brief band steering definitions
*
******************************************************************************
*/
#include "aicwf_steering.h"
#include "rwnx_defs.h"
#define MAC_FMT_B "%02x:%02x:%02x:%02x:%02x:%02x"
#define MAC_ARG_B(x) ((u8_l *)(x))[0], ((u8_l *)(x))[1], ((u8_l *)(x))[2], ((u8_l *)(x))[3], ((u8_l *)(x))[4], ((u8_l *)(x))[5]
#define STEEER_STR "[STEERING] USB "
#ifdef CONFIG_BAND_STEERING
static struct b_steer_block_entry *block_entry_lookup(struct rwnx_vif *rwnx_vif, u8_l *mac)
{
u8_l i;
struct b_steer_block_entry *ent = NULL;
for (i = 0; i < B_STEER_ENTRY_NUM; i++) {
ent = &(rwnx_vif->bsteerpriv.block_list[i]);
if (ent->used && (memcmp(ent->mac, mac, 6) == 0)) {
AICWFDBG(LOGSTEER, STEEER_STR"%s "MAC_FMT_B"\n", __func__, MAC_ARG_B(mac));
return ent;
}
}
return NULL;
}
void aicwf_band_steering_expire(struct rwnx_vif *rwnx_vif)
{
u8_l i;
struct b_steer_block_entry *ent = NULL;
if (rwnx_vif->bsteerpriv.inited == false) {
AICWFDBG(LOGSTEER, STEEER_STR"%s bsteerpriv not inited\n", __func__);
return;
}
spin_lock_bh(&(rwnx_vif->bsteerpriv.lock));
/* block entry */
for (i = 0; i < B_STEER_ENTRY_NUM; i++) {
ent = &(rwnx_vif->bsteerpriv.block_list[i]);
if (!ent->used)
continue;
if (ent->entry_expire) {
ent->entry_expire--;
if (ent->entry_expire == 0)
ent->used = 0;
}
}
spin_unlock_bh(&(rwnx_vif->bsteerpriv.lock));
return;
}
s32_l aicwf_band_steering_block_chk(struct rwnx_vif *rwnx_vif, u8_l *mac)
{
s32 ret = 0;
struct b_steer_block_entry *ent = NULL;
if (rwnx_vif->bsteerpriv.inited == false) {
AICWFDBG(LOGSTEER, STEEER_STR"%s bsteerpriv not inited\n", __func__);
return 0;
}
spin_lock_bh(&(rwnx_vif->bsteerpriv.lock));
ent = block_entry_lookup(rwnx_vif, mac);
if (ent)
ret = 1;
spin_unlock_bh(&(rwnx_vif->bsteerpriv.lock));
return ret;
}
void aicwf_band_steering_block_entry_add(struct rwnx_vif *rwnx_vif, u8_l *mac)
{
u8_l i;
struct b_steer_block_entry *ent = NULL;
if (rwnx_vif->bsteerpriv.inited == false) {
AICWFDBG(LOGSTEER, STEEER_STR"%s bsteerpriv not inited\n", __func__);
return;
}
AICWFDBG(LOGSTEER, STEEER_STR"%s "MAC_FMT_B"\n", __func__, MAC_ARG_B(mac));
spin_lock_bh(&(rwnx_vif->bsteerpriv.lock));
ent = block_entry_lookup(rwnx_vif, mac);
/* already exist */
if (ent) {
AICWFDBG(LOGSTEER, STEEER_STR"%s already exist\n", __func__);
ent->entry_expire = B_STEER_BLOCK_ENTRY_EXPIRE;
goto func_return;
}
/* find an empty entry */
for (i = 0; i < B_STEER_ENTRY_NUM; i++) {
if (!rwnx_vif->bsteerpriv.block_list[i].used) {
ent = &(rwnx_vif->bsteerpriv.block_list[i]);
break;
}
}
/* add the entry */
if (ent) {
AICWFDBG(LOGSTEER, STEEER_STR"%s "MAC_FMT_B"\n", __func__, MAC_ARG_B(mac));
ent->used = 1;
memcpy(ent->mac, mac, 6);
ent->entry_expire = B_STEER_BLOCK_ENTRY_EXPIRE;
}
func_return:
spin_unlock_bh(&(rwnx_vif->bsteerpriv.lock));
return;
}
void aicwf_band_steering_block_entry_del(struct rwnx_vif *rwnx_vif, u8_l *mac)
{
struct b_steer_block_entry *ent = NULL;
if (rwnx_vif->bsteerpriv.inited == false) {
AICWFDBG(LOGSTEER, STEEER_STR"%s bsteerpriv not inited\n", __func__);
return;
}
AICWFDBG(LOGSTEER, STEEER_STR"%s "MAC_FMT_B"\n", __func__, MAC_ARG_B(mac));
spin_lock_bh(&(rwnx_vif->bsteerpriv.lock));
ent = block_entry_lookup(rwnx_vif, mac);
if (ent)
ent->used = 0;
spin_unlock_bh(&(rwnx_vif->bsteerpriv.lock));
return;
}
void aicwf_band_steering_roam_block_entry_add(struct rwnx_vif *rwnx_vif, u8_l *mac)
{
u8_l i;
struct b_steer_block_entry *ent = NULL;
if (rwnx_vif->bsteerpriv.inited == false) {
AICWFDBG(LOGSTEER, STEEER_STR"%s bsteerpriv not inited\n", __func__);
return;
}
AICWFDBG(LOGSTEER, STEEER_STR"%s "MAC_FMT_B"\n", __func__, MAC_ARG_B(mac));
spin_lock_bh(&rwnx_vif->bsteerpriv.lock);
ent = block_entry_lookup(rwnx_vif, mac);
/* already exist */
if (ent)
goto func_return;
/* find an empty entry */
for (i = 0; i < B_STEER_ENTRY_NUM; i++) {
if (!rwnx_vif->bsteerpriv.block_list[i].used) {
ent = &(rwnx_vif->bsteerpriv.block_list[i]);
break;
}
}
/* add the entry */
if (ent) {
ent->used = 1;
memcpy(ent->mac, mac, 6);
ent->entry_expire = B_STEER_ROAM_BLOCK_ENTRY_EXPIRE;
}
func_return:
spin_unlock_bh(&rwnx_vif->bsteerpriv.lock);
return;
}
void aicwf_band_steering_init(struct rwnx_vif *rwnx_vif)
{
u8_l i;
AICWFDBG(LOGSTEER, STEEER_STR"%s\n", __func__);
spin_lock_init(&rwnx_vif->bsteerpriv.lock);
rwnx_vif->bsteerpriv.inited = true;
spin_lock_bh(&rwnx_vif->bsteerpriv.lock);
/* block entry */
for (i = 0; i < B_STEER_ENTRY_NUM; i++)
memset(&(rwnx_vif->bsteerpriv.block_list[i]), 0, sizeof(struct b_steer_block_entry));
spin_unlock_bh(&rwnx_vif->bsteerpriv.lock);
return;
}
#endif

View file

@ -0,0 +1,40 @@
#ifndef _AICWF_STEERING_H_
#define _AICWF_STEERING_H_
#include <linux/spinlock.h>
#include "lmac_types.h"
#ifdef CONFIG_BAND_STEERING
#define B_STEER_ENTRY_NUM 64//32
#define B_STEER_BLOCK_ENTRY_EXPIRE 60
#define B_STEER_ROAM_BLOCK_ENTRY_EXPIRE 5
#define STEER_UPFATE_TIME 2000
struct rwnx_vif;
struct b_steer_block_entry {
u8_l used;
u8_l mac[6];
u32_l entry_expire;
};
struct b_steer_priv {
struct b_steer_block_entry block_list[B_STEER_ENTRY_NUM];
spinlock_t lock;
bool inited;
};
void aicwf_band_steering_expire(struct rwnx_vif *rwnx_vif);
s32_l aicwf_band_steering_block_chk(struct rwnx_vif *rwnx_vif, u8_l *mac);
void aicwf_band_steering_block_entry_add(struct rwnx_vif *rwnx_vif, u8_l *mac);
void aicwf_band_steering_block_entry_del(struct rwnx_vif *rwnx_vif, u8_l *mac);
void aicwf_band_steering_roam_block_entry_add(struct rwnx_vif *rwnx_vif, u8_l *mac);
void aicwf_band_steering_init(struct rwnx_vif *rwnx_vif);
#endif
#endif

View file

@ -0,0 +1,630 @@
#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_ATOMIC);
if(!msg)
printk("%s: alloc failed \n", __func__);
memset(msg,0,len);
return msg;
}
void intf_tcp_drop_msg(struct rwnx_hw *priv,
struct msg_buf *msg)
{
//printk("%s \n",__func__);
if (msg->skb)
dev_kfree_skb_any(msg->skb);
kfree(msg);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
void tcp_ack_timeout(unsigned long data)
#else
void tcp_ack_timeout(struct timer_list *t)
#endif
{
//printk("%s \n",__func__);
struct tcp_ack_info *ack_info;
struct msg_buf *msg;
struct tcp_ack_manage *ack_m = NULL;
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
ack_info = (struct tcp_ack_info *)data;
#else
ack_info = container_of(t,struct tcp_ack_info,timer);
#endif
ack_m = container_of(ack_info, struct tcp_ack_manage,
ack_info[ack_info->ack_info_num]);
write_seqlock_bh(&ack_info->seqlock);
msg = ack_info->msgbuf;
if (ack_info->busy && msg && !ack_info->in_send_msg) {
ack_info->msgbuf = NULL;
ack_info->drop_cnt = 0;
ack_info->in_send_msg = msg;
write_sequnlock_bh(&ack_info->seqlock);
intf_tx(ack_m->priv, msg);//send skb
//ack_info->in_send_msg = NULL;//add by dwx
//write_sequnlock_bh(&ack_info->seqlock);
//intf_tx(ack_m->priv, msg);
return;
}
write_sequnlock_bh(&ack_info->seqlock);
}
void tcp_ack_init(struct rwnx_hw *priv)
{
int i;
struct tcp_ack_info *ack_info;
struct tcp_ack_manage *ack_m = &priv->ack_m;
printk("========== tcp ack debug %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 = 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)));
}
//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;
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,92 @@
#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 */
};
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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,313 @@
/**
* 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 DATA_BUF_MAX 2048
#define TXPKT_BLOCKSIZE 512
#define MAX_AGGR_TXPKT_LEN (1536*64)
#define CMD_TX_TIMEOUT 5000
#define TX_ALIGNMENT 4
#ifdef CONFIG_USB_TX_AGGR
#define MAX_USB_AGGR_TXPKT_LEN (1536*15)
#endif
#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;
#ifdef CONFIG_USB_MSG_IN_EP
struct completion msg_busrx_trgg;
#endif
struct task_struct *bustx_thread;
struct task_struct *busrx_thread;
#ifdef CONFIG_USB_MSG_IN_EP
struct task_struct *msg_busrx_thread;
#endif
};
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;
#ifdef CONFIG_USB_TX_AGGR
int fw_avail_bufcnt;
//for data tx
atomic_t tx_pktcnt;
struct frame_queue txq;
spinlock_t txqlock;
spinlock_t txdlock;
#endif
#endif//AICWF_USB_SUPPORT
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 500//50
#define AICWF_REORDER_WINSIZE 64
//SN_LESS(a, b) a-b<0 is ture
#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;
u8 forward;
u16 seq_num;
//uint len;
u8 is_amsdu;
u8 is_ap_reord;
u8 ap_fwd_cnt;
u8 ap_resend_cnt;
u8 *rx_data;
struct sk_buff *first_fwd_skb;
struct sk_buff *last_fwd_skb;
struct sk_buff *first_resend_skb;
struct sk_buff *last_resend_skb;
//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 CONFIG_USB_RX_REASSEMBLE
struct sk_buff *rx_reassemble_skb;
u32 rx_reassemble_total_len;
u32 rx_reassemble_cur_len;
u32 rx_reassemble_total_frags;
u32 rx_reassemble_cur_frags;
struct sk_buff *rx_msg_reassemble_skb;
u32 rx_msg_reassemble_total_len;
u32 rx_msg_reassemble_cur_len;
u32 rx_msg_reassemble_total_frags;
u32 rx_msg_reassemble_cur_frags;
#endif
#ifdef CONFIG_USB_MSG_IN_EP
atomic_t msg_rx_cnt;
spinlock_t msg_rxqlock;
struct frame_queue msg_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_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,208 @@
/**
* 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
#define USB_VENDOR_ID_TP 0x2357
#define USB_VENDOR_ID_TENDA 0x2604
#define USB_VENDOR_ID_AIC_V2 0x368B
#define USB_PRODUCT_ID_TP 0x014e
#define USB_PRODUCT_ID_MERCURY 0x014b
#define USB_PRODUCT_ID_FAST 0x014f
#define USB_PRODUCT_ID_TENDA 0x001f
#ifndef CONFIG_USB_BT
#define USB_PRODUCT_ID_AIC8800 0x8800
#define USB_PRODUCT_ID_AIC8801 0x8801
#define USB_PRODUCT_ID_AIC8800DC 0x88dc
#define USB_PRODUCT_ID_AIC8800DW 0x88dd
#define USB_PRODUCT_ID_AIC8800D81 0x8d81
#define USB_PRODUCT_ID_AIC8800D81X2 0x8d91
#define USB_PRODUCT_ID_AIC8800D89X2 0x8d99
#else
#define USB_PRODUCT_ID_AIC8801 0x8801
#define USB_PRODUCT_ID_AIC8800DC 0x88dc
#define USB_PRODUCT_ID_AIC8800DW 0x88dd
#define USB_PRODUCT_ID_AIC8800D81 0x8d81
#define USB_PRODUCT_ID_AIC8800D41 0x8d41
#define USB_PRODUCT_ID_AIC8800D81X2 0x8d91
#define USB_PRODUCT_ID_AIC8800D89X2 0x8d99
#define USB_PRODUCT_ID_AIC8800D83 0x8d83
#define USB_PRODUCT_ID_AIC8800D84 0x8d84
#define USB_PRODUCT_ID_AIC8800D85 0x8d85
#define USB_PRODUCT_ID_AIC8800D88 0x8d88
#endif
enum AICWF_IC{
PRODUCT_ID_AIC8801 = 0,
PRODUCT_ID_AIC8800DC,
PRODUCT_ID_AIC8800DW,
PRODUCT_ID_AIC8800D81,
PRODUCT_ID_AIC8800D81X2,
PRODUCT_ID_AIC8800D89X2
};
#define AICWF_USB_RX_URBS (20)//(200)
#ifdef CONFIG_USB_MSG_IN_EP
#define AICWF_USB_MSG_RX_URBS (100)
#endif
#ifdef CONFIG_USB_TX_AGGR
#define TXQLEN (2048*4)
#define AICWF_USB_TX_URBS (50)
#else
#define AICWF_USB_TX_URBS 200//(100)
#endif
#define AICWF_USB_TX_LOW_WATER (AICWF_USB_TX_URBS/4)//25%
#define AICWF_USB_TX_HIGH_WATER (AICWF_USB_TX_LOW_WATER*3)//75%
#ifdef CONFIG_PLATFORM_HI
#define AICWF_USB_AGGR_MAX_PKT_SIZE (2048*1)
#else
#define AICWF_USB_AGGR_MAX_PKT_SIZE (2048*10)
#endif
#define AICWF_USB_MSG_MAX_PKT_SIZE (2048)
#define AICWF_USB_MAX_PKT_SIZE (2048)
#define AICWF_USB_MAX_AMSDU_PKT_SIZE (2048*6)
#define AICWF_USB_FC_PERSTA_HIGH_WATER 64
#define AICWF_USB_FC_PERSTA_LOW_WATER 16
typedef enum {
USB_TYPE_DATA = 0X00,
USB_TYPE_CFG = 0X10,
USB_TYPE_CFG_CMD_RSP = 0X11,
USB_TYPE_CFG_DATA_CFM = 0X12,
USB_TYPE_CFG_PRINT = 0X13
} 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;
#ifdef CONFIG_PREALLOC_RX_SKB
struct rx_buff *rx_buff;
#endif
#ifdef CONFIG_USB_NO_TRANS_DMA_MAP
u8 *data_buf;
dma_addr_t data_dma_trans_addr;
#endif
bool cfm;
#ifdef CONFIG_USB_TX_AGGR
u8 aggr_cnt;
#endif
u8* usb_align_data;
};
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;
#ifdef CONFIG_USB_TX_AGGR
struct aicwf_tx_priv *tx_priv;
#endif
struct usb_anchor rx_submitted;
struct work_struct rx_urb_work;
#ifdef CONFIG_USB_MSG_IN_EP
struct usb_anchor msg_rx_submitted;
struct work_struct msg_rx_urb_work;
#endif
spinlock_t rx_free_lock;
spinlock_t tx_free_lock;
spinlock_t tx_post_lock;
spinlock_t tx_flow_lock;
#ifdef CONFIG_USB_MSG_IN_EP
spinlock_t msg_rx_free_lock;
#endif
struct list_head rx_free_list;
struct list_head tx_free_list;
struct list_head tx_post_list;
#ifdef CONFIG_USB_MSG_IN_EP
struct list_head msg_rx_free_list;
#endif
uint bulk_in_pipe;
uint bulk_out_pipe;
#ifdef CONFIG_USB_MSG_OUT_EP
uint msg_out_pipe;
#endif
#ifdef CONFIG_USB_MSG_IN_EP
uint msg_in_pipe;
#endif
int tx_free_count;
int tx_post_count;
bool rx_prepare_ready;
#if 0
struct aicwf_usb_buf usb_tx_buf[AICWF_USB_TX_URBS];
struct aicwf_usb_buf usb_rx_buf[AICWF_USB_RX_URBS];
#else
struct aicwf_usb_buf *usb_tx_buf;
struct aicwf_usb_buf *usb_rx_buf;
#endif
#ifdef CONFIG_USB_MSG_IN_EP
struct aicwf_usb_buf usb_msg_rx_buf[AICWF_USB_MSG_RX_URBS];
#endif
int msg_finished;
wait_queue_head_t msg_wait;
ulong msg_busy;
struct urb *msg_out_urb;
#ifdef CONFIG_USB_NO_TRANS_DMA_MAP
dma_addr_t cmd_dma_trans_addr;
#endif
#ifdef CONFIG_RX_TASKLET//AIDEN tasklet
struct tasklet_struct recv_tasklet;
#endif
#ifdef CONFIG_TX_TASKLET//AIDEN tasklet
struct tasklet_struct xmit_tasklet;
#endif
u16 chipid;
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);
#ifdef CONFIG_USB_MSG_IN_EP
int usb_msg_busrx_thread(void *data);
#endif
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_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
struct scanu_result_wext{
struct list_head scanu_re_list;
struct cfg80211_bss *bss;
struct scanu_result_ind *ind;
u32_l *payload;
};
void aicwf_set_wireless_ext( struct net_device *ndev, struct rwnx_hw *rwnx_hw);
void aicwf_scan_complete_event(struct net_device *dev);

View file

@ -0,0 +1,376 @@
/**
******************************************************************************
*
* @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)
/* conversion table from NL80211 to MACHW enum */
extern const int chnl2bw[];
/* conversion table from MACHW to NL80211 enum */
extern const int bw2chnl[];
/* Rate cntrl info */
#define MCS_INDEX_TX_RCX_OFT 0
#define MCS_INDEX_TX_RCX_MASK (0x7F << MCS_INDEX_TX_RCX_OFT)
#define BW_TX_RCX_OFT 7
#define BW_TX_RCX_MASK (0x3 << BW_TX_RCX_OFT)
#define SHORT_GI_TX_RCX_OFT 9
#define SHORT_GI_TX_RCX_MASK (0x1 << SHORT_GI_TX_RCX_OFT)
#define PRE_TYPE_TX_RCX_OFT 10
#define PRE_TYPE_TX_RCX_MASK (0x1 << PRE_TYPE_TX_RCX_OFT)
#define FORMAT_MOD_TX_RCX_OFT 11
#define FORMAT_MOD_TX_RCX_MASK (0x7 << FORMAT_MOD_TX_RCX_OFT)
/* 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
/* 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)
enum {
HW_RATE_1MBPS = 0,
HW_RATE_2MBPS = 1,
HW_RATE_5_5MBPS = 2,
HW_RATE_11MBPS = 3,
HW_RATE_6MBPS = 4,
HW_RATE_9MBPS = 5,
HW_RATE_12MBPS = 6,
HW_RATE_18MBPS = 7,
HW_RATE_24MBPS = 8,
HW_RATE_36MBPS = 9,
HW_RATE_48MBPS = 10,
HW_RATE_54MBPS = 11,
HW_RATE_MAX
};
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;
};
/**
* 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)
#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 static __attribute__((__always_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,771 @@
/**
******************************************************************************
*
* @file ipc_host.c
*
* @brief IPC module.
*
* Copyright (C) RivieraWaves 2011-2019
*
******************************************************************************
*/
/*
* INCLUDE FILES
******************************************************************************
*/
#ifndef __KERNEL__
#include <stdio.h>
#define REG_SW_SET_PROFILING(env, value) do{ }while(0)
#define REG_SW_CLEAR_PROFILING(env, value) do{ }while(0)
#define REG_SW_CLEAR_HOSTBUF_IDX_PROFILING(env) do{ }while(0)
#define REG_SW_SET_HOSTBUF_IDX_PROFILING(env, val) do{ }while(0)
#else
#include <linux/spinlock.h>
#include "rwnx_defs.h"
#include "rwnx_prof.h"
#endif
#include "reg_ipc_app.h"
#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_txdesc_cnt_msk[] =
{
NX_TXDESC_CNT0 - 1,
NX_TXDESC_CNT1 - 1,
NX_TXDESC_CNT2 - 1,
NX_TXDESC_CNT3 - 1,
#if NX_TXQ_CNT == 5
NX_TXDESC_CNT4 - 1,
#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
};
/*
* FUNCTIONS DEFINITIONS
******************************************************************************
*/
/**
* ipc_host_rxdesc_handler() - Handle the reception of a Rx Descriptor
*
* @env: pointer to the IPC Host environment
*
* Called from general IRQ handler when status %IPC_IRQ_E2A_RXDESC is set
*/
static void ipc_host_rxdesc_handler(struct ipc_host_env_tag *env)
{
// For profiling
REG_SW_SET_PROFILING(env->pthis, SW_PROF_IRQ_E2A_RXDESC);
// LMAC has triggered an IT saying that a reception has occurred.
// Then we first need to check the validity of the current hostbuf, and the validity
// of the next hostbufs too, because it is likely that several hostbufs have been
// filled within the time needed for this irq handling
do {
#ifdef CONFIG_RWNX_FULLMAC
// call the external function to indicate that a RX descriptor is received
if (env->cb.recv_data_ind(env->pthis,
env->ipc_host_rxdesc_array[env->ipc_host_rxdesc_idx].hostid) != 0)
#else
// call the external function to indicate that a RX packet is received
if (env->cb.recv_data_ind(env->pthis,
env->ipc_host_rxbuf_array[env->ipc_host_rxbuf_idx].hostid) != 0)
#endif //(CONFIG_RWNX_FULLMAC)
break;
}while(1);
// For profiling
REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IRQ_E2A_RXDESC);
}
/**
* ipc_host_radar_handler() - Handle the reception of radar events
*
* @env: pointer to the IPC Host environment
*
* Called from general IRQ handler when status %IPC_IRQ_E2A_RADAR is set
*/
static void ipc_host_radar_handler(struct ipc_host_env_tag *env)
{
#ifdef CONFIG_RWNX_RADAR
// LMAC has triggered an IT saying that a radar event has been sent to upper layer.
// Then we first need to check the validity of the current msg buf, and the validity
// of the next buffers too, because it is likely that several buffers have been
// filled within the time needed for this irq handling
// call the external function to indicate that a RX packet is received
spin_lock_bh(&((struct rwnx_hw *)env->pthis)->radar.lock);
while (env->cb.recv_radar_ind(env->pthis,
env->ipc_host_radarbuf_array[env->ipc_host_radarbuf_idx].hostid) == 0)
;
spin_unlock_bh(&((struct rwnx_hw *)env->pthis)->radar.lock);
#endif /* CONFIG_RWNX_RADAR */
}
/**
* ipc_host_unsup_rx_vec_handler() - Handle the reception of unsupported rx vector
*
* @env: pointer to the IPC Host environment
*
* Called from general IRQ handler when status %IPC_IRQ_E2A_UNSUP_RX_VEC is set
*/
static void ipc_host_unsup_rx_vec_handler(struct ipc_host_env_tag *env)
{
while (env->cb.recv_unsup_rx_vec_ind(env->pthis,
env->ipc_host_unsuprxvecbuf_array[env->ipc_host_unsuprxvecbuf_idx].hostid) == 0)
;
}
/**
* ipc_host_msg_handler() - Handler for firmware message
*
* @env: pointer to the IPC Host environment
*
* Called from general IRQ handler when status %IPC_IRQ_E2A_MSG is set
*/
static void ipc_host_msg_handler(struct ipc_host_env_tag *env)
{
// For profiling
REG_SW_SET_PROFILING(env->pthis, SW_PROF_IRQ_E2A_MSG);
// LMAC has triggered an IT saying that a message has been sent to upper layer.
// Then we first need to check the validity of the current msg buf, and the validity
// of the next buffers too, because it is likely that several buffers have been
// filled within the time needed for this irq handling
// call the external function to indicate that a RX packet is received
while (env->cb.recv_msg_ind(env->pthis,
env->ipc_host_msgbuf_array[env->ipc_host_msge2a_idx].hostid) == 0)
;
// For profiling
REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IRQ_E2A_MSG);
}
/**
* ipc_host_msgack_handler() - Handle the reception of message acknowledgement
*
* @env: pointer to the IPC Host environment
*
* Called from general IRQ handler when status %IPC_IRQ_E2A_MSG_ACK is set
*/
static void ipc_host_msgack_handler(struct ipc_host_env_tag *env)
{
void *hostid = env->msga2e_hostid;
ASSERT_ERR(hostid);
ASSERT_ERR(env->msga2e_cnt == (((struct lmac_msg *)(&env->shared->msg_a2e_buf.msg))->src_id & 0xFF));
env->msga2e_hostid = NULL;
env->msga2e_cnt++;
env->cb.recv_msgack_ind(env->pthis, hostid);
}
/**
* ipc_host_dbg_handler() - Handle the reception of Debug event
*
* @env: pointer to the IPC Host environment
*
* Called from general IRQ handler when status %IPC_IRQ_E2A_DBG is set
*/
static void ipc_host_dbg_handler(struct ipc_host_env_tag *env)
{
// For profiling
REG_SW_SET_PROFILING(env->pthis, SW_PROF_IRQ_E2A_DBG);
// LMAC has triggered an IT saying that a DBG message has been sent to upper layer.
// Then we first need to check the validity of the current buffer, and the validity
// of the next buffers too, because it is likely that several buffers have been
// filled within the time needed for this irq handling
// call the external function to indicate that a RX packet is received
while(env->cb.recv_dbg_ind(env->pthis,
env->ipc_host_dbgbuf_array[env->ipc_host_dbg_idx].hostid) == 0)
;
// For profiling
REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IRQ_E2A_DBG);
}
/**
* ipc_host_tx_cfm_handler() - Handle the reception of TX confirmation
*
* @env: pointer to the IPC Host environment
* @queue_idx: index of the hardware on which the confirmation has been received
* @user_pos: index of the user position
*
* Called from general IRQ handler when status %IPC_IRQ_E2A_TXCFM is set
*/
static void ipc_host_tx_cfm_handler(struct ipc_host_env_tag *env,
const int queue_idx, const int user_pos)
{
// TX confirmation descriptors have been received
REG_SW_SET_PROFILING(env->pthis, SW_PROF_IRQ_E2A_TXCFM);
while (1)
{
// Get the used index and increase it. We do the increase before knowing if the
// current buffer is confirmed because the callback function may call the
// ipc_host_txdesc_get() in case flow control was enabled and the index has to be
// already at the good value to ensure that the test of FIFO full is correct
uint32_t used_idx = env->txdesc_used_idx[queue_idx][user_pos]++;
uint32_t used_idx_mod = used_idx & nx_txdesc_cnt_msk[queue_idx];
void *host_id = env->tx_host_id[queue_idx][user_pos][used_idx_mod];
// Reset the host id in the array
env->tx_host_id[queue_idx][user_pos][used_idx_mod] = 0;
// call the external function to indicate that a TX packet is freed
if (host_id == 0)
{
// No more confirmations, so put back the used index at its initial value
env->txdesc_used_idx[queue_idx][user_pos] = used_idx;
break;
}
if (env->cb.send_data_cfm(env->pthis, host_id) != 0)
{
// No more confirmations, so put back the used index at its initial value
env->txdesc_used_idx[queue_idx][user_pos] = used_idx;
env->tx_host_id[queue_idx][user_pos][used_idx_mod] = host_id;
// and exit the loop
break;
}
REG_SW_SET_PROFILING_CHAN(env->pthis, SW_PROF_CHAN_CTXT_CFM_HDL_BIT);
REG_SW_CLEAR_PROFILING_CHAN(env->pthis, SW_PROF_CHAN_CTXT_CFM_HDL_BIT);
}
REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IRQ_E2A_TXCFM);
}
/**
******************************************************************************
*/
bool ipc_host_tx_frames_pending(struct ipc_host_env_tag *env)
{
int i, j;
bool tx_frames_pending = false;
for (i = 0; (i < IPC_TXQUEUE_CNT) && !tx_frames_pending; i++)
{
for (j = 0; j < nx_txuser_cnt[i]; j++)
{
uint32_t used_idx = env->txdesc_used_idx[i][j];
uint32_t free_idx = env->txdesc_free_idx[i][j];
// Check if this queue is empty or not
if (used_idx != free_idx)
{
// The queue is not empty, update the flag and exit
tx_frames_pending = true;
break;
}
}
}
return (tx_frames_pending);
}
/**
******************************************************************************
*/
void *ipc_host_tx_flush(struct ipc_host_env_tag *env, const int queue_idx, const int user_pos)
{
uint32_t used_idx = env->txdesc_used_idx[queue_idx][user_pos];
void *host_id = env->tx_host_id[queue_idx][user_pos][used_idx & nx_txdesc_cnt_msk[queue_idx]];
// call the external function to indicate that a TX packet is freed
if (host_id != 0)
{
// Reset the host id in the array
env->tx_host_id[queue_idx][user_pos][used_idx & nx_txdesc_cnt_msk[queue_idx]] = 0;
// Increment the used index
env->txdesc_used_idx[queue_idx][user_pos]++;
}
return (host_id);
}
/**
******************************************************************************
*/
void ipc_host_init(struct ipc_host_env_tag *env,
struct ipc_host_cb_tag *cb,
struct ipc_shared_env_tag *shared_env_ptr,
void *pthis)
{
unsigned int i;
unsigned int size;
unsigned int * dst;
// Reset the environments
// Reset the IPC Shared memory
#if 0
/* check potential platform bug on multiple stores */
memset(shared_env_ptr, 0, sizeof(struct ipc_shared_env_tag));
#else
dst = (unsigned int *)shared_env_ptr;
size = (unsigned int)sizeof(struct ipc_shared_env_tag);
for (i=0; i < size; i+=4)
{
*dst++ = 0;
}
#endif
// Reset the IPC Host environment
memset(env, 0, sizeof(struct ipc_host_env_tag));
// Initialize the shared environment pointer
env->shared = shared_env_ptr;
// Save the callbacks in our own environment
env->cb = *cb;
// Save the pointer to the register base
env->pthis = pthis;
// Initialize buffers numbers and buffers sizes needed for DMA Receptions
env->rx_bufnb = IPC_RXBUF_CNT;
#ifdef CONFIG_RWNX_FULLMAC
env->rxdesc_nb = IPC_RXDESC_CNT;
#endif //(CONFIG_RWNX_FULLMAC)
env->radar_bufnb = IPC_RADARBUF_CNT;
env->radar_bufsz = sizeof(struct radar_pulse_array_desc);
env->unsuprxvec_bufnb = IPC_UNSUPRXVECBUF_CNT;
env->unsuprxvec_bufsz = max(sizeof(struct rx_vector_desc), (size_t) RADIOTAP_HDR_MAX_LEN) +
RADIOTAP_HDR_VEND_MAX_LEN + UNSUP_RX_VEC_DATA_LEN;
env->ipc_e2amsg_bufnb = IPC_MSGE2A_BUF_CNT;
env->ipc_e2amsg_bufsz = sizeof(struct ipc_e2a_msg);
env->ipc_dbg_bufnb = IPC_DBGBUF_CNT;
env->ipc_dbg_bufsz = sizeof(struct ipc_dbg_msg);
for (i = 0; i < CONFIG_USER_MAX; i++)
{
// Initialize the pointers to the hostid arrays
env->tx_host_id[0][i] = env->tx_host_id0[i];
env->tx_host_id[1][i] = env->tx_host_id1[i];
env->tx_host_id[2][i] = env->tx_host_id2[i];
env->tx_host_id[3][i] = env->tx_host_id3[i];
#if NX_TXQ_CNT == 5
env->tx_host_id[4][i] = NULL;
#endif
// Initialize the pointers to the TX descriptor arrays
env->txdesc[0][i] = shared_env_ptr->txdesc0[i];
env->txdesc[1][i] = shared_env_ptr->txdesc1[i];
env->txdesc[2][i] = shared_env_ptr->txdesc2[i];
env->txdesc[3][i] = shared_env_ptr->txdesc3[i];
#if NX_TXQ_CNT == 5
env->txdesc[4][i] = NULL;
#endif
}
#if NX_TXQ_CNT == 5
env->tx_host_id[4][0] = env->tx_host_id4[0];
env->txdesc[4][0] = shared_env_ptr->txdesc4[0];
#endif
}
/**
******************************************************************************
*/
void ipc_host_patt_addr_push(struct ipc_host_env_tag *env, uint32_t addr)
{
struct ipc_shared_env_tag *shared_env_ptr = env->shared;
// Copy the address
shared_env_ptr->pattern_addr = addr;
}
/**
******************************************************************************
*/
int ipc_host_rxbuf_push(struct ipc_host_env_tag *env,
#ifdef CONFIG_RWNX_FULLMAC
uint32_t hostid,
#endif
uint32_t hostbuf)
{
struct ipc_shared_env_tag *shared_env_ptr = env->shared;
REG_SW_CLEAR_HOSTBUF_IDX_PROFILING(env->pthis);
REG_SW_SET_HOSTBUF_IDX_PROFILING(env->pthis, env->ipc_host_rxbuf_idx);
#ifdef CONFIG_RWNX_FULLMAC
// Copy the hostbuf (DMA address) in the ipc shared memory
shared_env_ptr->host_rxbuf[env->ipc_host_rxbuf_idx].hostid = hostid;
shared_env_ptr->host_rxbuf[env->ipc_host_rxbuf_idx].dma_addr = hostbuf;
#else
// Save the hostid and the hostbuf in global array
env->ipc_host_rxbuf_array[env->ipc_host_rxbuf_idx].hostid = hostid;
env->ipc_host_rxbuf_array[env->ipc_host_rxbuf_idx].dma_addr = hostbuf;
shared_env_ptr->host_rxbuf[env->ipc_host_rxbuf_idx] = hostbuf;
#endif //(CONFIG_RWNX_FULLMAC)
// Signal to the embedded CPU that at least one buffer is available
ipc_app2emb_trigger_set(shared_env_ptr, IPC_IRQ_A2E_RXBUF_BACK);
// Increment the array index
env->ipc_host_rxbuf_idx = (env->ipc_host_rxbuf_idx +1)%IPC_RXBUF_CNT;
return (0);
}
#ifdef CONFIG_RWNX_FULLMAC
/**
******************************************************************************
*/
int ipc_host_rxdesc_push(struct ipc_host_env_tag *env, void *hostid,
uint32_t hostbuf)
{
struct ipc_shared_env_tag *shared_env_ptr = env->shared;
// Reset the RX Descriptor DMA Address and increment the counter
env->ipc_host_rxdesc_array[env->ipc_host_rxdesc_idx].dma_addr = hostbuf;
env->ipc_host_rxdesc_array[env->ipc_host_rxdesc_idx].hostid = hostid;
shared_env_ptr->host_rxdesc[env->ipc_host_rxdesc_idx].dma_addr = hostbuf;
// Signal to the embedded CPU that at least one descriptor is available
ipc_app2emb_trigger_set(shared_env_ptr, IPC_IRQ_A2E_RXDESC_BACK);
env->ipc_host_rxdesc_idx = (env->ipc_host_rxdesc_idx + 1) % IPC_RXDESC_CNT;
return (0);
}
#endif /* CONFIG_RWNX_FULLMAC */
/**
******************************************************************************
*/
int ipc_host_radarbuf_push(struct ipc_host_env_tag *env, void *hostid,
uint32_t hostbuf)
{
struct ipc_shared_env_tag *shared_env_ptr = env->shared;
// Save the hostid and the hostbuf in global array
env->ipc_host_radarbuf_array[env->ipc_host_radarbuf_idx].hostid = hostid;
env->ipc_host_radarbuf_array[env->ipc_host_radarbuf_idx].dma_addr = hostbuf;
// Copy the hostbuf (DMA address) in the ipc shared memory
shared_env_ptr->radarbuf_hostbuf[env->ipc_host_radarbuf_idx] = hostbuf;
// Increment the array index
env->ipc_host_radarbuf_idx = (env->ipc_host_radarbuf_idx +1)%IPC_RADARBUF_CNT;
return (0);
}
/**
******************************************************************************
*/
int ipc_host_unsup_rx_vec_buf_push(struct ipc_host_env_tag *env,
void *hostid,
uint32_t hostbuf)
{
struct ipc_shared_env_tag *shared_env_ptr = env->shared;
env->ipc_host_unsuprxvecbuf_array[env->ipc_host_unsuprxvecbuf_idx].hostid = hostid;
env->ipc_host_unsuprxvecbuf_array[env->ipc_host_unsuprxvecbuf_idx].dma_addr = hostbuf;
// Copy the hostbuf (DMA address) in the ipc shared memory
shared_env_ptr->unsuprxvecbuf_hostbuf[env->ipc_host_unsuprxvecbuf_idx] = hostbuf;
// Increment the array index
env->ipc_host_unsuprxvecbuf_idx = (env->ipc_host_unsuprxvecbuf_idx + 1)%IPC_UNSUPRXVECBUF_CNT;
return (0);
}
/**
******************************************************************************
*/
int ipc_host_msgbuf_push(struct ipc_host_env_tag *env, void *hostid,
uint32_t hostbuf)
{
struct ipc_shared_env_tag *shared_env_ptr = env->shared;
// Save the hostid and the hostbuf in global array
env->ipc_host_msgbuf_array[env->ipc_host_msge2a_idx].hostid = hostid;
env->ipc_host_msgbuf_array[env->ipc_host_msge2a_idx].dma_addr = hostbuf;
// Copy the hostbuf (DMA address) in the ipc shared memory
shared_env_ptr->msg_e2a_hostbuf_addr[env->ipc_host_msge2a_idx] = hostbuf;
// Increment the array index
env->ipc_host_msge2a_idx = (env->ipc_host_msge2a_idx +1)%IPC_MSGE2A_BUF_CNT;
return (0);
}
/**
******************************************************************************
*/
int ipc_host_dbgbuf_push(struct ipc_host_env_tag *env, void *hostid,
uint32_t hostbuf)
{
struct ipc_shared_env_tag *shared_env_ptr = env->shared;
// Save the hostid and the hostbuf in global array
env->ipc_host_dbgbuf_array[env->ipc_host_dbg_idx].hostid = hostid;
env->ipc_host_dbgbuf_array[env->ipc_host_dbg_idx].dma_addr = hostbuf;
// Copy the hostbuf (DMA address) in the ipc shared memory
shared_env_ptr->dbg_hostbuf_addr[env->ipc_host_dbg_idx] = hostbuf;
// Increment the array index
env->ipc_host_dbg_idx = (env->ipc_host_dbg_idx +1)%IPC_DBGBUF_CNT;
return (0);
}
/**
******************************************************************************
*/
void ipc_host_dbginfobuf_push(struct ipc_host_env_tag *env, uint32_t infobuf)
{
struct ipc_shared_env_tag *shared_env_ptr = env->shared;
// Copy the hostbuf (DMA address) in the ipc shared memory
shared_env_ptr->la_dbginfo_addr = infobuf;
}
/**
******************************************************************************
*/
volatile struct txdesc_host *ipc_host_txdesc_get(struct ipc_host_env_tag *env, const int queue_idx, const int user_pos)
{
volatile struct txdesc_host *txdesc_free;
uint32_t used_idx = env->txdesc_used_idx[queue_idx][user_pos];
uint32_t free_idx = env->txdesc_free_idx[queue_idx][user_pos];
ASSERT_ERR(queue_idx < IPC_TXQUEUE_CNT);
ASSERT_ERR((free_idx - used_idx) <= nx_txdesc_cnt[queue_idx]);
// Check if a free descriptor is available
if (free_idx != (used_idx + nx_txdesc_cnt[queue_idx]))
{
// Get the pointer to the first free descriptor
txdesc_free = env->txdesc[queue_idx][user_pos] + (free_idx & nx_txdesc_cnt_msk[queue_idx]);
}
else
{
txdesc_free = NULL;
}
return txdesc_free;
}
/**
******************************************************************************
*/
void ipc_host_txdesc_push(struct ipc_host_env_tag *env, const int queue_idx,
const int user_pos, void *host_id)
{
uint32_t free_idx = env->txdesc_free_idx[queue_idx][user_pos] & nx_txdesc_cnt_msk[queue_idx];
volatile struct txdesc_host *txdesc_pushed = env->txdesc[queue_idx][user_pos] + free_idx;
// Descriptor is now ready
txdesc_pushed->ready = 0xFFFFFFFF;
// Save the host id in the environment
env->tx_host_id[queue_idx][user_pos][free_idx] = host_id;
// Increment the index
env->txdesc_free_idx[queue_idx][user_pos]++;
// trigger interrupt!!!
//REG_SW_SET_PROFILING(env->pthis, CO_BIT(queue_idx+SW_PROF_IRQ_A2E_TXDESC_FIRSTBIT));
ipc_app2emb_trigger_setf(env->shared, CO_BIT(user_pos + queue_idx * CONFIG_USER_MAX +
IPC_IRQ_A2E_TXDESC_FIRSTBIT));
}
/**
******************************************************************************
*/
void ipc_host_irq(struct ipc_host_env_tag *env, uint32_t status)
{
// Acknowledge the pending interrupts
ipc_emb2app_ack_clear(env->shared, status);
// And re-read the status, just to be sure that the acknowledgment is
// effective when we start the interrupt handling
ipc_emb2app_status_get(env->shared);
// Optimized for only one IRQ at a time
if (status & IPC_IRQ_E2A_RXDESC)
{
// handle the RX descriptor reception
ipc_host_rxdesc_handler(env);
}
if (status & IPC_IRQ_E2A_MSG_ACK)
{
ipc_host_msgack_handler(env);
}
if (status & IPC_IRQ_E2A_MSG)
{
ipc_host_msg_handler(env);
}
if (status & IPC_IRQ_E2A_TXCFM)
{
int i;
#ifdef __KERNEL__
spin_lock_bh(&((struct rwnx_hw *)env->pthis)->tx_lock);
#endif
// handle the TX confirmation reception
for (i = 0; i < IPC_TXQUEUE_CNT; i++)
{
int j = 0;
#ifdef CONFIG_RWNX_MUMIMO_TX
for (; j < nx_txuser_cnt[i]; j++)
#endif
{
uint32_t q_bit = CO_BIT(j + i * CONFIG_USER_MAX + IPC_IRQ_E2A_TXCFM_POS);
if (status & q_bit)
{
// handle the confirmation
ipc_host_tx_cfm_handler(env, i, j);
}
}
}
#ifdef __KERNEL__
spin_unlock_bh(&((struct rwnx_hw *)env->pthis)->tx_lock);
#endif
}
if (status & IPC_IRQ_E2A_RADAR)
{
// handle the radar event reception
ipc_host_radar_handler(env);
}
if (status & IPC_IRQ_E2A_UNSUP_RX_VEC)
{
// handle the unsupported rx vector reception
ipc_host_unsup_rx_vec_handler(env);
}
if (status & IPC_IRQ_E2A_DBG)
{
ipc_host_dbg_handler(env);
}
if (status & IPC_IRQ_E2A_TBTT_PRIM)
{
env->cb.prim_tbtt_ind(env->pthis);
}
if (status & IPC_IRQ_E2A_TBTT_SEC)
{
env->cb.sec_tbtt_ind(env->pthis);
}
}
/**
******************************************************************************
*/
int ipc_host_msg_push(struct ipc_host_env_tag *env, void *msg_buf, uint16_t len)
{
int i;
uint32_t *src, *dst;
REG_SW_SET_PROFILING(env->pthis, SW_PROF_IPC_MSGPUSH);
ASSERT_ERR(!env->msga2e_hostid);
ASSERT_ERR(round_up(len, 4) <= sizeof(env->shared->msg_a2e_buf.msg));
// Copy the message into the IPC MSG buffer
#ifdef __KERNEL__
src = (uint32_t*)((struct rwnx_cmd *)msg_buf)->a2e_msg;
#else
src = (uint32_t*) msg_buf;
#endif
dst = (uint32_t*)&(env->shared->msg_a2e_buf.msg);
// Copy the message in the IPC queue
for (i=0; i<len; i+=4)
{
*dst++ = *src++;
}
env->msga2e_hostid = msg_buf;
// Trigger the irq to send the message to EMB
ipc_app2emb_trigger_set(env->shared, IPC_IRQ_A2E_MSG);
REG_SW_CLEAR_PROFILING(env->pthis, SW_PROF_IPC_MSGPUSH);
return (0);
}
/**
******************************************************************************
*/
void ipc_host_enable_irq(struct ipc_host_env_tag *env, uint32_t value)
{
// Enable the handled interrupts
ipc_emb2app_unmask_set(env->shared, value);
}
/**
******************************************************************************
*/
void ipc_host_disable_irq(struct ipc_host_env_tag *env, uint32_t value)
{
// Enable the handled interrupts
ipc_emb2app_unmask_clear(env->shared, value);
}
/**
******************************************************************************
*/
uint32_t ipc_host_get_status(struct ipc_host_env_tag *env)
{
volatile uint32_t status;
status = ipc_emb2app_status_get(env->shared);
return status;
}
/**
******************************************************************************
*/
uint32_t ipc_host_get_rawstatus(struct ipc_host_env_tag *env)
{
volatile uint32_t rawstatus;
rawstatus = ipc_emb2app_rawstatus_get(env->shared);
return rawstatus;
}

View file

@ -0,0 +1,508 @@
/**
******************************************************************************
*
* @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
/*
* ENUMERATION
******************************************************************************
*/
enum ipc_host_desc_status
{
/// Descriptor is IDLE
IPC_HOST_DESC_IDLE = 0,
/// Data can be forwarded
IPC_HOST_DESC_FORWARD,
/// Data has to be kept in UMAC memory
IPC_HOST_DESC_KEEP,
/// Delete stored packet
IPC_HOST_DESC_DELETE,
/// Update Frame Length status
IPC_HOST_DESC_LEN_UPDATE,
};
/**
******************************************************************************
* @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[];
/**
******************************************************************************
* @brief Returns the full/not full status of the queue the index of which is
* passed as parameter.
*
* @param[in] env Pointer to the IPC host environment
* @param[in] queue_idx Index of the queue to be checked
*
* @return true if the queue is full, false otherwise
*
******************************************************************************
*/
__INLINE bool ipc_host_queue_full(struct ipc_host_env_tag *env,
const int queue_idx)
{
return (env->txdesc_free_idx[queue_idx] ==
(env->txdesc_used_idx[queue_idx] + nx_txdesc_cnt[queue_idx]));
}
/**
******************************************************************************
* @brief Initialize the IPC running on the Application CPU.
*
* This function:
* - initializes the IPC software environments
* - enables the interrupts in the IPC block
*
* @param[in] env Pointer to the IPC host environment
*
* @warning Since this function resets the IPC Shared memory, it must be called
* before the LMAC FW is launched because LMAC sets some init values in IPC
* Shared memory at boot.
*
******************************************************************************
*/
void ipc_host_init(struct ipc_host_env_tag *env,
struct ipc_host_cb_tag *cb,
struct ipc_shared_env_tag *shared_env_ptr,
void *pthis);
/** @addtogroup IPC_TX
* @{
*/
/**
******************************************************************************
* @brief Retrieve a new free Tx descriptor (host side).
*
* This function returns a pointer to the next Tx descriptor available from the
* queue queue_idx to the host driver. The driver will have to fill it with the
* appropriate endianness and to send it to the
* emb side with ipc_host_txdesc_push().
*
* This function should only be called once until ipc_host_txdesc_push() is called.
*
* This function will return NULL if the queue is full.
*
* @param[in] env Pointer to the IPC host environment
* @param[in] queue_idx Queue index. The index can be inferred from the
* user priority of the incoming packet.
* @param[in] user_pos User position. If MU-MIMO is not used, this value
* shall be 0.
* @return Pointer to the next Tx descriptor free. This can
* point to the host memory or to shared memory,
* depending on IPC implementation.
*
******************************************************************************
*/
volatile struct txdesc_host *ipc_host_txdesc_get(struct ipc_host_env_tag *env,
const int queue_idx,
const int user_pos);
/**
******************************************************************************
* @brief Push a filled Tx descriptor (host side).
*
* This function sets the next Tx descriptor available by the host side:
* - as used for the host side
* - as available for the emb side.
* The Tx descriptor must be correctly filled before calling this function.
*
* This function may trigger an IRQ to the emb CPU depending on the interrupt
* mitigation policy and on the push count.
*
* @param[in] env Pointer to the IPC host environment
* @param[in] queue_idx Queue index. Same value than ipc_host_txdesc_get()
* @param[in] user_pos User position. If MU-MIMO is not used, this value
* shall be 0.
* @param[in] host_id Parameter indicated by the IPC at TX confirmation,
* that allows the driver finding the buffer
*
******************************************************************************
*/
void ipc_host_txdesc_push(struct ipc_host_env_tag *env, const int queue_idx,
const int user_pos, void *host_id);
/**
******************************************************************************
* @brief Check if there are TX frames pending in the TX queues.
*
* @param[in] env Pointer to the IPC host environment
*
* @return true if there are frames pending, false otherwise.
*
******************************************************************************
*/
bool ipc_host_tx_frames_pending(struct ipc_host_env_tag *env);
/**
******************************************************************************
* @brief Get and flush a packet from the IPC queue passed as parameter.
*
* @param[in] env Pointer to the IPC host environment
* @param[in] queue_idx Index of the queue to flush
* @param[in] user_pos User position to flush
*
* @return The flushed hostid if there is one, 0 otherwise.
*
******************************************************************************
*/
void *ipc_host_tx_flush(struct ipc_host_env_tag *env, const int queue_idx,
const int user_pos);
/// @} IPC_TX
/** @addtogroup IPC_RX
* @{
*/
void ipc_host_patt_addr_push(struct ipc_host_env_tag *env, uint32_t addr);
/**
******************************************************************************
* @brief Push a pre-allocated buffer descriptor for Rx packet (host side)
*
* This function should be called by the host IRQ handler to supply the
* embedded side with new empty buffer.
*
* @param[in] env Pointer to the IPC host environment
* @param[in] hostid Packet ID used by the host (skbuff pointer on Linux)
* @param[in] hostbuf Pointer to the start of the buffer payload in the
* host memory (this may be inferred from the skbuff?)
* The length of this buffer should be predefined
* between host and emb statically (constant needed?).
*
******************************************************************************
*/
int ipc_host_rxbuf_push(struct ipc_host_env_tag *env,
#ifdef CONFIG_RWNX_FULLMAC
uint32_t hostid,
#endif
uint32_t hostbuf);
/**
******************************************************************************
* @brief Push a pre-allocated Descriptor
*
* This function should be called by the host IRQ handler to supply the
* embedded side with new empty buffer.
*
* @param[in] env Pointer to the IPC host environment
* @param[in] hostid Address of packet for host
* @param[in] hostbuf Pointer to the start of the buffer payload in the
* host memory. The length of this buffer should be
* predefined between host and emb statically.
*
******************************************************************************
*/
int ipc_host_rxdesc_push(struct ipc_host_env_tag *env, void *hostid,
uint32_t hostbuf);
/**
******************************************************************************
* @brief Push a pre-allocated radar event buffer descriptor
*
* This function is called at Init time to initialize all radar event buffers.
* Then each time embedded send a radar event, this function is used to push
* back the same buffer once it has been handled.
*
* @param[in] env Pointer to the IPC host environment
* @param[in] hostid Address of packet for host
* @param[in] hostbuf Pointer to the start of the buffer payload in the
* host memory. The length of this buffer should be
* predefined between host and emb statically.
*
******************************************************************************
*/
int ipc_host_radarbuf_push(struct ipc_host_env_tag *env, void *hostid,
uint32_t hostbuf);
/**
******************************************************************************
* @brief Push a pre-allocated unsupported rx vector buffer descriptor
*
* This function is called at Init time to initialize all unsupported rx vector
* buffers. Then each time the embedded sends a unsupported rx vector, this
* function is used to push a new unsupported rx vector buffer.
*
* @param[in] env Pointer to the IPC host environment
* @param[in] hostid Address of packet for host
* @param[in] hostbuf Pointer to the start of the buffer payload in the
* host memory. The length of this buffer should be
* predefined between host and emb statically.
*
******************************************************************************
*/
int ipc_host_unsup_rx_vec_buf_push(struct ipc_host_env_tag *env, void *hostid,
uint32_t hostbuf);
/**
******************************************************************************
* @brief Push a pre-allocated buffer descriptor for IPC MSGs (host side)
*
* This function is called at Init time to initialize all Emb2App messages
* buffers. Then each time embedded send a IPC message, this function is used
* to push back the same buffer once it has been handled.
*
* @param[in] env Pointer to the IPC host environment
* @param[in] hostid Address of buffer for host
* @param[in] hostbuf Address of buffer for embedded
* The length of this buffer should be predefined
* between host and emb statically.
*
******************************************************************************
*/
int ipc_host_msgbuf_push(struct ipc_host_env_tag *env, void *hostid,
uint32_t hostbuf);
/**
******************************************************************************
* @brief Push a pre-allocated buffer descriptor for Debug messages (host side)
*
* This function is called at Init time to initialize all debug messages.
* Then each time embedded send a debug message, this function is used to push
* back the same buffer once it has been handled.
*
* @param[in] env Pointer to the IPC host environment
* @param[in] hostid Address of buffer for host
* @param[in] hostbuf Address of buffer for embedded
* The length of this buffer should be predefined
* between host and emb statically.
*
******************************************************************************
*/
int ipc_host_dbgbuf_push(struct ipc_host_env_tag *env, void *hostid,
uint32_t hostbuf);
/**
******************************************************************************
* @brief Push the pre-allocated logic analyzer and debug information buffer
*
* @param[in] env Pointer to the IPC host environment
* @param[in] infobuf Address of buffer for embedded
* The length of this buffer should be predefined
* between host and emb statically.
*
******************************************************************************
*/
void ipc_host_dbginfobuf_push(struct ipc_host_env_tag *env, uint32_t infobuf);
/// @} IPC_RX
/** @addtogroup IPC_MISC
* @{
*/
/**
******************************************************************************
* @brief Handle all IPC interrupts on the host side.
*
* The following interrupts should be handled:
* Tx confirmation, Rx buffer requests, Rx packet ready and kernel messages
*
* @param[in] env Pointer to the IPC host environment
*
******************************************************************************
*/
void ipc_host_irq(struct ipc_host_env_tag *env, uint32_t status);
/**
******************************************************************************
* @brief Send a message to the embedded side
*
* @param[in] env Pointer to the IPC host environment
* @param[in] msg_buf Pointer to the message buffer
* @param[in] msg_len Length of the message to be transmitted
*
* @return Non-null value on failure
*
******************************************************************************
*/
int ipc_host_msg_push(struct ipc_host_env_tag *env, void *msg_buf, uint16_t len);
/**
******************************************************************************
* @brief Enable IPC interrupts
*
* @param[in] env Global ipc_host environment pointer
* @param[in] value Bitfield of the interrupts to enable
*
* @warning After calling this function, IPC interrupts can be triggered at any
* time. Potentially, an interrupt could happen even before returning from the
* function if there is a request pending from the embedded side.
*
******************************************************************************
*/
void ipc_host_enable_irq(struct ipc_host_env_tag *env, uint32_t value);
void ipc_host_disable_irq(struct ipc_host_env_tag *env, uint32_t value);
uint32_t ipc_host_get_status(struct ipc_host_env_tag *env);
uint32_t ipc_host_get_rawstatus(struct ipc_host_env_tag *env);
/// @} IPC_MISC
#endif // _IPC_HOST_H_

View file

@ -0,0 +1,802 @@
/**
****************************************************************************************
*
* @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
*/
#define NX_TX_PAYLOAD_MAX 6
/*
* Message struct/ID API version
*/
#define MSG_API_VER 15
/*
****************************************************************************************
*/
// 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;
#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,589 @@
/**
****************************************************************************************
*
* @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;
///Multi-BSSID index (0 if this is the reference (i.e. transmitted) BSSID)
u8_l mluti_bssid_index;
///Maximum BSSID indicator
u8_l max_bssid_indicator;
};
/// 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_TX_UNDER_80MHZ 0x04
#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
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;
#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
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
#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,161 @@
/**
******************************************************************************
*
* @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_CPU
*****************************************************************************/
#define RAM_LMAC_FW_ADDR 0x00150000
#define ROM_FMAC_FW_ADDR 0x00010000
#define RAM_FMAC_FW_ADDR 0x00120000
#define ROM_FMAC_PATCH_ADDR 0x00180000
#if defined(CONFIG_DPD) || defined(CONFIG_LOFT_CALIB)
#define ROM_FMAC_CALIB_ADDR 0x00130000
#endif
/*****************************************************************************
* 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_ */

View file

@ -0,0 +1,299 @@
/**
****************************************************************************************
*
* @file rwnx_ipc_app.h
*
* @brief IPC module register definitions
*
* Copyright (C) RivieraWaves 2011-2019
*
****************************************************************************************
*/
#ifndef _REG_IPC_APP_H_
#define _REG_IPC_APP_H_
#ifndef __KERNEL__
#include <stdint.h>
#include "arch.h"
#else
#include "ipc_compat.h"
#endif
#include "reg_access.h"
#define REG_IPC_APP_DECODING_MASK 0x0000007F
/**
* @brief APP2EMB_TRIGGER register definition
* <pre>
* Bits Field Name Reset Value
* ----- ------------------ -----------
* 31:00 APP2EMB_TRIGGER 0x0
* </pre>
*/
#define IPC_APP2EMB_TRIGGER_ADDR 0x12000000
#define IPC_APP2EMB_TRIGGER_OFFSET 0x00000000
#define IPC_APP2EMB_TRIGGER_INDEX 0x00000000
#define IPC_APP2EMB_TRIGGER_RESET 0x00000000
__INLINE u32 ipc_app2emb_trigger_get(void *env)
{
return REG_IPC_APP_RD(env, IPC_APP2EMB_TRIGGER_INDEX);
}
__INLINE void ipc_app2emb_trigger_set(void *env, u32 value)
{
REG_IPC_APP_WR(env, IPC_APP2EMB_TRIGGER_INDEX, value);
}
// field definitions
#define IPC_APP2EMB_TRIGGER_MASK ((u32)0xFFFFFFFF)
#define IPC_APP2EMB_TRIGGER_LSB 0
#define IPC_APP2EMB_TRIGGER_WIDTH ((u32)0x00000020)
#define IPC_APP2EMB_TRIGGER_RST 0x0
__INLINE u32 ipc_app2emb_trigger_getf(void *env)
{
u32 localVal = REG_IPC_APP_RD(env, IPC_APP2EMB_TRIGGER_INDEX);
ASSERT_ERR((localVal & ~((u32)0xFFFFFFFF)) == 0);
return (localVal >> 0);
}
__INLINE void ipc_app2emb_trigger_setf(void *env, u32 app2embtrigger)
{
ASSERT_ERR((((u32)app2embtrigger << 0) & ~((u32)0xFFFFFFFF)) == 0);
REG_IPC_APP_WR(env, IPC_APP2EMB_TRIGGER_INDEX, (u32)app2embtrigger << 0);
}
/**
* @brief EMB2APP_RAWSTATUS register definition
* <pre>
* Bits Field Name Reset Value
* ----- ------------------ -----------
* 31:00 EMB2APP_RAWSTATUS 0x0
* </pre>
*/
#define IPC_EMB2APP_RAWSTATUS_ADDR 0x12000004
#define IPC_EMB2APP_RAWSTATUS_OFFSET 0x00000004
#define IPC_EMB2APP_RAWSTATUS_INDEX 0x00000001
#define IPC_EMB2APP_RAWSTATUS_RESET 0x00000000
__INLINE u32 ipc_emb2app_rawstatus_get(void *env)
{
return REG_IPC_APP_RD(env, IPC_EMB2APP_RAWSTATUS_INDEX);
}
__INLINE void ipc_emb2app_rawstatus_set(void *env, u32 value)
{
REG_IPC_APP_WR(env, IPC_EMB2APP_RAWSTATUS_INDEX, value);
}
// field definitions
#define IPC_EMB2APP_RAWSTATUS_MASK ((u32)0xFFFFFFFF)
#define IPC_EMB2APP_RAWSTATUS_LSB 0
#define IPC_EMB2APP_RAWSTATUS_WIDTH ((u32)0x00000020)
#define IPC_EMB2APP_RAWSTATUS_RST 0x0
__INLINE u32 ipc_emb2app_rawstatus_getf(void *env)
{
u32 localVal = REG_IPC_APP_RD(env, IPC_EMB2APP_RAWSTATUS_INDEX);
ASSERT_ERR((localVal & ~((u32)0xFFFFFFFF)) == 0);
return (localVal >> 0);
}
/**
* @brief EMB2APP_ACK register definition
* <pre>
* Bits Field Name Reset Value
* ----- ------------------ -----------
* 31:00 EMB2APP_ACK 0x0
* </pre>
*/
#define IPC_EMB2APP_ACK_ADDR 0x12000008
#define IPC_EMB2APP_ACK_OFFSET 0x00000008
#define IPC_EMB2APP_ACK_INDEX 0x00000002
#define IPC_EMB2APP_ACK_RESET 0x00000000
__INLINE u32 ipc_emb2app_ack_get(void *env)
{
return REG_IPC_APP_RD(env, IPC_EMB2APP_ACK_INDEX);
}
__INLINE void ipc_emb2app_ack_clear(void *env, u32 value)
{
REG_IPC_APP_WR(env, IPC_EMB2APP_ACK_INDEX, value);
}
// field definitions
#define IPC_EMB2APP_ACK_MASK ((u32)0xFFFFFFFF)
#define IPC_EMB2APP_ACK_LSB 0
#define IPC_EMB2APP_ACK_WIDTH ((u32)0x00000020)
#define IPC_EMB2APP_ACK_RST 0x0
__INLINE u32 ipc_emb2app_ack_getf(void *env)
{
u32 localVal = REG_IPC_APP_RD(env, IPC_EMB2APP_ACK_INDEX);
ASSERT_ERR((localVal & ~((u32)0xFFFFFFFF)) == 0);
return (localVal >> 0);
}
__INLINE void ipc_emb2app_ack_clearf(void *env, u32 emb2appack)
{
ASSERT_ERR((((u32)emb2appack << 0) & ~((u32)0xFFFFFFFF)) == 0);
REG_IPC_APP_WR(env, IPC_EMB2APP_ACK_INDEX, (u32)emb2appack << 0);
}
/**
* @brief EMB2APP_UNMASK_SET register definition
* <pre>
* Bits Field Name Reset Value
* ----- ------------------ -----------
* 31:00 EMB2APP_UNMASK 0x0
* </pre>
*/
#define IPC_EMB2APP_UNMASK_SET_ADDR 0x1200000C
#define IPC_EMB2APP_UNMASK_SET_OFFSET 0x0000000C
#define IPC_EMB2APP_UNMASK_SET_INDEX 0x00000003
#define IPC_EMB2APP_UNMASK_SET_RESET 0x00000000
__INLINE u32 ipc_emb2app_unmask_get(void *env)
{
return REG_IPC_APP_RD(env, IPC_EMB2APP_UNMASK_SET_INDEX);
}
__INLINE void ipc_emb2app_unmask_set(void *env, u32 value)
{
REG_IPC_APP_WR(env, IPC_EMB2APP_UNMASK_SET_INDEX, value);
}
// field definitions
#define IPC_EMB2APP_UNMASK_MASK ((u32)0xFFFFFFFF)
#define IPC_EMB2APP_UNMASK_LSB 0
#define IPC_EMB2APP_UNMASK_WIDTH ((u32)0x00000020)
#define IPC_EMB2APP_UNMASK_RST 0x0
__INLINE u32 ipc_emb2app_unmask_getf(void *env)
{
u32 localVal = REG_IPC_APP_RD(env, IPC_EMB2APP_UNMASK_SET_INDEX);
ASSERT_ERR((localVal & ~((u32)0xFFFFFFFF)) == 0);
return (localVal >> 0);
}
__INLINE void ipc_emb2app_unmask_setf(void *env, u32 emb2appunmask)
{
ASSERT_ERR((((u32)emb2appunmask << 0) & ~((u32)0xFFFFFFFF)) == 0);
REG_IPC_APP_WR(env, IPC_EMB2APP_UNMASK_SET_INDEX, (u32)emb2appunmask << 0);
}
/**
* @brief EMB2APP_UNMASK_CLEAR register definition
* <pre>
* Bits Field Name Reset Value
* ----- ------------------ -----------
* 31:00 EMB2APP_UNMASK 0x0
* </pre>
*/
#define IPC_EMB2APP_UNMASK_CLEAR_ADDR 0x12000010
#define IPC_EMB2APP_UNMASK_CLEAR_OFFSET 0x00000010
#define IPC_EMB2APP_UNMASK_CLEAR_INDEX 0x00000004
#define IPC_EMB2APP_UNMASK_CLEAR_RESET 0x00000000
__INLINE void ipc_emb2app_unmask_clear(void *env, u32 value)
{
REG_IPC_APP_WR(env, IPC_EMB2APP_UNMASK_CLEAR_INDEX, value);
}
// fields defined in symmetrical set/clear register
__INLINE void ipc_emb2app_unmask_clearf(void *env, u32 emb2appunmask)
{
ASSERT_ERR((((u32)emb2appunmask << 0) & ~((u32)0xFFFFFFFF)) == 0);
REG_IPC_APP_WR(env, IPC_EMB2APP_UNMASK_CLEAR_INDEX, (u32)emb2appunmask << 0);
}
/**
* @brief EMB2APP_STATUS register definition
* <pre>
* Bits Field Name Reset Value
* ----- ------------------ -----------
* 31:00 EMB2APP_STATUS 0x0
* </pre>
*/
#ifdef CONFIG_RWNX_OLD_IPC
#define IPC_EMB2APP_STATUS_ADDR 0x12000014
#define IPC_EMB2APP_STATUS_OFFSET 0x00000014
#define IPC_EMB2APP_STATUS_INDEX 0x00000005
#else
#define IPC_EMB2APP_STATUS_ADDR 0x1200001C
#define IPC_EMB2APP_STATUS_OFFSET 0x0000001C
#define IPC_EMB2APP_STATUS_INDEX 0x00000007
#endif
#define IPC_EMB2APP_STATUS_RESET 0x00000000
__INLINE u32 ipc_emb2app_status_get(void *env)
{
return REG_IPC_APP_RD(env, IPC_EMB2APP_STATUS_INDEX);
}
__INLINE void ipc_emb2app_status_set(void *env, u32 value)
{
REG_IPC_APP_WR(env, IPC_EMB2APP_STATUS_INDEX, value);
}
// field definitions
#define IPC_EMB2APP_STATUS_MASK ((u32)0xFFFFFFFF)
#define IPC_EMB2APP_STATUS_LSB 0
#define IPC_EMB2APP_STATUS_WIDTH ((u32)0x00000020)
#define IPC_EMB2APP_STATUS_RST 0x0
__INLINE u32 ipc_emb2app_status_getf(void *env)
{
u32 localVal = REG_IPC_APP_RD(env, IPC_EMB2APP_STATUS_INDEX);
ASSERT_ERR((localVal & ~((u32)0xFFFFFFFF)) == 0);
return (localVal >> 0);
}
/**
* @brief APP_SIGNATURE register definition
* <pre>
* Bits Field Name Reset Value
* ----- ------------------ ----------
* 31:00 APP_SIGNATURE 0x0
* </pre>
*/
#define IPC_APP_SIGNATURE_ADDR 0x12000040
#define IPC_APP_SIGNATURE_OFFSET 0x00000040
#define IPC_APP_SIGNATURE_INDEX 0x00000010
#define IPC_APP_SIGNATURE_RESET 0x00000000
__INLINE u32 ipc_app_signature_get(void *env)
{
return REG_IPC_APP_RD(env, IPC_APP_SIGNATURE_INDEX);
}
__INLINE void ipc_app_signature_set(void *env, u32 value)
{
REG_IPC_APP_WR(env, IPC_APP_SIGNATURE_INDEX, value);
}
// field definitions
#define IPC_APP_SIGNATURE_MASK ((u32)0xFFFFFFFF)
#define IPC_APP_SIGNATURE_LSB 0
#define IPC_APP_SIGNATURE_WIDTH ((u32)0x00000020)
#define IPC_APP_SIGNATURE_RST 0x0
__INLINE u32 ipc_app_signature_getf(void *env)
{
u32 localVal = REG_IPC_APP_RD(env, IPC_APP_SIGNATURE_INDEX);
ASSERT_ERR((localVal & ~((u32)0xFFFFFFFF)) == 0);
return (localVal >> 0);
}
#endif // _REG_IPC_APP_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,237 @@
/**
****************************************************************************************
*
* @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);
if ((ret = request_firmware(&config_fw, filename, rwnx_hw->dev))) {
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);
if ((ret = request_firmware(&config_fw, filename, rwnx_hw->dev))) {
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,604 @@
/**
******************************************************************************
*
* rwnx_cmds.c
*
* Handles queueing (push to IPC, ack/cfm from IPC) of commands issued to
* LMAC FW
*
* Copyright (C) RivieraWaves 2014-2019
*
******************************************************************************
*/
//#define CREATE_TRACE_POINTS
#include <linux/list.h>
#include "rwnx_cmds.h"
#include "rwnx_defs.h"
#include "rwnx_strs.h"
#include "rwnx_events.h"
#include "aicwf_txrxif.h"
#include "rwnx_wakelock.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);AIDEN
} else {
if (RWNX_CMD_WAIT_COMPLETE(cmd->flags)) {
cmd->result = 0;
complete(&cmd->complete);
}
}
if(cmd_mgr->queue_sz == 0){
rwnx_wakeup_unlock(g_rwnx_plat->usbdev->rwnx_hw->ws_tx);
}
}
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);
if(cmd_mgr->queue_sz == 0){
rwnx_wakeup_lock(g_rwnx_plat->usbdev->rwnx_hw->ws_tx);
}
cmd_mgr->queue_sz++;
spin_unlock_bh(&cmd_mgr->lock);
WAKE_CMD_WORK(cmd_mgr);
return 0;
}
void rwnx_msg_free_(struct lmac_msg *msg);
static int cmd_mgr_queue(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
{
int ret = 0;
#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
bool defer_push = false;
u8_l empty = 0;
//RWNX_DBG(RWNX_FN_ENTRY_STR);
#ifdef CREATE_TRACE_POINTS
trace_msg_send(cmd->id);
#endif
if(cmd->e2a_msg != NULL) {
do {
spin_lock_bh(&cmd_mgr->lock);
if(cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) {
AICWFDBG(LOGERROR, "cmd queue crashed\n");
cmd->result = -EPIPE;
spin_unlock_bh(&cmd_mgr->lock);
return -EPIPE;
}
empty = list_empty(&cmd_mgr->cmds);
if(!empty) {
spin_unlock_bh(&cmd_mgr->lock);
if(in_softirq()) {
printk("in_softirq:check cmdqueue empty\n");
mdelay(10);
} else {
printk("check cmdqueue empty\n");
msleep(50);
}
}
} while(!empty);//wait for cmd queue empty
} else {
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);
if(cmd_mgr->queue_sz == 0){
rwnx_wakeup_lock(g_rwnx_plat->usbdev->rwnx_hw->ws_tx);
}
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) {
spin_unlock_bh(&cmd_mgr->lock);
AICWFDBG(LOGTRACE, "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) {
spin_unlock_bh(&cmd_mgr->lock);
WAKE_CMD_WORK(cmd_mgr);
} else {
spin_unlock_bh(&cmd_mgr->lock);
}
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/*AIDEN workaround* cmd_mgr->queue_sz*/);
if (!wait_for_completion_killable_timeout(&cmd->complete, tout)) {
printk(KERN_CRIT"%s cmd timed-out cmd_mgr->queue_sz:%d\n", __func__,cmd_mgr->queue_sz);
#ifdef AICWF_SDIO_SUPPORT
ret = aicwf_sdio_writeb(sdiodev, SDIOWIFI_WAKEUP_REG, 2);
if (ret < 0) {
sdio_err("reg:%d write failed!\n", SDIOWIFI_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);
}
ret = -ETIMEDOUT;
spin_unlock_bh(&cmd_mgr->lock);
}
else{
spin_lock_bh(&cmd_mgr->lock);
list_del(&cmd->list);
cmd_mgr->queue_sz--;
if(cmd_mgr->queue_sz == 0){
rwnx_wakeup_unlock(usbdev->rwnx_hw->ws_tx);
}
spin_unlock_bh(&cmd_mgr->lock);
rwnx_cmd_free(cmd);//kfree(cmd);AIDEN
if(!list_empty(&cmd_mgr->cmds) && usbdev->state == USB_UP_ST)
WAKE_CMD_WORK(cmd_mgr);
}
#endif
} else {
cmd->result = 0;
}
return ret;
}
/**
*
*/
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_killable_timeout(&next->complete, tout)) {
printk(KERN_CRIT"%s cmd timed-out cmd_mgr->queue_sz:%d\n", __func__, cmd_mgr->queue_sz);
cmd_dump(next);
spin_lock_bh(&cmd_mgr->lock);
//AIDEN workaround
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 {
spin_lock_bh(&cmd_mgr->lock);
list_del(&next->list);
cmd_mgr->queue_sz--;
if(cmd_mgr->queue_sz == 0){
rwnx_wakeup_unlock(usbdev->rwnx_hw->ws_tx);
}
spin_unlock_bh(&cmd_mgr->lock);
rwnx_cmd_free(next);//kfree(next);AIDEN
}
}
}
}
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);
#ifndef CONFIG_DEBUG_ATOMIC_SLEEP
//spin_lock_bh(&rwnx_hw->cb_lock);
#endif
res = cb(rwnx_hw, cmd, msg);
#ifndef CONFIG_DEBUG_ATOMIC_SLEEP
//spin_unlock_bh(&rwnx_hw->cb_lock);
#endif
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
AICWFDBG(LOGTRACE, "%s cmd->id=%d\n", __func__, 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);
#if 0
if(cmd_mgr->queue_sz == 0){
rwnx_wakeup_unlock(g_rwnx_plat->usbdev->rwnx_hw->ws_tx);
}
#endif
}
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)
{
if(cmd_mgr->print && cmd_mgr->drain){
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;
buffer[3] = 0x0;
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,120 @@
/**
******************************************************************************
*
* 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
#define RWNX_80211_CMD_TIMEOUT_MS 4000//500//300
#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//8 AIDEN
#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,433 @@
/**
******************************************************************************
*
* @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 */
#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(5, 18, 0)
#define IEEE80211_MAX_AMPDU_BUF IEEE80211_MAX_AMPDU_BUF_HE
#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
#ifndef REGULATORY_IGNORE_STALE_KICKOFF
#define REGULATORY_IGNORE_STALE_KICKOFF 0
#endif
#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,203 @@
/**
******************************************************************************
*
* @file rwnx_debugfs.h
*
* @brief Miscellaneous utility function definitions
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#ifndef _RWNX_DEBUGFS_H_
#define _RWNX_DEBUGFS_H_
#include <linux/workqueue.h>
#include <linux/if_ether.h>
#include <linux/version.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,928 @@
/**
******************************************************************************
*
* @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"
#include "rwnx_compat.h"
#ifdef CONFIG_FILTER_TCP_ACK
#include "aicwf_tcp_ack.h"
#endif
#ifdef CONFIG_BAND_STEERING
#include "aicwf_steering.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
//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 >= HIGH_KERNEL_VERSION
#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
#ifndef IEEE80211_MAX_AMPDU_BUF
#define IEEE80211_MAX_AMPDU_BUF 0x100
#endif
#ifndef IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB
#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB 0x08
#endif
#ifndef IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB
#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB 0x04
#endif
#ifndef IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA
#define IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA 0x40
#endif
#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, 7, 0)
#define NL80211_IFTYPE_P2P_DEVICE 10
#define IEEE80211_RADIOTAP_AMPDU_STATUS 20
#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
#ifdef CONFIG_BAND_STEERING
enum band_type {
BAND_ON_24G = 0,
BAND_ON_5G = 1,
BAND_ON_60G = 2,
BAND_ON_6G = 3,
BAND_MAX,
};
enum WIFI_FRAME_TYPE {
WIFI_MGT_TYPE = (0),
};
enum WIFI_FRAME_SUBTYPE {
WIFI_ASSOCREQ = (0 | WIFI_MGT_TYPE),
WIFI_PROBEREQ = (BIT(6) | WIFI_MGT_TYPE),
WIFI_AUTH = (BIT(7) | BIT(5) | BIT(4) | WIFI_MGT_TYPE),
};
struct tmp_feature_sta {
u8_l sta_idx;
u8_l supported_band;
};
#define MAX_PENDING_PROBES 3
struct ap_probe_rsp {
u8_l da[6];
struct work_struct rsp_work;
bool in_use;
};
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
#define NL80211_MESHCONF_POWER_MODE 26
/*
* TDLS capabililites to be enabled in the 5th byte of the
* @WLAN_EID_EXT_CAPABILITY information element
*/
#define WLAN_EXT_CAPA5_TDLS_ENABLED BIT(5)
#define WLAN_EXT_CAPA5_TDLS_PROHIBITED BIT(6)
#define WLAN_EXT_CAPA8_OPMODE_NOTIF BIT(6)
/* TDLS specific payload type in the LLC/SNAP header */
#define WLAN_TDLS_SNAP_RFTYPE 0x2
#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 */
#ifdef CONFIG_BAND_STEERING
u8_l tmp_sta_idx;
enum band_type band;
u32_l freq;
bool start;
#endif
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 */
#ifdef CONFIG_BAND_STEERING
struct workqueue_struct *rsp_wq;
struct timer_list steer_timer;
struct work_struct steer_work;
struct b_steer_priv bsteerpriv;
struct ap_probe_rsp pb_pool[MAX_PENDING_PROBES];
#endif
};
#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 {
u32 rx_pkts;
u32 tx_pkts;
u64 rx_bytes;
u64 tx_bytes;
unsigned long last_act;
struct hw_vect last_rx;
struct rwnx_rx_rate_stats rx_rate;
u32 last_chan_time;
u32 last_chan_busy_time;
u32 tx_ack_succ_stat;
u32 tx_ack_fail_stat;
u32 last_chan_tx_busy_time;
};
#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 */
struct ieee80211_he_cap_elem he_cap_elem;
struct ieee80211_he_mcs_nss_supp he_mcs_nss_supp;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) || defined(CONFIG_VHT_FOR_OLD_KERNEL)
__le32 vht_cap_info;
struct ieee80211_vht_mcs_info supp_mcs;
#endif
};
#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 */
#ifdef CONFIG_DYNAMIC_PERPWR
s8_l rssi_save;
s8_l per_pwrloss;
struct work_struct per_pwr_work;
unsigned long last_jiffies;
#endif
#ifdef CONFIG_BAND_STEERING
u32_l link_time;
s8_l rssi;
u8_l support_band;
#endif
};
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 */
void rwnx_set_conn_state(atomic_t *drv_conn_state, int state);
enum rwnx_drv_connect_status {
RWNX_DRV_STATUS_DISCONNECTED = 0,
RWNX_DRV_STATUS_DISCONNECTING,
RWNX_DRV_STATUS_CONNECTING,
RWNX_DRV_STATUS_CONNECTED,
RWNX_DRV_STATUS_ROAMING,
};
static const char *const s_conn_state[] = {
"RWNX_DRV_STATUS_DISCONNECTED",
"RWNX_DRV_STATUS_DISCONNECTING",
"RWNX_DRV_STATUS_CONNECTING",
"RWNX_DRV_STATUS_CONNECTED",
"RWNX_DRV_STATUS_ROAMING",
};
struct sta_tx_flowctrl {
atomic_t tx_pending_cnt;
u8 flowctrl;
};
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];
#ifdef CONFIG_HE_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;
bool fwlog_en;
bool scanning;
bool p2p_working;
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
struct sta_tx_flowctrl sta_flowctrl[NX_REMOTE_STA_MAX];
#if 0
bool he_flag;
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
struct mac_chan_op ap_chan;
struct ieee80211_channel set_chan;
#endif
#ifdef CONFIG_VHT_FOR_OLD_KERNEL
struct ieee80211_sta_vht_cap vht_cap_2G;
struct ieee80211_sta_vht_cap vht_cap_5G;
#endif
#ifdef CONFIG_USE_WIRELESS_EXT
bool wext_scan;
struct completion wext_scan_com;
struct list_head wext_scanre_list;
char wext_essid[33];
int support_freqs[SCAN_CHANNEL_MAX];
int support_freqs_number;
#ifdef CONFIG_DYNAMIC_PWR
struct timer_list pwrloss_timer;
struct work_struct pwrloss_work;
struct rwnx_vif *read_rssi_vif;
s8 pwrloss_lvl;
u8 sta_rssi_idx;
#endif
#endif
#ifdef CONFIG_BAND_STEERING
u8_l iface_idx;
struct tmp_feature_sta feature_table[NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX];
#endif
};
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->usbdev->chipid == PRODUCT_ID_AIC8801) ||
((g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800DC ||
g_rwnx_plat->usbdev->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,294 @@
/**
******************************************************************************
*
* @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 ? */
if ((ret = request_irq(rwnx_hw->plat->pci_dev->irq, rwnx_irq_hdlr, 0,
"rwnx", rwnx_hw)))
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);
if ((ret = pci_enable_device(pci_dev))) {
dev_err(&(pci_dev->dev), "pci_enable_device failed\n");
goto out_enable;
}
pci_set_master(pci_dev);
if ((ret = pci_request_regions(pci_dev, KBUILD_MODNAME))) {
dev_err(&(pci_dev->dev), "pci_request_regions failed\n");
goto out_request;
}
if (!(rwnx_dini->pci_bar0_vaddr = (u8 *)pci_ioremap_bar(pci_dev, 0))) {
dev_err(&(pci_dev->dev), "pci_ioremap_bar(%d) failed\n", 0);
ret = -ENOMEM;
goto out_bar0;
}
if (!(rwnx_dini->pci_bar4_vaddr = (u8 *)pci_ioremap_bar(pci_dev, 4))) {
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,568 @@
/**
******************************************************************************
*
* @file rwnx_fw_dump.c
*
* @brief Definition of debug fs entries to process fw dump
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#include <linux/kmod.h>
#include <linux/debugfs.h>
#include "rwnx_defs.h"
#include "rwnx_debugfs.h"
static ssize_t rwnx_dbgfs_rhd_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
ssize_t read;
mutex_lock(&priv->dbgdump_elem.mutex);
if (!priv->debugfs.trace_prst) {
mutex_unlock(&priv->dbgdump_elem.mutex);
return 0;
}
read = simple_read_from_buffer(user_buf, count, ppos,
dump->rhd_mem,
dump->dbg_info.rhd_len);
mutex_unlock(&priv->dbgdump_elem.mutex);
return read;
}
DEBUGFS_READ_FILE_OPS(rhd);
static ssize_t rwnx_dbgfs_rbd_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
ssize_t read;
mutex_lock(&priv->dbgdump_elem.mutex);
if (!priv->debugfs.trace_prst) {
mutex_unlock(&priv->dbgdump_elem.mutex);
return 0;
}
read = simple_read_from_buffer(user_buf, count, ppos,
dump->rbd_mem,
dump->dbg_info.rbd_len);
mutex_unlock(&priv->dbgdump_elem.mutex);
return read;
}
DEBUGFS_READ_FILE_OPS(rbd);
static ssize_t rwnx_dbgfs_thdx_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos, int idx)
{
struct rwnx_hw *priv = file->private_data;
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
ssize_t read;
mutex_lock(&priv->dbgdump_elem.mutex);
if (!priv->debugfs.trace_prst) {
mutex_unlock(&priv->dbgdump_elem.mutex);
return 0;
}
read = simple_read_from_buffer(user_buf, count, ppos,
&dump->thd_mem[idx],
dump->dbg_info.thd_len[idx]);
mutex_unlock(&priv->dbgdump_elem.mutex);
return read;
}
static ssize_t rwnx_dbgfs_thd0_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
return rwnx_dbgfs_thdx_read(file, user_buf, count, ppos, 0);
}
DEBUGFS_READ_FILE_OPS(thd0);
static ssize_t rwnx_dbgfs_thd1_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
return rwnx_dbgfs_thdx_read(file, user_buf, count, ppos, 1);
}
DEBUGFS_READ_FILE_OPS(thd1);
static ssize_t rwnx_dbgfs_thd2_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
return rwnx_dbgfs_thdx_read(file, user_buf, count, ppos, 2);
}
DEBUGFS_READ_FILE_OPS(thd2);
static ssize_t rwnx_dbgfs_thd3_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
return rwnx_dbgfs_thdx_read(file, user_buf, count, ppos, 3);
}
DEBUGFS_READ_FILE_OPS(thd3);
#if (NX_TXQ_CNT == 5)
static ssize_t rwnx_dbgfs_thd4_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
return rwnx_dbgfs_thdx_read(file, user_buf, count, ppos, 4);
}
DEBUGFS_READ_FILE_OPS(thd4);
#endif
static ssize_t rwnx_dbgfs_mactrace_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
ssize_t read;
mutex_lock(&priv->dbgdump_elem.mutex);
if (!priv->debugfs.trace_prst) {
char msg[64];
scnprintf(msg, sizeof(msg), "Force trigger\n");
rwnx_dbgfs_trigger_fw_dump(priv, msg);
mutex_unlock(&priv->dbgdump_elem.mutex);
return 0;
}
read = simple_read_from_buffer(user_buf, count, ppos,
dump->la_mem,
dump->dbg_info.la_conf.trace_len);
mutex_unlock(&priv->dbgdump_elem.mutex);
return read;
}
DEBUGFS_READ_FILE_OPS(mactrace);
static ssize_t rwnx_dbgfs_macdiags_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
ssize_t read;
mutex_lock(&priv->dbgdump_elem.mutex);
if (!priv->debugfs.trace_prst) {
mutex_unlock(&priv->dbgdump_elem.mutex);
return 0;
}
read = simple_read_from_buffer(user_buf, count, ppos,
dump->dbg_info.diags_mac,
DBG_DIAGS_MAC_MAX * 2);
mutex_unlock(&priv->dbgdump_elem.mutex);
return read;
}
DEBUGFS_READ_FILE_OPS(macdiags);
static ssize_t rwnx_dbgfs_phydiags_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
ssize_t read;
mutex_lock(&priv->dbgdump_elem.mutex);
if (!priv->debugfs.trace_prst) {
mutex_unlock(&priv->dbgdump_elem.mutex);
return 0;
}
read = simple_read_from_buffer(user_buf, count, ppos,
dump->dbg_info.diags_phy,
DBG_DIAGS_PHY_MAX * 2);
mutex_unlock(&priv->dbgdump_elem.mutex);
return read;
}
DEBUGFS_READ_FILE_OPS(phydiags);
static ssize_t rwnx_dbgfs_hwdiags_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
char buf[16];
int ret;
mutex_lock(&priv->dbgdump_elem.mutex);
if (!priv->debugfs.trace_prst) {
mutex_unlock(&priv->dbgdump_elem.mutex);
return 0;
}
ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
"%08X\n", dump->dbg_info.hw_diag);
mutex_unlock(&priv->dbgdump_elem.mutex);
return simple_read_from_buffer(user_buf, count, ppos, buf, ret);
}
DEBUGFS_READ_FILE_OPS(hwdiags);
static ssize_t rwnx_dbgfs_plfdiags_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
char buf[16];
int ret;
mutex_lock(&priv->dbgdump_elem.mutex);
if (!priv->debugfs.trace_prst) {
mutex_unlock(&priv->dbgdump_elem.mutex);
return 0;
}
ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
"%08X\n", dump->dbg_info.la_conf.diag_conf);
mutex_unlock(&priv->dbgdump_elem.mutex);
return simple_read_from_buffer(user_buf, count, ppos, buf, ret);
}
DEBUGFS_READ_FILE_OPS(plfdiags);
static ssize_t rwnx_dbgfs_swdiags_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
ssize_t read;
mutex_lock(&priv->dbgdump_elem.mutex);
if (!priv->debugfs.trace_prst) {
mutex_unlock(&priv->dbgdump_elem.mutex);
return 0;
}
read = simple_read_from_buffer(user_buf, count, ppos,
&dump->dbg_info.sw_diag,
dump->dbg_info.sw_diag_len);
mutex_unlock(&priv->dbgdump_elem.mutex);
return read;
}
DEBUGFS_READ_FILE_OPS(swdiags);
static ssize_t rwnx_dbgfs_error_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
ssize_t read;
mutex_lock(&priv->dbgdump_elem.mutex);
if (!priv->debugfs.trace_prst) {
mutex_unlock(&priv->dbgdump_elem.mutex);
return 0;
}
read = simple_read_from_buffer(user_buf, count, ppos,
dump->dbg_info.error,
strlen((char *)dump->dbg_info.error));
mutex_unlock(&priv->dbgdump_elem.mutex);
return read;
}
DEBUGFS_READ_FILE_OPS(error);
static ssize_t rwnx_dbgfs_rxdesc_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
char buf[32];
int ret;
ssize_t read;
mutex_lock(&priv->dbgdump_elem.mutex);
if (!priv->debugfs.trace_prst) {
mutex_unlock(&priv->dbgdump_elem.mutex);
return 0;
}
ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
"%08X\n%08X\n", dump->dbg_info.rhd,
dump->dbg_info.rbd);
read = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
mutex_unlock(&priv->dbgdump_elem.mutex);
return read;
}
DEBUGFS_READ_FILE_OPS(rxdesc);
static ssize_t rwnx_dbgfs_txdesc_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
char buf[64];
int len = 0;
int i;
mutex_lock(&priv->dbgdump_elem.mutex);
if (!priv->debugfs.trace_prst) {
mutex_unlock(&priv->dbgdump_elem.mutex);
return 0;
}
for (i = 0; i < NX_TXQ_CNT; i++) {
len += scnprintf(&buf[len], min_t(size_t, sizeof(buf) - len - 1, count),
"%08X\n", dump->dbg_info.thd[i]);
}
mutex_unlock(&priv->dbgdump_elem.mutex);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
DEBUGFS_READ_FILE_OPS(txdesc);
static ssize_t rwnx_dbgfs_macrxptr_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
ssize_t read;
mutex_lock(&priv->dbgdump_elem.mutex);
if (!priv->debugfs.trace_prst) {
mutex_unlock(&priv->dbgdump_elem.mutex);
return 0;
}
read = simple_read_from_buffer(user_buf, count, ppos,
&dump->dbg_info.rhd_hw_ptr,
2 * sizeof(dump->dbg_info.rhd_hw_ptr));
mutex_unlock(&priv->dbgdump_elem.mutex);
return read;
}
DEBUGFS_READ_FILE_OPS(macrxptr);
static ssize_t rwnx_dbgfs_lamacconf_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
ssize_t read;
mutex_lock(&priv->dbgdump_elem.mutex);
if (!priv->debugfs.trace_prst) {
mutex_unlock(&priv->dbgdump_elem.mutex);
return 0;
}
read = simple_read_from_buffer(user_buf, count, ppos,
dump->dbg_info.la_conf.conf,
LA_CONF_LEN * 4);
mutex_unlock(&priv->dbgdump_elem.mutex);
return read;
}
DEBUGFS_READ_FILE_OPS(lamacconf);
static ssize_t rwnx_dbgfs_chaninfo_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
struct dbg_debug_dump_tag *dump = priv->dbgdump_elem.buf.addr;
char buf[4 * 32];
int ret;
mutex_lock(&priv->dbgdump_elem.mutex);
if (!priv->debugfs.trace_prst) {
mutex_unlock(&priv->dbgdump_elem.mutex);
return 0;
}
ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
"type: %d\n"
"prim20_freq: %d MHz\n"
"center1_freq: %d MHz\n"
"center2_freq: %d MHz\n",
(dump->dbg_info.chan_info.info1 >> 8) & 0xFF,
(dump->dbg_info.chan_info.info1 >> 16) & 0xFFFF,
(dump->dbg_info.chan_info.info2 >> 0) & 0xFFFF,
(dump->dbg_info.chan_info.info2 >> 16) & 0xFFFF);
mutex_unlock(&priv->dbgdump_elem.mutex);
return simple_read_from_buffer(user_buf, count, ppos, buf, ret);
}
DEBUGFS_READ_FILE_OPS(chaninfo);
static ssize_t rwnx_dbgfs_um_helper_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
char buf[sizeof(priv->debugfs.helper_cmd)];
int ret;
ret = scnprintf(buf, min_t(size_t, sizeof(buf) - 1, count),
"%s", priv->debugfs.helper_cmd);
return simple_read_from_buffer(user_buf, count, ppos, buf, ret);
}
static ssize_t rwnx_dbgfs_um_helper_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
int eobuf = min_t(size_t, sizeof(priv->debugfs.helper_cmd) - 1, count);
priv->debugfs.helper_cmd[eobuf] = '\0';
if (copy_from_user(priv->debugfs.helper_cmd, user_buf, eobuf))
return -EFAULT;
return count;
}
DEBUGFS_READ_WRITE_FILE_OPS(um_helper);
/*
* Calls a userspace pgm
*/
int rwnx_um_helper(struct rwnx_debugfs *rwnx_debugfs, const char *cmd)
{
char *envp[] = { "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
char **argv;
int argc, ret;
if (!rwnx_debugfs->dir ||
!strlen((cmd = cmd ? cmd : rwnx_debugfs->helper_cmd)))
return 0;
argv = argv_split(in_interrupt() ? GFP_ATOMIC : GFP_KERNEL, cmd, &argc);
if (!argc)
return PTR_ERR(argv);
if ((ret = call_usermodehelper(argv[0], argv, envp,
UMH_WAIT_PROC | UMH_KILLABLE)))
printk(KERN_CRIT "Failed to call %s (%s returned %d)\n",
argv[0], cmd, ret);
argv_free(argv);
return ret;
}
static void rwnx_um_helper_work(struct work_struct *ws)
{
struct rwnx_debugfs *rwnx_debugfs = container_of(ws, struct rwnx_debugfs,
helper_work);
struct rwnx_hw *rwnx_hw = container_of(rwnx_debugfs, struct rwnx_hw,
debugfs);
rwnx_um_helper(rwnx_debugfs, NULL);
if (!rwnx_debugfs->unregistering)
rwnx_umh_done(rwnx_hw);
rwnx_debugfs->helper_scheduled = false;
}
int rwnx_trigger_um_helper(struct rwnx_debugfs *rwnx_debugfs)
{
struct rwnx_hw *rwnx_hw = container_of(rwnx_debugfs, struct rwnx_hw,
debugfs);
if (rwnx_debugfs->helper_scheduled == true) {
dev_err(rwnx_hw->dev, "%s: Already scheduled\n", __func__);
return -EBUSY;
}
spin_lock_bh(&rwnx_debugfs->umh_lock);
if (rwnx_debugfs->unregistering) {
spin_unlock_bh(&rwnx_debugfs->umh_lock);
dev_err(rwnx_hw->dev, "%s: unregistering\n", __func__);
return -ENOENT;
}
rwnx_debugfs->helper_scheduled = true;
schedule_work(&rwnx_debugfs->helper_work);
spin_unlock_bh(&rwnx_debugfs->umh_lock);
return 0;
}
int rwnx_dbgfs_register_fw_dump(struct rwnx_hw *rwnx_hw,
struct dentry *dir_drv,
struct dentry *dir_diags)
{
struct rwnx_debugfs *rwnx_debugfs = &rwnx_hw->debugfs;
BUILD_BUG_ON(sizeof(CONFIG_RWNX_UM_HELPER_DFLT) >=
sizeof(rwnx_debugfs->helper_cmd));
strncpy(rwnx_debugfs->helper_cmd,
CONFIG_RWNX_UM_HELPER_DFLT, sizeof(rwnx_debugfs->helper_cmd));
INIT_WORK(&rwnx_debugfs->helper_work, rwnx_um_helper_work);
DEBUGFS_ADD_FILE(um_helper, dir_drv, S_IWUSR | S_IRUSR);
rwnx_debugfs->trace_prst = rwnx_debugfs->helper_scheduled = false;
spin_lock_init(&rwnx_debugfs->umh_lock);
DEBUGFS_ADD_FILE(rhd, dir_diags, S_IRUSR);
DEBUGFS_ADD_FILE(rbd, dir_diags, S_IRUSR);
DEBUGFS_ADD_FILE(thd0, dir_diags, S_IRUSR);
DEBUGFS_ADD_FILE(thd1, dir_diags, S_IRUSR);
DEBUGFS_ADD_FILE(thd2, dir_diags, S_IRUSR);
DEBUGFS_ADD_FILE(thd3, dir_diags, S_IRUSR);
#if (NX_TXQ_CNT == 5)
DEBUGFS_ADD_FILE(thd4, dir_diags, S_IRUSR);
#endif
DEBUGFS_ADD_FILE(mactrace, dir_diags, S_IRUSR);
DEBUGFS_ADD_FILE(macdiags, dir_diags, S_IRUSR);
DEBUGFS_ADD_FILE(phydiags, dir_diags, S_IRUSR);
DEBUGFS_ADD_FILE(plfdiags, dir_diags, S_IRUSR);
DEBUGFS_ADD_FILE(hwdiags, dir_diags, S_IRUSR);
DEBUGFS_ADD_FILE(swdiags, dir_diags, S_IRUSR);
DEBUGFS_ADD_FILE(error, dir_diags, S_IRUSR);
DEBUGFS_ADD_FILE(rxdesc, dir_diags, S_IRUSR);
DEBUGFS_ADD_FILE(txdesc, dir_diags, S_IRUSR);
DEBUGFS_ADD_FILE(macrxptr, dir_diags, S_IRUSR);
DEBUGFS_ADD_FILE(lamacconf, dir_diags, S_IRUSR);
DEBUGFS_ADD_FILE(chaninfo, dir_diags, S_IRUSR);
return 0;
err:
return -1;
}

View file

@ -0,0 +1,47 @@
/**
******************************************************************************
*
* @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"
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);
printk("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,18 @@
#include <linux/version.h>
#include <linux/skbuff.h>
void rwnx_gki_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);
}

View file

@ -0,0 +1,11 @@
#ifndef __RWNX_GKI_H
#define __RWNX_GKI_H
#ifdef CONFIG_GKI
void rwnx_gki_skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list);
#define rwnx_skb_append rwnx_gki_skb_append
#else
#define rwnx_skb_append skb_append
#endif//CONFIG_GKI
#endif

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,65 @@
/**
******************************************************************************
*
* @file rwnx_main.h
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#ifndef _RWNX_MAIN_H_
#define _RWNX_MAIN_H_
#include "rwnx_defs.h"
int rwnx_cfg80211_init(struct rwnx_plat *rwnx_plat, void **platform_data);
void rwnx_cfg80211_deinit(struct rwnx_hw *rwnx_hw);
int rwnx_fill_station_info(struct rwnx_sta *sta, struct rwnx_vif *vif,
struct station_info *sinfo, u8 *phymode, u32 *tx_phyrate, u32 *rx_phyrate);
extern int testmode;
extern u8 chip_id;
extern u8 chip_sub_id;
extern u8 chip_mcu_id;
#define CHIP_ID_H_MASK 0xC0
#define IS_CHIP_ID_H() ((chip_id & CHIP_ID_H_MASK) == CHIP_ID_H_MASK)
#define RSSI_GET_INTERVAL (10 * 1000) //time interval
#define RSSI_THD_0 (-20) //rssi 0 (dBm)
#define RSSI_THD_1 (-30) //rssi 1 (dBm)
#define RSSI_THD_2 (-75) //rssi 2 (dBm)
#define PWR_LOSS_LVL0 (-10) //RSSI > RSSI_THD_0
#define PWR_LOSS_LVL1 (-5 ) //RSSI_THD_1 < RSSI <RSSI_THD_0
#define PWR_LOSS_LVL2 (0) //RSSI_THD_2 < RSSI <RSSI_THD_1
#define PWR_LOSS_LVL3 (0)//(2) //RSSI <RSSI_THD_2
#define PWR_DELAY_TIME (10 * 1000) //pwr reduced latency time (ms)
struct rwnx_sta *rwnx_retrieve_sta(struct rwnx_hw *rwnx_hw,
struct rwnx_vif *rwnx_vif, u8 *addr,
__le16 fc, bool ap);
#ifdef CONFIG_BAND_STEERING
void aicwf_steering_work(struct work_struct *work);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
void aicwf_steering_timeout(ulong data);
#else
void aicwf_steering_timeout(struct timer_list *t);
#endif
#endif
#ifdef CONFIG_DYNAMIC_PERPWR
void rssi_update_txpwrloss(struct rwnx_sta *sta, s8_l rssi);
void aicwf_txpwer_per_sta_worker(struct work_struct *work);
#endif
#ifdef CONFIG_DYNAMIC_PWR
void set_txpwrloss_ctrl(struct rwnx_hw *rwnx_hw, s8 value);
void aicwf_pwrloss_worker(struct work_struct *work);
#endif
#endif /* _RWNX_MAIN_H_ */

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

File diff suppressed because it is too large Load diff

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

@ -0,0 +1,659 @@
/**
******************************************************************************
*
* @file rwnx_mu_group.c
*
* Copyright (C) RivieraWaves 2016-2019
*
******************************************************************************
*/
#include "rwnx_defs.h"
#include "rwnx_msg_tx.h"
#include "rwnx_events.h"
/**
* rwnx_mu_group_sta_init - Initialize group information for a STA
*
* @sta: Sta to initialize
*/
void rwnx_mu_group_sta_init(struct rwnx_sta *sta,
const struct ieee80211_vht_cap *vht_cap)
{
sta->group_info.map = 0;
sta->group_info.cnt = 0;
sta->group_info.active.next = LIST_POISON1;
sta->group_info.update.next = LIST_POISON1;
sta->group_info.last_update = 0;
sta->group_info.traffic = 0;
sta->group_info.group = 0;
if (!vht_cap ||
!(vht_cap->vht_cap_info & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) {
sta->group_info.map = RWNX_SU_GROUP;
}
}
/**
* rwnx_mu_group_sta_del - Remove a sta from all MU group
*
* @rwnx_hw: main driver data
* @sta: STA to remove
*
* Remove one sta from all the MU groups it belongs to.
*/
void rwnx_mu_group_sta_del(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta)
{
struct rwnx_mu_info *mu = &rwnx_hw->mu;
int i, j, group_id;
bool lock_taken;
u64 map;
lock_taken = (down_interruptible(&mu->lock) == 0);
group_sta_for_each(sta, group_id, map) {
struct rwnx_mu_group *group = rwnx_mu_group_from_id(mu, group_id);
for (i = 0; i < CONFIG_USER_MAX; i++) {
if (group->users[i] == sta) {
group->users[i] = NULL;
group->user_cnt --;
/* Don't keep group with only one user */
if (group->user_cnt == 1) {
for (j = 0; j < CONFIG_USER_MAX; j++) {
if (group->users[j]) {
group->users[j]->group_info.cnt--;
group->users[j]->group_info.map &= ~BIT_ULL(group->group_id);
if (group->users[j]->group_info.group == group_id)
group->users[j]->group_info.group = 0;
group->user_cnt --;
break;
}
}
mu->group_cnt--;
trace_mu_group_delete(group->group_id);
} else {
trace_mu_group_update(group);
}
break;
}
}
WARN((i == CONFIG_USER_MAX), "sta %d doesn't belongs to group %d",
sta->sta_idx, group_id);
}
sta->group_info.map = 0;
sta->group_info.cnt = 0;
sta->group_info.traffic = 0;
if (sta->group_info.active.next != LIST_POISON1)
list_del(&sta->group_info.active);
if (sta->group_info.update.next != LIST_POISON1)
list_del(&sta->group_info.update);
if (lock_taken)
up(&mu->lock);
}
/**
* rwnx_mu_group_sta_get_map - Get the list of group a STA belongs to
*
* @sta: pointer to the sta
*
* @return the list of group a STA belongs to as a bitfield
*/
u64 rwnx_mu_group_sta_get_map(struct rwnx_sta *sta)
{
if (sta)
return sta->group_info.map;
return 0;
}
/**
* rwnx_mu_group_sta_get_pos - Get sta position in a group
*
* @rwnx_hw: main driver data
* @sta: pointer to the sta
* @group_id: Group id
*
* @return the positon of @sta in group @group_id or -1 if the sta
* doesn't belongs to the group (or group id is invalid)
*/
int rwnx_mu_group_sta_get_pos(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
int group_id)
{
struct rwnx_mu_group *group;
int i;
group = rwnx_mu_group_from_id(&rwnx_hw->mu, group_id);
if (!group)
return -1;
for (i = 0; i < CONFIG_USER_MAX; i++) {
if (group->users[i] == sta)
return i;
}
WARN(1, "sta %d doesn't belongs to group %d",
sta->sta_idx, group_id);
return -1;
}
/**
* rwnx_mu_group_move_head - Move (or add) one element at the top of a list
*
* @list: list pointer
* @elem: element to move (or add) at the top of @list
*
*/
static inline
void rwnx_mu_group_move_head(struct list_head *list, struct list_head *elem)
{
if (elem->next != LIST_POISON1) {
__list_del_entry(elem);
}
list_add(elem, list);
}
/**
* rwnx_mu_group_remove_users - Remove all the users of a group
*
* @mu: pointer on MU info
* @group: pointer on group to remove users from
*
* Loop over all users one one group and remove this group from their
* map (and count).
* Each users is also added to the update_sta list, so that group info
* will be resent to fw for this user.
*/
static inline
void rwnx_mu_group_remove_users(struct rwnx_mu_info *mu,
struct rwnx_mu_group *group)
{
struct rwnx_sta *sta;
int i, group_id = group->group_id;
for (i = 0; i < CONFIG_USER_MAX; i++) {
if (group->users[i]) {
sta = group->users[i];
group->users[i] = NULL;
sta->group_info.cnt--;
sta->group_info.map &= ~BIT_ULL(group_id);
rwnx_mu_group_move_head(&mu->update_sta,
&sta->group_info.update);
}
}
if (group->user_cnt)
mu->group_cnt--;
group->user_cnt = 0;
trace_mu_group_delete(group_id);
}
/**
* rwnx_mu_group_add_users - Add users to a group
*
* @mu: pointer on MU info
* @group: pointer on group to add users in
* @nb_user: number of users to ad
* @users: table of user to add
*
* Add @nb_users to @group (which may already have users)
* Each new users is added to the first free position.
* It is assume that @group has at least @nb_user free position. If it is not
* case it only add the number of users needed to complete the group.
* Each users (effectively added to @group) is also added to the update_sta
* list, so that group info will be resent to fw for this user.
*/
static inline
void rwnx_mu_group_add_users(struct rwnx_mu_info *mu,
struct rwnx_mu_group *group,
int nb_user, struct rwnx_sta **users)
{
int i, j, group_id = group->group_id;
if (!group->user_cnt)
mu->group_cnt++;
j = 0;
for (i = 0; i < nb_user ; i++) {
for (; j < CONFIG_USER_MAX ; j++) {
if (group->users[j] == NULL) {
group->users[j] = users[i];
users[i]->group_info.cnt ++;
users[i]->group_info.map |= BIT_ULL(group_id);
rwnx_mu_group_move_head(&(mu->update_sta),
&(users[i]->group_info.update));
group->user_cnt ++;
j ++;
break;
}
WARN(j == (CONFIG_USER_MAX - 1),
"Too many user for group %d (nb_user=%d)",
group_id, group->user_cnt + nb_user - i);
}
}
trace_mu_group_update(group);
}
/**
* rwnx_mu_group_create_one - create on group with a specific group of user
*
* @mu: pointer on MU info
* @nb_user: number of user to include in the group (<= CONFIG_USER_MAX)
* @users: table of users
*
* Try to create a new group with a specific group of users.
* 1- First it checks if a group containing all this users already exists.
*
* 2- Then it checks if it is possible to complete a group which already
* contains at least one user.
*
* 3- Finally it create a new group. To do so, it take take the last group of
* the active_groups list, remove all its current users and add the new ones
*
* In all cases, the group selected is moved at the top of the active_groups
* list
*
* @return 1 if a new group has been created and 0 otherwise
*/
static
int rwnx_mu_group_create_one(struct rwnx_mu_info *mu, int nb_user,
struct rwnx_sta **users, int *nb_group_left)
{
int i, group_id;
struct rwnx_mu_group *group;
u64 group_match;
u64 group_avail;
group_match = users[0]->group_info.map;
group_avail = users[0]->group_info.map;
for (i = 1; i < nb_user ; i++) {
group_match &= users[i]->group_info.map;
group_avail |= users[i]->group_info.map;
}
if (group_match) {
/* a group (or more) with all the users already exist */
group_id = RWNX_GET_FIRST_GROUP_ID(group_match);
group = rwnx_mu_group_from_id(mu, group_id);
rwnx_mu_group_move_head(&mu->active_groups, &group->list);
return 0;
}
#if CONFIG_USER_MAX > 2
if (group_avail) {
/* check if we can complete a group */
struct rwnx_sta *users2[CONFIG_USER_MAX];
int nb_user2;
group_for_each(group_id, group_avail) {
group = rwnx_mu_group_from_id(mu, group_id);
if (group->user_cnt == CONFIG_USER_MAX)
continue;
nb_user2 = 0;
for (i = 0; i < nb_user ; i++) {
if (!(users[i]->group_info.map & BIT_ULL(group_id))) {
users2[nb_user2] = users[i];
nb_user2++;
}
}
if ((group->user_cnt + nb_user2) <= CONFIG_USER_MAX) {
rwnx_mu_group_add_users(mu, group, nb_user2, users2);
rwnx_mu_group_move_head(&mu->active_groups, &group->list);
return 0;
}
}
}
#endif /* CONFIG_USER_MAX > 2*/
/* create a new group */
group = list_last_entry(&mu->active_groups, struct rwnx_mu_group, list);
rwnx_mu_group_remove_users(mu, group);
rwnx_mu_group_add_users(mu, group, nb_user, users);
rwnx_mu_group_move_head(&mu->active_groups, &group->list);
(*nb_group_left)--;
return 1;
}
/**
* rwnx_mu_group_create - Create new groups containing one specific sta
*
* @mu: pointer on MU info
* @sta: sta to add in each group
* @nb_group_left: maximum number to new group allowed. (updated on exit)
*
* This will try to create "all the possible" group with a specific sta being
* a member of all these group.
* The function simply loops over the @active_sta list (starting from @sta).
* When it has (CONFIG_USER_MAX - 1) users it try to create a new group with
* these users (plus @sta).
* Loops end when there is no more users, or no more new group is allowed
*
*/
static
void rwnx_mu_group_create(struct rwnx_mu_info *mu, struct rwnx_sta *sta,
int *nb_group_left)
{
struct rwnx_sta *user_sta = sta;
struct rwnx_sta *users[CONFIG_USER_MAX];
int nb_user = 1;
users[0] = sta;
while (*nb_group_left) {
list_for_each_entry_continue(user_sta, &mu->active_sta, group_info.active) {
users[nb_user] = user_sta;
if (++nb_user == CONFIG_USER_MAX) {
break;
}
}
if (nb_user > 1) {
if (rwnx_mu_group_create_one(mu, nb_user, users, nb_group_left))
(*nb_group_left)--;
if (nb_user < CONFIG_USER_MAX)
break;
else
nb_user = 1;
} else
break;
}
}
/**
* rwnx_mu_group_work - process function of the "group_work"
*
* The work is scheduled when several sta (MU beamformee capable) are active.
* When called, the @active_sta contains the list of the active sta (starting
* from the most recent one), and @active_groups is the list of all possible
* groups ordered so that the first one is the most recently used.
*
* This function will create new groups, starting from group containing the
* most "active" sta.
* For example if the list of sta is :
* sta8 -> sta3 -> sta4 -> sta7 -> sta1
* and the number of user per group is 3, it will create grooups :
* - sta8 / sta3 / sta4
* - sta8 / sta7 / sta1
* - sta3 / sta4 / sta7
* - sta3 / sta1
* - sta4 / sta7 / sta1
* - sta7 / sta1
*
* To create new group, the least used group are first selected.
* It is only allowed to create NX_MU_GROUP_MAX per iteration.
*
* Once groups have been updated, mu group information is update to the fw.
* To do so it use the @update_sta list to know which sta has been affected.
* As it is necessary to wait for fw confirmation before using this new group
* MU is temporarily disabled during group update
*
* Work is then rescheduled.
*
* At the end of the function, both @active_sta and @update_sta list are empty.
*
* Note:
* - This is still a WIP, and will require more tuning
* - not all combinations are created, to avoid to much processing.
* - reschedule delay should be adaptative
*/
void rwnx_mu_group_work(struct work_struct *ws)
{
struct delayed_work *dw = container_of(ws, struct delayed_work, work);
struct rwnx_mu_info *mu = container_of(dw, struct rwnx_mu_info, group_work);
struct rwnx_hw *rwnx_hw = container_of(mu, struct rwnx_hw, mu);
struct rwnx_sta *sta, *next;
int nb_group_left = NX_MU_GROUP_MAX;
if (WARN(!rwnx_hw->mod_params->mutx,
"In group formation work, but mutx disabled"))
return;
if (down_interruptible(&mu->lock) != 0)
return;
mu->update_count++;
if (!mu->update_count)
mu->update_count++;
list_for_each_entry_safe(sta, next, &mu->active_sta, group_info.active) {
if (nb_group_left)
rwnx_mu_group_create(mu, sta, &nb_group_left);
sta->group_info.last_update = mu->update_count;
list_del(&sta->group_info.active);
}
if (! list_empty(&mu->update_sta)) {
list_for_each_entry_safe(sta, next, &mu->update_sta, group_info.update) {
rwnx_send_mu_group_update_req(rwnx_hw, sta);
list_del(&sta->group_info.update);
}
}
mu->next_group_select = jiffies;
rwnx_mu_group_sta_select(rwnx_hw);
up(&mu->lock);
return;
}
/**
* rwnx_mu_group_init - Initialize MU groups
*
* @rwnx_hw: main driver data
*
* Initialize all MU group
*/
void rwnx_mu_group_init(struct rwnx_hw *rwnx_hw)
{
struct rwnx_mu_info *mu = &rwnx_hw->mu;
int i;
INIT_LIST_HEAD(&mu->active_groups);
INIT_LIST_HEAD(&mu->active_sta);
INIT_LIST_HEAD(&mu->update_sta);
for (i = 0; i < NX_MU_GROUP_MAX; i++) {
int j;
mu->groups[i].user_cnt = 0;
mu->groups[i].group_id = i + 1;
for (j = 0; j < CONFIG_USER_MAX; j++) {
mu->groups[i].users[j] = NULL;
}
list_add(&mu->groups[i].list, &mu->active_groups);
}
mu->update_count = 1;
mu->group_cnt = 0;
mu->next_group_select = jiffies;
INIT_DELAYED_WORK(&mu->group_work, rwnx_mu_group_work);
sema_init(&mu->lock, 1);
}
/**
* rwnx_mu_set_active_sta - mark a STA as active
*
* @rwnx_hw: main driver data
* @sta: pointer to the sta
* @traffic: Number of buffers to add in the sta's traffic counter
*
* If @sta is MU beamformee capable (and MU-MIMO tx is enabled) move the
* sta at the top of the @active_sta list.
* It also schedule the group_work if not already scheduled and the list
* contains more than one sta.
*
* If a STA was already in the list during the last group update
* (i.e. sta->group_info.last_update == mu->update_count) it is not added
* back to the list until a sta that wasn't active during the last update is
* added. This is to avoid scheduling group update with a list of sta that
* were all already in the list during previous update.
*
* It is called with mu->lock taken.
*/
void rwnx_mu_set_active_sta(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
int traffic)
{
struct rwnx_mu_info *mu = &rwnx_hw->mu;
if (!sta || (sta->group_info.map & RWNX_SU_GROUP))
return;
sta->group_info.traffic += traffic;
if ((sta->group_info.last_update != mu->update_count) ||
!list_empty(&mu->active_sta)) {
rwnx_mu_group_move_head(&mu->active_sta, &sta->group_info.active);
if (!delayed_work_pending(&mu->group_work) &&
!list_is_singular(&mu->active_sta)) {
schedule_delayed_work(&mu->group_work,
msecs_to_jiffies(RWNX_MU_GROUP_INTERVAL));
}
}
}
/**
* rwnx_mu_set_active_group - mark a MU group as active
*
* @rwnx_hw: main driver data
* @group_id: Group id
*
* move a group at the top of the @active_groups list
*/
void rwnx_mu_set_active_group(struct rwnx_hw *rwnx_hw, int group_id)
{
struct rwnx_mu_info *mu = &rwnx_hw->mu;
struct rwnx_mu_group *group = rwnx_mu_group_from_id(mu, group_id);
rwnx_mu_group_move_head(&mu->active_groups, &group->list);
}
/**
* rwnx_mu_group_sta_select - Select the best group for MU stas
*
* @rwnx_hw: main driver data
*
* For each MU capable client of AP interfaces this function tries to select
* the best group to use.
*
* In first pass, gather information from all stations to form statistics
* for each group for the previous @RWNX_MU_GROUP_SELECT_INTERVAL interval:
* - number of buffers transmitted
* - number of user
*
* Then groups with more than 2 active users, are assigned after being ordered
* by traffic :
* - group with highest traffic is selected: set this group for all its users
* - update nb_users for all others group (as one sta may be in several groups)
* - select the next group that have still mor than 2 users and assign it.
* - continue until all group are processed
*
*/
void rwnx_mu_group_sta_select(struct rwnx_hw *rwnx_hw)
{
struct rwnx_mu_info *mu = &rwnx_hw->mu;
int nb_users[NX_MU_GROUP_MAX + 1];
int traffic[NX_MU_GROUP_MAX + 1];
int order[NX_MU_GROUP_MAX + 1];
struct rwnx_sta *sta;
struct rwnx_vif *vif;
struct list_head *head;
u64 map;
int i, j, update, group_id, tmp, cnt = 0;
if (!mu->group_cnt || time_before(jiffies, mu->next_group_select))
return;
list_for_each_entry(vif, &rwnx_hw->vifs, list) {
if (RWNX_VIF_TYPE(vif) != NL80211_IFTYPE_AP)
continue;
#ifdef CONFIG_RWNX_FULLMAC
head = &vif->ap.sta_list;
#else
head = &vif->stations;
#endif /* CONFIG_RWNX_FULLMAC */
memset(nb_users, 0, sizeof(nb_users));
memset(traffic, 0, sizeof(traffic));
list_for_each_entry(sta, head, list) {
int sta_traffic = sta->group_info.traffic;
/* reset statistics for next selection */
sta->group_info.traffic = 0;
if (sta->group_info.group)
trace_mu_group_selection(sta, 0);
sta->group_info.group = 0;
if (sta->group_info.cnt == 0 ||
sta_traffic < RWNX_MU_GROUP_MIN_TRAFFIC)
continue;
group_sta_for_each(sta, group_id, map) {
nb_users[group_id]++;
traffic[group_id] += sta_traffic;
/* list group with 2 users or more */
if (nb_users[group_id] == 2)
order[cnt++] = group_id;
}
}
/* reorder list of group with more that 2 users */
update = 1;
while(update) {
update = 0;
for (i = 0; i < cnt - 1; i++) {
if (traffic[order[i]] < traffic[order[i + 1]]) {
tmp = order[i];
order[i] = order[i + 1];
order[i + 1] = tmp;
update = 1;
}
}
}
/* now assign group in traffic order */
for (i = 0; i < cnt ; i ++) {
struct rwnx_mu_group *group;
group_id = order[i];
if (nb_users[group_id] < 2)
continue;
group = rwnx_mu_group_from_id(mu, group_id);
for (j = 0; j < CONFIG_USER_MAX ; j++) {
if (group->users[j]) {
trace_mu_group_selection(group->users[j], group_id);
group->users[j]->group_info.group = group_id;
group_sta_for_each(group->users[j], tmp, map) {
if (group_id != tmp)
nb_users[tmp]--;
}
}
}
}
}
mu->next_group_select = jiffies +
msecs_to_jiffies(RWNX_MU_GROUP_SELECT_INTERVAL);
mu->next_group_select |= 1;
}

View file

@ -0,0 +1,179 @@
/**
******************************************************************************
*
* @file rwnx_mu_group.h
*
* Copyright (C) RivieraWaves 2016-2019
*
******************************************************************************
*/
#ifndef _RWNX_MU_GROUP_H_
#define _RWNX_MU_GROUP_H_
#include <linux/workqueue.h>
#include <linux/semaphore.h>
struct rwnx_hw;
struct rwnx_sta;
#ifdef CONFIG_RWNX_MUMIMO_TX
/**
* struct rwnx_sta_group_info - Group Information for a STA
*
* @active: node for @mu->active_sta list
* @update: node for @mu->update_sta list
* @cnt: Number of groups the STA belongs to
* @map: Bitfield of groups the sta belongs to
* @traffic: Number of buffers sent since previous group selection
* @group: Id of the group selected by previous group selection
* (cf @rwnx_mu_group_sta_select)
*/
struct rwnx_sta_group_info {
struct list_head active;
struct list_head update;
u16 last_update;
int cnt;
u64 map;
int traffic;
u8 group;
};
/**
* struct mu_group_info - Information about the users of a group
*
* @list: node for mu->active_groups
* @group_id: Group identifier
* @user_cnt: Number of the users in the group
* @users: Pointer to the sta, ordered by user position
*/
struct rwnx_mu_group {
struct list_head list;
int group_id;
int user_cnt;
struct rwnx_sta *users[CONFIG_USER_MAX];
};
/**
* struct rwnx_mu_info - Information about all MU group
*
* @active_groups: List of all possible groups. Ordered from the most recently
* used one to the least one (and possibly never used)
* @active_sta: List of MU beamformee sta that have been active (since previous
* group update). Ordered from the most recently active.
* @update_sta: List of sta whose group information has changed and need to be
* updated at fw level
* @groups: Table of all groups
* @group_work: Work item used to schedule group update
* @update_count: Counter used to identify the last group formation update.
* (cf rwnx_sta_group_info.last_update)
* @lock: Lock taken during group update. If tx happens lock is taken, then tx
* will not used MU.
* @next_group_assign: Next time the group selection should be run
* (ref @rwnx_mu_group_sta_select)
* @group_cnt: Number of group created
*/
struct rwnx_mu_info {
struct list_head active_groups;
struct list_head active_sta;
struct list_head update_sta;
struct rwnx_mu_group groups[NX_MU_GROUP_MAX];
struct delayed_work group_work;
u16 update_count;
struct semaphore lock;
unsigned long next_group_select;
u8 group_cnt;
};
#define RWNX_SU_GROUP BIT_ULL(0)
#define RWNX_MU_GROUP_MASK 0x7ffffffffffffffeULL
#define RWNX_MU_GROUP_INTERVAL 200 /* in ms */
#define RWNX_MU_GROUP_SELECT_INTERVAL 100 /* in ms */
// minimum traffic in a RWNX_MU_GROUP_SELECT_INTERVAL to consider the sta
#define RWNX_MU_GROUP_MIN_TRAFFIC 50 /* in number of packet */
#define RWNX_GET_FIRST_GROUP_ID(map) (fls64(map) - 1)
#define group_sta_for_each(sta, id, map) \
map = sta->group_info.map & RWNX_MU_GROUP_MASK; \
for (id = (fls64(map) - 1) ; id > 0 ; \
map &= ~(u64)BIT_ULL(id), id = (fls64(map) - 1))
#define group_for_each(id, map) \
for (id = (fls64(map) - 1) ; id > 0 ; \
map &= ~(u64)BIT_ULL(id), id = (fls64(map) - 1))
#define RWNX_MUMIMO_INFO_POS_ID(info) (((info) >> 6) & 0x3)
#define RWNX_MUMIMO_INFO_GROUP_ID(info) ((info) & 0x3f)
static inline
struct rwnx_mu_group *rwnx_mu_group_from_id(struct rwnx_mu_info *mu, int id)
{
if (id > NX_MU_GROUP_MAX)
return NULL;
return &mu->groups[id - 1];
}
void rwnx_mu_group_sta_init(struct rwnx_sta *sta,
const struct ieee80211_vht_cap *vht_cap);
void rwnx_mu_group_sta_del(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta);
u64 rwnx_mu_group_sta_get_map(struct rwnx_sta *sta);
int rwnx_mu_group_sta_get_pos(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
int group_id);
void rwnx_mu_group_init(struct rwnx_hw *rwnx_hw);
void rwnx_mu_set_active_sta(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
int traffic);
void rwnx_mu_set_active_group(struct rwnx_hw *rwnx_hw, int group_id);
void rwnx_mu_group_sta_select(struct rwnx_hw *rwnx_hw);
#else /* ! CONFIG_RWNX_MUMIMO_TX */
static inline
void rwnx_mu_group_sta_init(struct rwnx_sta *sta,
const struct ieee80211_vht_cap *vht_cap)
{}
static inline
void rwnx_mu_group_sta_del(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta)
{}
static inline
u64 rwnx_mu_group_sta_get_map(struct rwnx_sta *sta)
{
return 0;
}
static inline
int rwnx_mu_group_sta_get_pos(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
int group_id)
{
return 0;
}
static inline
void rwnx_mu_group_init(struct rwnx_hw *rwnx_hw)
{}
static inline
void rwnx_mu_set_active_sta(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
int traffic)
{}
static inline
void rwnx_mu_set_active_group(struct rwnx_hw *rwnx_hw, int group_id)
{}
static inline
void rwnx_mu_group_sta_select(struct rwnx_hw *rwnx_hw)
{}
#endif /* CONFIG_RWNX_MUMIMO_TX */
#endif /* _RWNX_MU_GROUP_H_ */

View file

@ -0,0 +1,94 @@
/**
******************************************************************************
*
* @file rwnx_pci.c
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#include <linux/pci.h>
#include <linux/module.h>
#include "rwnx_defs.h"
#include "rwnx_dini.h"
#include "rwnx_v7.h"
#define PCI_VENDOR_ID_DINIGROUP 0x17DF
#define PCI_DEVICE_ID_DINIGROUP_DNV6_F2PCIE 0x1907
#define PCI_DEVICE_ID_XILINX_CEVA_VIRTEX7 0x7011
static const struct pci_device_id rwnx_pci_ids[] = {
{PCI_DEVICE(PCI_VENDOR_ID_DINIGROUP, PCI_DEVICE_ID_DINIGROUP_DNV6_F2PCIE)},
{PCI_DEVICE(PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_XILINX_CEVA_VIRTEX7)},
{0,}
};
/* Uncomment this for depmod to create module alias */
/* We don't want this on development platform */
//MODULE_DEVICE_TABLE(pci, rwnx_pci_ids);
static int rwnx_pci_probe(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id)
{
struct rwnx_plat *rwnx_plat = NULL;
void *drvdata;
int ret = -ENODEV;
RWNX_DBG(RWNX_FN_ENTRY_STR);
if (pci_id->vendor == PCI_VENDOR_ID_DINIGROUP) {
ret = rwnx_dini_platform_init(pci_dev, &rwnx_plat);
} else if (pci_id->vendor == PCI_VENDOR_ID_XILINX) {
ret = rwnx_v7_platform_init(pci_dev, &rwnx_plat);
}
if (ret)
return ret;
rwnx_plat->pci_dev = pci_dev;
ret = rwnx_platform_init(rwnx_plat, &drvdata);
pci_set_drvdata(pci_dev, drvdata);
if (ret)
rwnx_plat->deinit(rwnx_plat);
return ret;
}
static void rwnx_pci_remove(struct pci_dev *pci_dev)
{
struct rwnx_hw *rwnx_hw;
struct rwnx_plat *rwnx_plat;
RWNX_DBG(RWNX_FN_ENTRY_STR);
rwnx_hw = pci_get_drvdata(pci_dev);
rwnx_plat = rwnx_hw->plat;
rwnx_platform_deinit(rwnx_hw);
rwnx_plat->deinit(rwnx_plat);
pci_set_drvdata(pci_dev, NULL);
}
static struct pci_driver rwnx_pci_drv = {
.name = KBUILD_MODNAME,
.id_table = rwnx_pci_ids,
.probe = rwnx_pci_probe,
.remove = rwnx_pci_remove
};
int rwnx_pci_register_drv(void)
{
return pci_register_driver(&rwnx_pci_drv);
}
void rwnx_pci_unregister_drv(void)
{
pci_unregister_driver(&rwnx_pci_drv);
}

View file

@ -0,0 +1,17 @@
/**
******************************************************************************
*
* @file rwnx_pci.h
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#ifndef _RWNX_PCI_H_
#define _RWNX_PCI_H_
int rwnx_pci_register_drv(void);
void rwnx_pci_unregister_drv(void);
#endif /* _RWNX_PCI_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,186 @@
/**
******************************************************************************
*
* @file rwnx_platorm.h
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#ifndef _RWNX_PLATFORM_H_
#define _RWNX_PLATFORM_H_
#include <linux/pci.h>
#include "lmac_msg.h"
#define RWNX_CONFIG_FW_NAME "rwnx_settings.ini"
#define RWNX_PHY_CONFIG_TRD_NAME "rwnx_trident.ini"
#define RWNX_PHY_CONFIG_KARST_NAME "rwnx_karst.ini"
#define RWNX_AGC_FW_NAME "agcram.bin"
#define RWNX_LDPC_RAM_NAME "ldpcram.bin"
#ifdef CONFIG_RWNX_FULLMAC
#define RWNX_MAC_FW_BASE_NAME "fmacfw"
#elif defined CONFIG_RWNX_FHOST
#define RWNX_MAC_FW_BASE_NAME "fhostfw"
#endif /* CONFIG_RWNX_FULLMAC */
#ifdef CONFIG_RWNX_TL4
#define RWNX_MAC_FW_NAME RWNX_MAC_FW_BASE_NAME".hex"
#else
#define RWNX_MAC_FW_NAME RWNX_MAC_FW_BASE_NAME".ihex"
#define RWNX_MAC_FW_NAME2 RWNX_MAC_FW_BASE_NAME".bin"
#endif
#define RWNX_FCU_FW_NAME "fcuram.bin"
#if (defined(CONFIG_DPD) && !defined(CONFIG_FORCE_DPD_CALIB))
#define FW_DPDRESULT_NAME_8800DC "aic_dpdresult_lite_8800dc.bin"
#endif
#define POWER_LEVEL_INVALID_VAL (127)
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,
};
/**
* Type of memory to access (cf rwnx_plat.get_address)
*
* @RWNX_ADDR_CPU To access memory of the embedded CPU
* @RWNX_ADDR_SYSTEM To access memory/registers of one subsystem of the
* embedded system
*
*/
enum rwnx_platform_addr {
RWNX_ADDR_CPU,
RWNX_ADDR_SYSTEM,
RWNX_ADDR_MAX,
};
typedef struct
{
txpwr_lvl_conf_t txpwr_lvl;
txpwr_lvl_conf_v2_t txpwr_lvl_v2;
txpwr_lvl_conf_v3_t txpwr_lvl_v3;
txpwr_lvl_conf_v4_t txpwr_lvl_v4;
txpwr_lvl_adj_conf_t txpwr_lvl_adj;
txpwr_loss_conf_t txpwr_loss;
txpwr_ofst_conf_t txpwr_ofst;
txpwr_ofst2x_conf_t txpwr_ofst2x;
txpwr_ofst2x_conf_v2_t txpwr_ofst2x_v2;
xtal_cap_conf_t xtal_cap;
} userconfig_info_t;
extern userconfig_info_t userconfig_info;
typedef enum {
REGIONS_SRRC,
REGIONS_FCC,
REGIONS_ETSI,
REGIONS_JP,
REGIONS_DEFAULT,
} Regions_code;
struct rwnx_hw;
/**
* struct rwnx_plat - Operation pointers for RWNX PCI platform
*
* @pci_dev: pointer to pci dev
* @enabled: Set if embedded platform has been enabled (i.e. fw loaded and
* ipc started)
* @enable: Configure communication with the fw (i.e. configure the transfers
* enable and register interrupt)
* @disable: Stop communication with the fw
* @deinit: Free all ressources allocated for the embedded platform
* @get_address: Return the virtual address to access the requested address on
* the platform.
* @ack_irq: Acknowledge the irq at link level.
* @get_config_reg: Return the list (size + pointer) of registers to restore in
* order to reload the platform while keeping the current configuration.
*
* @priv Private data for the link driver
*/
struct rwnx_plat {
struct pci_dev *pci_dev;
#ifdef AICWF_SDIO_SUPPORT
struct aic_sdio_dev *sdiodev;
#endif
#ifdef AICWF_USB_SUPPORT
struct aic_usb_dev *usbdev;
#endif
bool enabled;
bool wait_disconnect_cb;
int (*enable)(struct rwnx_hw *rwnx_hw);
int (*disable)(struct rwnx_hw *rwnx_hw);
void (*deinit)(struct rwnx_plat *rwnx_plat);
u8* (*get_address)(struct rwnx_plat *rwnx_plat, int addr_name,
unsigned int offset);
void (*ack_irq)(struct rwnx_plat *rwnx_plat);
int (*get_config_reg)(struct rwnx_plat *rwnx_plat, const u32 **list);
u8 priv[0] __aligned(sizeof(void *));
};
#define RWNX_ADDR(plat, base, offset) \
plat->get_address(plat, base, offset)
#define RWNX_REG_READ(plat, base, offset) \
readl(plat->get_address(plat, base, offset))
#define RWNX_REG_WRITE(val, plat, base, offset) \
writel(val, plat->get_address(plat, base, offset))
extern struct rwnx_plat *g_rwnx_plat;
int rwnx_platform_init(struct rwnx_plat *rwnx_plat, void **platform_data);
void rwnx_platform_deinit(struct rwnx_hw *rwnx_hw);
int rwnx_platform_on(struct rwnx_hw *rwnx_hw, void *config);
void rwnx_platform_off(struct rwnx_hw *rwnx_hw, void **config);
int is_file_exist(char* name);
void get_userconfig_txpwr_lvl_in_fdrv(txpwr_lvl_conf_t *txpwr_lvl);
void get_userconfig_txpwr_lvl_v2_in_fdrv(txpwr_lvl_conf_v2_t *txpwr_lvl_v2);
void get_userconfig_txpwr_lvl_v3_in_fdrv(txpwr_lvl_conf_v3_t *txpwr_lvl_v3);
void get_userconfig_txpwr_lvl_v4_in_fdrv(txpwr_lvl_conf_v4_t *txpwr_lvl_v4);
void get_userconfig_txpwr_lvl_adj_in_fdrv(txpwr_lvl_adj_conf_t *txpwr_lvl_adj);
void get_userconfig_txpwr_ofst_in_fdrv(txpwr_ofst_conf_t *txpwr_ofst);
void get_userconfig_txpwr_ofst2x_in_fdrv(txpwr_ofst2x_conf_t *txpwr_ofst2x);
void get_userconfig_txpwr_ofst2x_v2_in_fdrv(txpwr_ofst2x_conf_v2_t *txpwr_ofst2x_v2);
void get_userconfig_txpwr_loss(txpwr_loss_conf_t *txpwr_loss);
void set_txpwr_loss_ofst(s8_l value);
void rwnx_plat_userconfig_parsing(char *buffer, int size);
uint8_t get_ccode_region(char * ccode);
u8 get_region_index(char * name);
#ifdef CONFIG_POWER_LIMIT
int8_t rwnx_plat_powerlimit_save(u8_l band, char *channel, u8_l bw, char *limit, char *name);
void rwnx_plat_powerlimit_parsing(char *buffer, int size, char *cc);
int8_t get_powerlimit_by_freq(uint8_t band, uint16_t freq, uint8_t r_idx);
int8_t get_powerlimit_by_chnum(uint8_t chnum, uint8_t r_idx, uint8_t bw);
#endif
int rwnx_platform_register_drv(void);
void rwnx_platform_unregister_drv(void);
extern struct device *rwnx_platform_get_dev(struct rwnx_plat *rwnx_plat);
static inline unsigned int rwnx_platform_get_irq(struct rwnx_plat *rwnx_plat)
{
return rwnx_plat->pci_dev->irq;
}
#endif /* _RWNX_PLATFORM_H_ */

View file

@ -0,0 +1,133 @@
/**
****************************************************************************************
*
* @file rwnx_prof.h
*
* Copyright (C) RivieraWaves 2012-2019
*
****************************************************************************************
*/
#ifndef _RWNX_PROF_H_
#define _RWNX_PROF_H_
#include "reg_access.h"
#include "rwnx_platform.h"
static inline void rwnx_prof_set(struct rwnx_hw *rwnx_hw, int val)
{
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
RWNX_REG_WRITE(val, rwnx_plat, RWNX_ADDR_SYSTEM, NXMAC_SW_SET_PROFILING_ADDR);
}
static inline void rwnx_prof_clear(struct rwnx_hw *rwnx_hw, int val)
{
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
RWNX_REG_WRITE(val, rwnx_plat, RWNX_ADDR_SYSTEM, NXMAC_SW_CLEAR_PROFILING_ADDR);
}
#if 0
/* Defines for SW Profiling registers values */
enum {
TX_IPC_IRQ,
TX_IPC_EVT,
TX_PREP_EVT,
TX_DMA_IRQ,
TX_MAC_IRQ,
TX_PAYL_HDL,
TX_CFM_EVT,
TX_IPC_CFM,
RX_MAC_IRQ, // 8
RX_TRIGGER_EVT,
RX_DMA_IRQ,
RX_DMA_EVT,
RX_IPC_IND,
RX_MPDU_XFER,
DBG_PROF_MAX
};
#endif
enum {
SW_PROF_HOSTBUF_IDX = 12,
/****** IPC IRQs related signals ******/
/* E2A direction */
SW_PROF_IRQ_E2A_RXDESC = 16, // to make sure we let 16 bits available for LMAC FW
SW_PROF_IRQ_E2A_TXCFM,
SW_PROF_IRQ_E2A_DBG,
SW_PROF_IRQ_E2A_MSG,
SW_PROF_IPC_MSGPUSH,
SW_PROF_MSGALLOC,
SW_PROF_MSGIND,
SW_PROF_DBGIND,
/* A2E direction */
SW_PROF_IRQ_A2E_TXCFM_BACK,
/****** Driver functions related signals ******/
SW_PROF_WAIT_QUEUE_STOP,
SW_PROF_WAIT_QUEUE_WAKEUP,
SW_PROF_RWNXDATAIND,
SW_PROF_RWNX_IPC_IRQ_HDLR,
SW_PROF_RWNX_IPC_THR_IRQ_HDLR,
SW_PROF_IEEE80211RX,
SW_PROF_RWNX_PATTERN,
SW_PROF_MAX
};
// [LT]For debug purpose only
#if (0)
#define SW_PROF_CHAN_CTXT_CFM_HDL_BIT (21)
#define SW_PROF_CHAN_CTXT_CFM_BIT (22)
#define SW_PROF_CHAN_CTXT_CFM_SWDONE_BIT (23)
#define SW_PROF_CHAN_CTXT_PUSH_BIT (24)
#define SW_PROF_CHAN_CTXT_QUEUE_BIT (25)
#define SW_PROF_CHAN_CTXT_TX_BIT (26)
#define SW_PROF_CHAN_CTXT_TX_PAUSE_BIT (27)
#define SW_PROF_CHAN_CTXT_PSWTCH_BIT (28)
#define SW_PROF_CHAN_CTXT_SWTCH_BIT (29)
// TO DO: update this
#define REG_SW_SET_PROFILING_CHAN(env, bit) \
rwnx_prof_set((struct rwnx_hw*)env, BIT(bit))
#define REG_SW_CLEAR_PROFILING_CHAN(env, bit) \
rwnx_prof_clear((struct rwnx_hw*)env, BIT(bit))
#else
#define SW_PROF_CHAN_CTXT_CFM_HDL_BIT (0)
#define SW_PROF_CHAN_CTXT_CFM_BIT (0)
#define SW_PROF_CHAN_CTXT_CFM_SWDONE_BIT (0)
#define SW_PROF_CHAN_CTXT_PUSH_BIT (0)
#define SW_PROF_CHAN_CTXT_QUEUE_BIT (0)
#define SW_PROF_CHAN_CTXT_TX_BIT (0)
#define SW_PROF_CHAN_CTXT_TX_PAUSE_BIT (0)
#define SW_PROF_CHAN_CTXT_PSWTCH_BIT (0)
#define SW_PROF_CHAN_CTXT_SWTCH_BIT (0)
#define REG_SW_SET_PROFILING_CHAN(env, bit) do {} while (0)
#define REG_SW_CLEAR_PROFILING_CHAN(env, bit) do {} while (0)
#endif
#ifdef CONFIG_RWNX_SW_PROFILING
/* Macros for SW PRofiling registers access */
#define REG_SW_SET_PROFILING(env, bit) \
rwnx_prof_set((struct rwnx_hw*)env, BIT(bit))
#define REG_SW_SET_HOSTBUF_IDX_PROFILING(env, val) \
rwnx_prof_set((struct rwnx_hw*)env, val<<(SW_PROF_HOSTBUF_IDX))
#define REG_SW_CLEAR_PROFILING(env, bit) \
rwnx_prof_clear((struct rwnx_hw*)env, BIT(bit))
#define REG_SW_CLEAR_HOSTBUF_IDX_PROFILING(env) \
rwnx_prof_clear((struct rwnx_hw*)env,0x0F<<(SW_PROF_HOSTBUF_IDX))
#else
#define REG_SW_SET_PROFILING(env, value) do {} while (0)
#define REG_SW_CLEAR_PROFILING(env, value) do {} while (0)
#define REG_SW_SET_HOSTBUF_IDX_PROFILING(env, val) do {} while (0)
#define REG_SW_CLEAR_HOSTBUF_IDX_PROFILING(env) do {} while (0)
#endif
#endif /* _RWNX_PROF_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,186 @@
/**
******************************************************************************
*
* @file rwnx_radar.h
*
* @brief Functions to handle radar detection
*
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#ifndef _RWNX_RADAR_H_
#define _RWNX_RADAR_H_
#include <linux/nl80211.h>
struct rwnx_vif;
struct rwnx_hw;
enum rwnx_radar_chain {
RWNX_RADAR_RIU = 0,
RWNX_RADAR_FCU,
RWNX_RADAR_LAST
};
enum rwnx_radar_detector {
RWNX_RADAR_DETECT_DISABLE = 0, /* Ignore radar pulses */
RWNX_RADAR_DETECT_ENABLE = 1, /* Process pattern detection but do not
report radar to upper layer (for test) */
RWNX_RADAR_DETECT_REPORT = 2 /* Process pattern detection and report
radar to upper layer. */
};
#ifdef CONFIG_RWNX_RADAR
#include <linux/workqueue.h>
#include <linux/spinlock.h>
#define RWNX_RADAR_PULSE_MAX 32
/**
* struct rwnx_radar_pulses - List of pulses reported by HW
* @index: write index
* @count: number of valid pulses
* @buffer: buffer of pulses
*/
struct rwnx_radar_pulses {
/* Last radar pulses received */
int index;
int count;
u32 buffer[RWNX_RADAR_PULSE_MAX];
};
/**
* struct dfs_pattern_detector - DFS pattern detector
* @region: active DFS region, NL80211_DFS_UNSET until set
* @num_radar_types: number of different radar types
* @last_pulse_ts: time stamp of last valid pulse in usecs
* @prev_jiffies:
* @radar_detector_specs: array of radar detection specs
* @channel_detectors: list connecting channel_detector elements
*/
struct dfs_pattern_detector {
u8 enabled;
enum nl80211_dfs_regions region;
u8 num_radar_types;
u64 last_pulse_ts;
u32 prev_jiffies;
const struct radar_detector_specs *radar_spec;
struct list_head detectors[];
};
#define NX_NB_RADAR_DETECTED 4
/**
* struct rwnx_radar_detected - List of radar detected
*/
struct rwnx_radar_detected {
u16 index;
u16 count;
s64 time[NX_NB_RADAR_DETECTED];
s16 freq[NX_NB_RADAR_DETECTED];
};
#define RWNX_RADAR_DUMP_EN 1
#ifdef RWNX_RADAR_DUMP_EN
#define RWNX_RADARR_DUMP_NB 32
struct rwnx_radar_dump {
u32 cnt;
u32 idx;
u32 ps[RWNX_RADARR_DUMP_NB];
u64 tm[RWNX_RADARR_DUMP_NB];
u64 ts[RWNX_RADARR_DUMP_NB];
};
#endif
enum rwnx_radar_status {
RWNX_RADAR_IDLE = 0,
RWNX_RADAR_CAC_BUSY = 1,
RWNX_RADAR_CAC_DONE = 2,
RWNX_RADAR_INSERVICE_BUSY = 3,
RWNX_RADAR_INSERVICE_DONE = 4
};
struct rwnx_radar {
struct rwnx_radar_pulses pulses[RWNX_RADAR_LAST];
struct dfs_pattern_detector *dpd[RWNX_RADAR_LAST];
struct rwnx_radar_detected detected[RWNX_RADAR_LAST];
#ifdef RWNX_RADAR_DUMP_EN
struct rwnx_radar_dump *rmem;
#endif
u16 status;
u16 sta_num;
struct work_struct detection_work; /* Work used to process radar pulses */
spinlock_t lock; /* lock for pulses processing */
/* In softmac cac is handled by mac80211 */
#ifdef CONFIG_RWNX_FULLMAC
struct delayed_work cac_work; /* Work used to handle CAC */
struct rwnx_vif *cac_vif; /* vif on which we started CAC */
#endif
};
void rwnx_radar_reset_rmem(struct rwnx_radar *radar);
void rwnx_radar_init_rmem(struct rwnx_radar *radar);
void rwnx_radar_deinit_rmem(struct rwnx_radar *radar);
bool rwnx_radar_detection_init(struct rwnx_radar *radar);
void rwnx_radar_detection_deinit(struct rwnx_radar *radar);
bool rwnx_radar_set_domain(struct rwnx_radar *radar,
enum nl80211_dfs_regions region);
void rwnx_radar_detection_enable(struct rwnx_radar *radar, u8 enable, u8 chain);
bool rwnx_radar_detection_is_enable(struct rwnx_radar *radar, u8 chain);
void rwnx_radar_start_cac(struct rwnx_radar *radar, u32 cac_time_ms,
struct rwnx_vif *vif);
void rwnx_radar_cancel_cac(struct rwnx_radar *radar);
void rwnx_radar_detection_enable_on_cur_channel(struct rwnx_hw *rwnx_hw);
int rwnx_radar_dump_pattern_detector(char *buf, size_t len,
struct rwnx_radar *radar, u8 chain);
int rwnx_radar_dump_radar_detected(char *buf, size_t len,
struct rwnx_radar *radar, u8 chain);
#else
struct rwnx_radar {
};
static inline bool rwnx_radar_detection_init(struct rwnx_radar *radar)
{return true;}
static inline void rwnx_radar_detection_deinit(struct rwnx_radar *radar)
{}
static inline bool rwnx_radar_set_domain(struct rwnx_radar *radar,
enum nl80211_dfs_regions region)
{return true;}
static inline void rwnx_radar_detection_enable(struct rwnx_radar *radar,
u8 enable, u8 chain)
{}
static inline bool rwnx_radar_detection_is_enable(struct rwnx_radar *radar,
u8 chain)
{return false;}
static inline void rwnx_radar_start_cac(struct rwnx_radar *radar,
u32 cac_time_ms, struct rwnx_vif *vif)
{}
static inline void rwnx_radar_cancel_cac(struct rwnx_radar *radar)
{}
static inline void rwnx_radar_detection_enable_on_cur_channel(struct rwnx_hw *rwnx_hw)
{}
static inline int rwnx_radar_dump_pattern_detector(char *buf, size_t len,
struct rwnx_radar *radar,
u8 chain)
{return 0;}
static inline int rwnx_radar_dump_radar_detected(char *buf, size_t len,
struct rwnx_radar *radar,
u8 chain)
{return 0;}
#endif /* CONFIG_RWNX_RADAR */
#endif // _RWNX_RADAR_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,408 @@
/**
******************************************************************************
*
* @file rwnx_rx.h
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#ifndef _RWNX_RX_H_
#define _RWNX_RX_H_
#include "aicwf_txrxif.h"
#define SERVER_PORT 67
#define CLIENT_PORT 68
#define DHCP_MAGIC 0x63825363
#define DHCP_ACK 5
#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */
#define DHCP_OPTION_END 255
enum rx_status_bits
{
/// The buffer can be forwarded to the networking stack
RX_STAT_FORWARD = 1 << 0,
/// A new buffer has to be allocated
RX_STAT_ALLOC = 1 << 1,
/// The buffer has to be deleted
RX_STAT_DELETE = 1 << 2,
/// The length of the buffer has to be updated
RX_STAT_LEN_UPDATE = 1 << 3,
/// The length in the Ethernet header has to be updated
RX_STAT_ETH_LEN_UPDATE = 1 << 4,
/// Simple copy
RX_STAT_COPY = 1 << 5,
/// Spurious frame (inform upper layer and discard)
RX_STAT_SPURIOUS = 1 << 6,
/// packet for monitor interface
RX_STAT_MONITOR = 1 << 7,
};
/*
* Decryption status subfields.
* {
*/
#define RWNX_RX_HD_DECR_UNENC 0 // ENCRYPTION TYPE NONE
#define RWNX_RX_HD_DECR_WEP 1 // ENCRYPTION TYPE WEP
#define RWNX_RX_HD_DECR_TKIP 2 // ENCRYPTION TYPE TKIP
#define RWNX_RX_HD_DECR_CCMP128 3 // ENCRYPTION TYPE CCMP128
#define RWNX_RX_HD_DECR_CCMP256 4 // ENCRYPTION TYPE CCMP256
#define RWNX_RX_HD_DECR_GCMP128 5 // ENCRYPTION TYPE GCMP128
#define RWNX_RX_HD_DECR_GCMP256 6 // ENCRYPTION TYPE GCMP256
#define RWNX_RX_HD_DECR_WAPI 7 // ENCRYPTION TYPE WAPI
// @}
//#ifdef CONFIG_RWNX_MON_DATA
#if 0
#define RX_MACHDR_BACKUP_LEN 64
#endif
struct rx_vector_1_old {
/** Receive Vector 1a */
u32 leg_length :12;
u32 leg_rate : 4;
u32 ht_length :16;
/** Receive Vector 1b */
u32 _ht_length : 4; // FIXME
u32 short_gi : 1;
u32 stbc : 2;
u32 smoothing : 1;
u32 mcs : 7;
u32 pre_type : 1;
u32 format_mod : 3;
u32 ch_bw : 2;
u32 n_sts : 3;
u32 lsig_valid : 1;
u32 sounding : 1;
u32 num_extn_ss : 2;
u32 aggregation : 1;
u32 fec_coding : 1;
u32 dyn_bw : 1;
u32 doze_not_allowed : 1;
/** Receive Vector 1c */
u32 antenna_set : 8;
u32 partial_aid : 9;
u32 group_id : 6;
u32 first_user : 1;
s32 rssi1 : 8;
/** Receive Vector 1d */
s32 rssi2 : 8;
s32 rssi3 : 8;
s32 rssi4 : 8;
u32 reserved_1d : 8;
};
struct rx_leg_vect
{
u8 dyn_bw_in_non_ht : 1;
u8 chn_bw_in_non_ht : 2;
u8 rsvd_nht : 4;
u8 lsig_valid : 1;
} __packed;
struct rx_ht_vect
{
u16 sounding : 1;
u16 smoothing : 1;
u16 short_gi : 1;
u16 aggregation : 1;
u16 stbc : 1;
u16 num_extn_ss : 2;
u16 lsig_valid : 1;
u16 mcs : 7;
u16 fec : 1;
u16 length :16;
} __packed;
struct rx_vht_vect
{
u8 sounding : 1;
u8 beamformed : 1;
u8 short_gi : 1;
u8 rsvd_vht1 : 1;
u8 stbc : 1;
u8 doze_not_allowed : 1;
u8 first_user : 1;
u8 rsvd_vht2 : 1;
u16 partial_aid : 9;
u16 group_id : 6;
u16 rsvd_vht3 : 1;
u32 mcs : 4;
u32 nss : 3;
u32 fec : 1;
u32 length :20;
u32 rsvd_vht4 : 4;
} __packed;
struct rx_he_vect
{
u8 sounding : 1;
u8 beamformed : 1;
u8 gi_type : 2;
u8 stbc : 1;
u8 rsvd_he1 : 3;
u8 uplink_flag : 1;
u8 beam_change : 1;
u8 dcm : 1;
u8 he_ltf_type : 2;
u8 doppler : 1;
u8 rsvd_he2 : 2;
u8 bss_color : 6;
u8 rsvd_he3 : 2;
u8 txop_duration : 7;
u8 rsvd_he4 : 1;
u8 pe_duration : 4;
u8 spatial_reuse : 4;
u8 sig_b_comp_mode : 1;
u8 dcm_sig_b : 1;
u8 mcs_sig_b : 3;
u8 ru_size : 3;
u32 mcs : 4;
u32 nss : 3;
u32 fec : 1;
u32 length :20;
u32 rsvd_he6 : 4;
} __packed;
struct rx_vector_1 {
u8 format_mod : 4;
u8 ch_bw : 3;
u8 pre_type : 1;
u8 antenna_set : 8;
s32 rssi_leg : 8;
u32 leg_length :12;
u32 leg_rate : 4;
s32 rssi1 : 8;
union
{
struct rx_leg_vect leg;
struct rx_ht_vect ht;
struct rx_vht_vect vht;
struct rx_he_vect he;
};
} __packed;
struct rx_vector_2_old {
/** Receive Vector 2a */
u32 rcpi : 8;
u32 evm1 : 8;
u32 evm2 : 8;
u32 evm3 : 8;
/** Receive Vector 2b */
u32 evm4 : 8;
u32 reserved2b_1 : 8;
u32 reserved2b_2 : 8;
u32 reserved2b_3 : 8;
};
struct rx_vector_2 {
/** Receive Vector 2a */
u32 rcpi1 : 8;
u32 rcpi2 : 8;
u32 rcpi3 : 8;
u32 rcpi4 : 8;
/** Receive Vector 2b */
u32 evm1 : 8;
u32 evm2 : 8;
u32 evm3 : 8;
u32 evm4 : 8;
};
struct phy_channel_info_desc {
/** PHY channel information 1 */
u32 phy_band : 8;
u32 phy_channel_type : 8;
u32 phy_prim20_freq : 16;
/** PHY channel information 2 */
u32 phy_center1_freq : 16;
u32 phy_center2_freq : 16;
};
struct hw_vect {
/** Total length for the MPDU transfer */
u32 len :16;
u32 reserved : 8;//data type is included
/** AMPDU Status Information */
u32 mpdu_cnt : 6;
u32 ampdu_cnt : 2;
/** TSF Low */
__le32 tsf_lo;
/** TSF High */
__le32 tsf_hi;
/** Receive Vector 1 */
struct rx_vector_1 rx_vect1;
/** Receive Vector 2 */
struct rx_vector_2 rx_vect2;
/** Status **/
u32 rx_vect2_valid : 1;
u32 resp_frame : 1;
/** Decryption Status */
u32 decr_status : 3;
u32 rx_fifo_oflow : 1;
/** Frame Unsuccessful */
u32 undef_err : 1;
u32 phy_err : 1;
u32 fcs_err : 1;
u32 addr_mismatch : 1;
u32 ga_frame : 1;
u32 current_ac : 2;
u32 frm_successful_rx : 1;
/** Descriptor Done */
u32 desc_done_rx : 1;
/** Key Storage RAM Index */
u32 key_sram_index : 10;
/** Key Storage RAM Index Valid */
u32 key_sram_v : 1;
u32 type : 2;
u32 subtype : 4;
};
//#ifdef CONFIG_RWNX_MON_DATA
#if 0
/// MAC header backup descriptor
struct mon_machdrdesc
{
/// Length of the buffer
u32 buf_len;
/// Buffer containing mac header, LLC and SNAP
u8 buffer[RX_MACHDR_BACKUP_LEN];
};
#endif
struct hw_rxhdr {
/** RX vector */
struct hw_vect hwvect;
/** PHY channel information */
struct phy_channel_info_desc phy_info;
/** RX flags */
u32 flags_is_amsdu : 1;
u32 flags_is_80211_mpdu: 1;
u32 flags_is_4addr : 1;
u32 flags_new_peer : 1;
#if defined(AICWF_SDIO_SUPPORT) || defined(AICWF_USB_SUPPORT)
u32 flags_user_prio : 1; // aic: fw not fill any more
u32 flags_need_reord : 1;
u32 flags_upload : 1;
#else
u32 flags_user_prio : 3;
#endif
#ifndef AICWF_RX_REORDER
u32 flags_rsvd0 : 1;
#else
u32 is_monitor_vif : 1;
#endif
u32 flags_vif_idx : 8; // 0xFF if invalid VIF index
u32 flags_sta_idx : 8; // 0xFF if invalid STA index
u32 flags_dst_idx : 8; // 0xFF if unknown destination STA
//#ifdef CONFIG_RWNX_MON_DATA
#if 0
/// MAC header backup descriptor (used only for MSDU when there is a monitor and a data interface)
struct mon_machdrdesc mac_hdr_backup;
#endif
/** Pattern indicating if the buffer is available for the driver */
u32 pattern;
};
struct rwnx_legrate {
int idx;
int rate;
};
extern struct rwnx_legrate legrates_lut[];
extern u16 tx_legrates_lut_rate[];
struct DHCPInfo {
u8 op;
u8 htype;
u8 hlen;
u8 hops;
u32 xid;
u16 secs;
u16 flags;
u32 ciaddr;
u32 yiaddr;
u32 siaddr;
u32 giaddr;
u8 chaddr[16];
u8 sname[64];
u8 file[128];
u32 cookie;
u8 options[308]; /* 312 - cookie */
};
u8 rwnx_unsup_rx_vec_ind(void *pthis, void *hostid);
u8 rwnx_rxdataind(void *pthis, void *hostid);
u8 rwnx_rxdataind_aicwf(struct rwnx_hw *rwnx_hw, void *hostid, void *rx_priv);
int aicwf_process_rxframes(struct aicwf_rx_priv *rx_priv);
#ifdef CONFIG_USB_MSG_IN_EP
int aicwf_process_msg_rxframes(struct aicwf_rx_priv *rx_priv);
#endif
#ifdef AICWF_ARP_OFFLOAD
void arpoffload_proc(struct sk_buff *skb, struct rwnx_vif *rwnx_vif);
#endif
#ifdef AICWF_RX_REORDER
struct recv_msdu *reord_rxframe_alloc(spinlock_t *lock, struct list_head *q);
void reord_rxframe_free(spinlock_t *lock, struct list_head *q, struct list_head *list);
struct reord_ctrl_info *reord_init_sta( struct aicwf_rx_priv *rx_priv, const u8 *mac_addr);
void reord_deinit_sta(struct aicwf_rx_priv *rx_priv, struct reord_ctrl_info *reord_info);
int reord_need_check(struct reord_ctrl *preorder_ctrl, u16 seq_num);
int reord_rxframe_enqueue(struct reord_ctrl *preorder_ctrl, struct recv_msdu *prframe);
void reord_timeout_worker(struct work_struct *work);
int reord_single_frame_ind(struct aicwf_rx_priv *rx_priv, struct recv_msdu *prframe);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)
void reord_timeout_handler (ulong data);
#else
void reord_timeout_handler (struct timer_list *t);
#endif
#endif
void rwnx_rxdata_process_amsdu(struct rwnx_hw *rwnx_hw, struct sk_buff *skb, u8 vif_idx,
struct sk_buff_head *list);
#ifdef CONFIG_HE_FOR_OLD_KERNEL
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 197)
struct element {
u8 id;
u8 datalen;
u8 data[];
};
/* element iteration helpers */
#define for_each_element(_elem, _data, _datalen) \
for (_elem = (const struct element *)(_data); \
(const u8 *)(_data) + (_datalen) - (const u8 *)_elem >= \
(int)sizeof(*_elem) && \
(const u8 *)(_data) + (_datalen) - (const u8 *)_elem >= \
(int)sizeof(*_elem) + _elem->datalen; \
_elem = (const struct element *)(_elem->data + _elem->datalen))
#define for_each_element_id(element, _id, data, datalen) \
for_each_element(element, data, datalen) \
if (element->id == (_id))
#endif
#endif
#endif /* _RWNX_RX_H_ */

View file

@ -0,0 +1,269 @@
/**
******************************************************************************
*
* @file rwnx_strs.c
*
* @brief Miscellaneous debug strings
*
* Copyright (C) RivieraWaves 2014-2019
*
******************************************************************************
*/
#include "lmac_msg.h"
static const char *const rwnx_mmid2str[MSG_I(MM_MAX)] = {
[MSG_I(MM_RESET_REQ)] = "MM_RESET_REQ",
[MSG_I(MM_RESET_CFM)] = "MM_RESET_CFM",
[MSG_I(MM_START_REQ)] = "MM_START_REQ",
[MSG_I(MM_START_CFM)] = "MM_START_CFM",
[MSG_I(MM_VERSION_REQ)] = "MM_VERSION_REQ",
[MSG_I(MM_VERSION_CFM)] = "MM_VERSION_CFM",
[MSG_I(MM_ADD_IF_REQ)] = "MM_ADD_IF_REQ",
[MSG_I(MM_ADD_IF_CFM)] = "MM_ADD_IF_CFM",
[MSG_I(MM_REMOVE_IF_REQ)] = "MM_REMOVE_IF_REQ",
[MSG_I(MM_REMOVE_IF_CFM)] = "MM_REMOVE_IF_CFM",
[MSG_I(MM_STA_ADD_REQ)] = "MM_STA_ADD_REQ",
[MSG_I(MM_STA_ADD_CFM)] = "MM_STA_ADD_CFM",
[MSG_I(MM_STA_DEL_REQ)] = "MM_STA_DEL_REQ",
[MSG_I(MM_STA_DEL_CFM)] = "MM_STA_DEL_CFM",
[MSG_I(MM_SET_FILTER_REQ)] = "MM_SET_FILTER_REQ",
[MSG_I(MM_SET_FILTER_CFM)] = "MM_SET_FILTER_CFM",
[MSG_I(MM_SET_CHANNEL_REQ)] = "MM_SET_CHANNEL_REQ",
[MSG_I(MM_SET_CHANNEL_CFM)] = "MM_SET_CHANNEL_CFM",
[MSG_I(MM_SET_DTIM_REQ)] = "MM_SET_DTIM_REQ",
[MSG_I(MM_SET_DTIM_CFM)] = "MM_SET_DTIM_CFM",
[MSG_I(MM_SET_BEACON_INT_REQ)] = "MM_SET_BEACON_INT_REQ",
[MSG_I(MM_SET_BEACON_INT_CFM)] = "MM_SET_BEACON_INT_CFM",
[MSG_I(MM_SET_BASIC_RATES_REQ)] = "MM_SET_BASIC_RATES_REQ",
[MSG_I(MM_SET_BASIC_RATES_CFM)] = "MM_SET_BASIC_RATES_CFM",
[MSG_I(MM_SET_BSSID_REQ)] = "MM_SET_BSSID_REQ",
[MSG_I(MM_SET_BSSID_CFM)] = "MM_SET_BSSID_CFM",
[MSG_I(MM_SET_EDCA_REQ)] = "MM_SET_EDCA_REQ",
[MSG_I(MM_SET_EDCA_CFM)] = "MM_SET_EDCA_CFM",
[MSG_I(MM_SET_MODE_REQ)] = "MM_SET_MODE_REQ",
[MSG_I(MM_SET_MODE_CFM)] = "MM_SET_MODE_CFM",
[MSG_I(MM_SET_VIF_STATE_REQ)] = "MM_SET_VIF_STATE_REQ",
[MSG_I(MM_SET_VIF_STATE_CFM)] = "MM_SET_VIF_STATE_CFM",
[MSG_I(MM_SET_SLOTTIME_REQ)] = "MM_SET_SLOTTIME_REQ",
[MSG_I(MM_SET_SLOTTIME_CFM)] = "MM_SET_SLOTTIME_CFM",
[MSG_I(MM_SET_IDLE_REQ)] = "MM_SET_IDLE_REQ",
[MSG_I(MM_SET_IDLE_CFM)] = "MM_SET_IDLE_CFM",
[MSG_I(MM_KEY_ADD_REQ)] = "MM_KEY_ADD_REQ",
[MSG_I(MM_KEY_ADD_CFM)] = "MM_KEY_ADD_CFM",
[MSG_I(MM_KEY_DEL_REQ)] = "MM_KEY_DEL_REQ",
[MSG_I(MM_KEY_DEL_CFM)] = "MM_KEY_DEL_CFM",
[MSG_I(MM_BA_ADD_REQ)] = "MM_BA_ADD_REQ",
[MSG_I(MM_BA_ADD_CFM)] = "MM_BA_ADD_CFM",
[MSG_I(MM_BA_DEL_REQ)] = "MM_BA_DEL_REQ",
[MSG_I(MM_BA_DEL_CFM)] = "MM_BA_DEL_CFM",
[MSG_I(MM_PRIMARY_TBTT_IND)] = "MM_PRIMARY_TBTT_IND",
[MSG_I(MM_SECONDARY_TBTT_IND)] = "MM_SECONDARY_TBTT_IND",
[MSG_I(MM_SET_POWER_REQ)] = "MM_SET_POWER_REQ",
[MSG_I(MM_SET_POWER_CFM)] = "MM_SET_POWER_CFM",
[MSG_I(MM_DBG_TRIGGER_REQ)] = "MM_DBG_TRIGGER_REQ",
[MSG_I(MM_SET_PS_MODE_REQ)] = "MM_SET_PS_MODE_REQ",
[MSG_I(MM_SET_PS_MODE_CFM)] = "MM_SET_PS_MODE_CFM",
[MSG_I(MM_CHAN_CTXT_ADD_REQ)] = "MM_CHAN_CTXT_ADD_REQ",
[MSG_I(MM_CHAN_CTXT_ADD_CFM)] = "MM_CHAN_CTXT_ADD_CFM",
[MSG_I(MM_CHAN_CTXT_DEL_REQ)] = "MM_CHAN_CTXT_DEL_REQ",
[MSG_I(MM_CHAN_CTXT_DEL_CFM)] = "MM_CHAN_CTXT_DEL_CFM",
[MSG_I(MM_CHAN_CTXT_LINK_REQ)] = "MM_CHAN_CTXT_LINK_REQ",
[MSG_I(MM_CHAN_CTXT_LINK_CFM)] = "MM_CHAN_CTXT_LINK_CFM",
[MSG_I(MM_CHAN_CTXT_UNLINK_REQ)] = "MM_CHAN_CTXT_UNLINK_REQ",
[MSG_I(MM_CHAN_CTXT_UNLINK_CFM)] = "MM_CHAN_CTXT_UNLINK_CFM",
[MSG_I(MM_CHAN_CTXT_UPDATE_REQ)] = "MM_CHAN_CTXT_UPDATE_REQ",
[MSG_I(MM_CHAN_CTXT_UPDATE_CFM)] = "MM_CHAN_CTXT_UPDATE_CFM",
[MSG_I(MM_CHAN_CTXT_SCHED_REQ)] = "MM_CHAN_CTXT_SCHED_REQ",
[MSG_I(MM_CHAN_CTXT_SCHED_CFM)] = "MM_CHAN_CTXT_SCHED_CFM",
[MSG_I(MM_BCN_CHANGE_REQ)] = "MM_BCN_CHANGE_REQ",
[MSG_I(MM_BCN_CHANGE_CFM)] = "MM_BCN_CHANGE_CFM",
[MSG_I(MM_TIM_UPDATE_REQ)] = "MM_TIM_UPDATE_REQ",
[MSG_I(MM_TIM_UPDATE_CFM)] = "MM_TIM_UPDATE_CFM",
[MSG_I(MM_CONNECTION_LOSS_IND)] = "MM_CONNECTION_LOSS_IND",
[MSG_I(MM_CHANNEL_SWITCH_IND)] = "MM_CHANNEL_SWITCH_IND",
[MSG_I(MM_CHANNEL_PRE_SWITCH_IND)] = "MM_CHANNEL_PRE_SWITCH_IND",
[MSG_I(MM_REMAIN_ON_CHANNEL_REQ)] = "MM_REMAIN_ON_CHANNEL_REQ",
[MSG_I(MM_REMAIN_ON_CHANNEL_CFM)] = "MM_REMAIN_ON_CHANNEL_CFM",
[MSG_I(MM_REMAIN_ON_CHANNEL_EXP_IND)] = "MM_REMAIN_ON_CHANNEL_EXP_IND",
[MSG_I(MM_PS_CHANGE_IND)] = "MM_PS_CHANGE_IND",
[MSG_I(MM_TRAFFIC_REQ_IND)] = "MM_TRAFFIC_REQ_IND",
[MSG_I(MM_SET_PS_OPTIONS_REQ)] = "MM_SET_PS_OPTIONS_REQ",
[MSG_I(MM_SET_PS_OPTIONS_CFM)] = "MM_SET_PS_OPTIONS_CFM",
[MSG_I(MM_P2P_VIF_PS_CHANGE_IND)] = "MM_P2P_VIF_PS_CHANGE_IND",
[MSG_I(MM_CSA_COUNTER_IND)] = "MM_CSA_COUNTER_IND",
[MSG_I(MM_CHANNEL_SURVEY_IND)] = "MM_CHANNEL_SURVEY_IND",
[MSG_I(MM_SET_P2P_NOA_REQ)] = "MM_SET_P2P_NOA_REQ",
[MSG_I(MM_SET_P2P_OPPPS_REQ)] = "MM_SET_P2P_OPPPS_REQ",
[MSG_I(MM_SET_P2P_NOA_CFM)] = "MM_SET_P2P_NOA_CFM",
[MSG_I(MM_SET_P2P_OPPPS_CFM)] = "MM_SET_P2P_OPPPS_CFM",
[MSG_I(MM_CFG_RSSI_REQ)] = "MM_CFG_RSSI_REQ",
[MSG_I(MM_RSSI_STATUS_IND)] = "MM_RSSI_STATUS_IND",
[MSG_I(MM_CSA_FINISH_IND)] = "MM_CSA_FINISH_IND",
[MSG_I(MM_CSA_TRAFFIC_IND)] = "MM_CSA_TRAFFIC_IND",
[MSG_I(MM_MU_GROUP_UPDATE_REQ)] = "MM_MU_GROUP_UPDATE_REQ",
[MSG_I(MM_MU_GROUP_UPDATE_CFM)] = "MM_MU_GROUP_UPDATE_CFM",
[MSG_I(MM_SET_ARPOFFLOAD_REQ)] = "MM_SET_ARPOFFLOAD_REQ",
[MSG_I(MM_SET_ARPOFFLOAD_CFM)] = "MM_SET_ARPOFFLOAD_CFM",
[MSG_I(MM_SET_AGG_DISABLE_REQ)] = "MM_SET_AGG_DISABLE_REQ",
[MSG_I(MM_SET_AGG_DISABLE_CFM)] = "MM_SET_AGG_DISABLE_CFM",
[MSG_I(MM_SET_COEX_REQ)] = "MM_SET_COEX_REQ",
[MSG_I(MM_SET_COEX_CFM)] = "MM_SET_COEX_CFM",
[MSG_I(MM_SET_RF_CONFIG_REQ)] = "MM_SET_RF_CONFIG_REQ",
[MSG_I(MM_SET_RF_CONFIG_CFM)] = "MM_SET_RF_CONFIG_CFM",
[MSG_I(MM_SET_RF_CALIB_REQ)] = "MM_SET_RF_CALIB_REQ",
[MSG_I(MM_SET_RF_CALIB_CFM)] = "MM_SET_RF_CALIB_CFM",
[MSG_I(MM_GET_MAC_ADDR_REQ)] = "MM_GET_MAC_ADDR_REQ",
[MSG_I(MM_GET_MAC_ADDR_CFM)] = "MM_GET_MAC_ADDR_CFM",
[MSG_I(MM_GET_STA_INFO_REQ)] = "MM_GET_STA_INFO_REQ",
[MSG_I(MM_GET_STA_INFO_CFM)] = "MM_GET_STA_INFO_CFM",
[MSG_I(MM_SET_TXPWR_IDX_LVL_REQ)] = "MM_SET_TXPWR_IDX_LVL_REQ",
[MSG_I(MM_SET_TXPWR_IDX_LVL_CFM)] = "MM_SET_TXPWR_IDX_LVL_CFM",
[MSG_I(MM_SET_TXPWR_OFST_REQ)] = "MM_SET_TXPWR_OFST_REQ",
[MSG_I(MM_SET_TXPWR_OFST_CFM)] = "MM_SET_TXPWR_OFST_CFM",
[MSG_I(MM_SET_STACK_START_REQ)] = "MM_SET_STACK_START_REQ",
[MSG_I(MM_SET_STACK_START_CFM)] = "MM_SET_STACK_START_CFM",
[MSG_I(MM_APM_STALOSS_IND)] = "MM_APM_STALOSS_IND",
[MSG_I(MM_SET_VENDOR_HWCONFIG_REQ)] = "MM_SET_VENDOR_HWCONFIG_REQ",
[MSG_I(MM_SET_VENDOR_HWCONFIG_CFM)] = "MM_SET_VENDOR_HWCONFIG_CFM",
[MSG_I(MM_GET_FW_VERSION_REQ)] = "MM_GET_FW_VERSION_REQ",
[MSG_I(MM_GET_FW_VERSION_CFM)] = "MM_GET_FW_VERSION_CFM",
[MSG_I(MM_SET_RESUME_RESTORE_REQ)] = "MM_SET_RESUME_RESTORE_REQ",
[MSG_I(MM_SET_RESUME_RESTORE_CFM)] = "MM_SET_RESUME_RESTORE_CFM",
[MSG_I(MM_GET_WIFI_DISABLE_REQ)] = "MM_GET_WIFI_DISABLE_REQ",
[MSG_I(MM_GET_WIFI_DISABLE_CFM)] = "MM_GET_WIFI_DISABLE_CFM",
[MSG_I(MM_CFG_RSSI_CFM)] = "MM_CFG_RSSI_CFM",
[MSG_I(MM_SET_TXPWR_PER_STA_REQ)] = "MM_SET_TXPWR_PER_STA_REQ",
[MSG_I(MM_SET_TXPWR_PER_STA_CFM)] = "MM_SET_TXPWR_PER_STA_CFM",
};
static const char *const rwnx_dbgid2str[MSG_I(DBG_MAX)] = {
[MSG_I(DBG_MEM_READ_REQ)] = "DBG_MEM_READ_REQ",
[MSG_I(DBG_MEM_READ_CFM)] = "DBG_MEM_READ_CFM",
[MSG_I(DBG_MEM_WRITE_REQ)] = "DBG_MEM_WRITE_REQ",
[MSG_I(DBG_MEM_WRITE_CFM)] = "DBG_MEM_WRITE_CFM",
[MSG_I(DBG_SET_MOD_FILTER_REQ)] = "DBG_SET_MOD_FILTER_REQ",
[MSG_I(DBG_SET_MOD_FILTER_CFM)] = "DBG_SET_MOD_FILTER_CFM",
[MSG_I(DBG_SET_SEV_FILTER_REQ)] = "DBG_SET_SEV_FILTER_REQ",
[MSG_I(DBG_SET_SEV_FILTER_CFM)] = "DBG_SET_SEV_FILTER_CFM",
[MSG_I(DBG_ERROR_IND)] = "DBG_ERROR_IND",
[MSG_I(DBG_GET_SYS_STAT_REQ)] = "DBG_GET_SYS_STAT_REQ",
[MSG_I(DBG_GET_SYS_STAT_CFM)] = "DBG_GET_SYS_STAT_CFM",
};
static const char *const rwnx_scanid2str[MSG_I(SCAN_MAX)] = {
[MSG_I(SCAN_START_REQ)] = "SCAN_START_REQ",
[MSG_I(SCAN_START_CFM)] = "SCAN_START_CFM",
[MSG_I(SCAN_DONE_IND)] = "SCAN_DONE_IND",
};
static const char *const rwnx_tdlsid2str[MSG_I(TDLS_MAX)] = {
[MSG_I(TDLS_CHAN_SWITCH_CFM)] = "TDLS_CHAN_SWITCH_CFM",
[MSG_I(TDLS_CHAN_SWITCH_REQ)] = "TDLS_CHAN_SWITCH_REQ",
[MSG_I(TDLS_CHAN_SWITCH_IND)] = "TDLS_CHAN_SWITCH_IND",
[MSG_I(TDLS_CHAN_SWITCH_BASE_IND)] = "TDLS_CHAN_SWITCH_BASE_IND",
[MSG_I(TDLS_CANCEL_CHAN_SWITCH_REQ)] = "TDLS_CANCEL_CHAN_SWITCH_REQ",
[MSG_I(TDLS_CANCEL_CHAN_SWITCH_CFM)] = "TDLS_CANCEL_CHAN_SWITCH_CFM",
[MSG_I(TDLS_PEER_PS_IND)] = "TDLS_PEER_PS_IND",
[MSG_I(TDLS_PEER_TRAFFIC_IND_REQ)] = "TDLS_PEER_TRAFFIC_IND_REQ",
[MSG_I(TDLS_PEER_TRAFFIC_IND_CFM)] = "TDLS_PEER_TRAFFIC_IND_CFM",
};
#ifdef CONFIG_RWNX_FULLMAC
static const char *const rwnx_scanuid2str[MSG_I(SCANU_MAX)] = {
[MSG_I(SCANU_START_REQ)] = "SCANU_START_REQ",
[MSG_I(SCANU_START_CFM)] = "SCANU_START_CFM",
[MSG_I(SCANU_JOIN_REQ)] = "SCANU_JOIN_REQ",
[MSG_I(SCANU_JOIN_CFM)] = "SCANU_JOIN_CFM",
[MSG_I(SCANU_RESULT_IND)] = "SCANU_RESULT_IND",
[MSG_I(SCANU_FAST_REQ)] = "SCANU_FAST_REQ",
[MSG_I(SCANU_FAST_CFM)] = "SCANU_FAST_CFM",
[MSG_I(SCANU_VENDOR_IE_REQ)] = "SCANU_VENDOR_IE_REQ",
[MSG_I(SCANU_VENDOR_IE_CFM)] = "SCANU_VENDOR_IE_CFM",
[MSG_I(SCANU_START_CFM_ADDTIONAL)] = "SCANU_START_CFM_ADDTIONAL",
[MSG_I(SCANU_CANCEL_REQ)] = "SCANU_CANCEL_REQ",
[MSG_I(SCANU_CANCEL_CFM)] = "SCANU_CANCEL_CFM",
};
static const char *const rwnx_meid2str[MSG_I(ME_MAX)] = {
[MSG_I(ME_CONFIG_REQ)] = "ME_CONFIG_REQ",
[MSG_I(ME_CONFIG_CFM)] = "ME_CONFIG_CFM",
[MSG_I(ME_CHAN_CONFIG_REQ)] = "ME_CHAN_CONFIG_REQ",
[MSG_I(ME_CHAN_CONFIG_CFM)] = "ME_CHAN_CONFIG_CFM",
[MSG_I(ME_SET_CONTROL_PORT_REQ)] = "ME_SET_CONTROL_PORT_REQ",
[MSG_I(ME_SET_CONTROL_PORT_CFM)] = "ME_SET_CONTROL_PORT_CFM",
[MSG_I(ME_TKIP_MIC_FAILURE_IND)] = "ME_TKIP_MIC_FAILURE_IND",
[MSG_I(ME_STA_ADD_REQ)] = "ME_STA_ADD_REQ",
[MSG_I(ME_STA_ADD_CFM)] = "ME_STA_ADD_CFM",
[MSG_I(ME_STA_DEL_REQ)] = "ME_STA_DEL_REQ",
[MSG_I(ME_STA_DEL_CFM)] = "ME_STA_DEL_CFM",
[MSG_I(ME_TX_CREDITS_UPDATE_IND)]= "ME_TX_CREDITS_UPDATE_IND",
[MSG_I(ME_RC_STATS_REQ)] = "ME_RC_STATS_REQ",
[MSG_I(ME_RC_STATS_CFM)] = "ME_RC_STATS_CFM",
[MSG_I(ME_RC_SET_RATE_REQ)] = "ME_RC_SET_RATE_REQ",
[MSG_I(ME_TRAFFIC_IND_REQ)] = "ME_TRAFFIC_IND_REQ",
[MSG_I(ME_TRAFFIC_IND_CFM)] = "ME_TRAFFIC_IND_CFM",
[MSG_I(ME_SET_PS_MODE_REQ)] = "ME_SET_PS_MODE_REQ",
[MSG_I(ME_SET_PS_MODE_CFM)] = "ME_SET_PS_MODE_CFM",
};
static const char *const rwnx_smid2str[MSG_I(SM_MAX)] = {
[MSG_I(SM_CONNECT_REQ)] = "SM_CONNECT_REQ",
[MSG_I(SM_CONNECT_CFM)] = "SM_CONNECT_CFM",
[MSG_I(SM_CONNECT_IND)] = "SM_CONNECT_IND",
[MSG_I(SM_DISCONNECT_REQ)] = "SM_DISCONNECT_REQ",
[MSG_I(SM_DISCONNECT_CFM)] = "SM_DISCONNECT_CFM",
[MSG_I(SM_DISCONNECT_IND)] = "SM_DISCONNECT_IND",
[MSG_I(SM_EXTERNAL_AUTH_REQUIRED_IND)] = "SM_EXTERNAL_AUTH_REQUIRED_IND",
[MSG_I(SM_EXTERNAL_AUTH_REQUIRED_RSP)] = "SM_EXTERNAL_AUTH_REQUIRED_RSP",
[MSG_I(SM_EXTERNAL_AUTH_REQUIRED_RSP_CFM)] = "SM_EXTERNAL_AUTH_REQUIRED_RSP_CFM",
};
static const char *const rwnx_apmid2str[MSG_I(APM_MAX)] = {
[MSG_I(APM_START_REQ)] = "APM_START_REQ",
[MSG_I(APM_START_CFM)] = "APM_START_CFM",
[MSG_I(APM_STOP_REQ)] = "APM_STOP_REQ",
[MSG_I(APM_STOP_CFM)] = "APM_STOP_CFM",
[MSG_I(APM_START_CAC_REQ)] = "APM_START_CAC_REQ",
[MSG_I(APM_START_CAC_CFM)] = "APM_START_CAC_CFM",
[MSG_I(APM_STOP_CAC_REQ)] = "APM_STOP_CAC_REQ",
[MSG_I(APM_STOP_CAC_CFM)] = "APM_STOP_CAC_CFM",
[MSG_I(APM_SET_BEACON_IE_REQ)] = "APM_SET_BEACON_IE_REQ",
[MSG_I(APM_SET_BEACON_IE_CFM)] = "APM_SET_BEACON_IE_CFM",
};
static const char *const rwnx_meshid2str[MSG_I(MESH_MAX)] = {
[MSG_I(MESH_START_REQ)] = "MESH_START_REQ",
[MSG_I(MESH_START_CFM)] = "MESH_START_CFM",
[MSG_I(MESH_STOP_REQ)] = "MESH_STOP_REQ",
[MSG_I(MESH_STOP_CFM)] = "MESH_STOP_CFM",
[MSG_I(MESH_UPDATE_REQ)] = "MESH_UPDATE_REQ",
[MSG_I(MESH_UPDATE_CFM)] = "MESH_UPDATE_CFM",
[MSG_I(MESH_PATH_CREATE_REQ)] = "MESH_PATH_CREATE_REQ",
[MSG_I(MESH_PATH_CREATE_CFM)] = "MESH_PATH_CREATE_CFM",
[MSG_I(MESH_PATH_UPDATE_REQ)] = "MESH_PATH_UPDATE_REQ",
[MSG_I(MESH_PATH_UPDATE_CFM)] = "MESH_PATH_UPDATE_CFM",
[MSG_I(MESH_PROXY_ADD_REQ)] = "MESH_PROXY_ADD_REQ",
[MSG_I(MESH_PEER_UPDATE_IND)] = "MESH_PEER_UPDATE_IND",
[MSG_I(MESH_PATH_UPDATE_IND)] = "MESH_PATH_UPDATE_IND",
[MSG_I(MESH_PROXY_UPDATE_IND)] = "MESH_PROXY_UPDATE_IND",
};
#endif /* CONFIG_RWNX_FULLMAC */
const char *const *rwnx_id2str[TASK_LAST_EMB + 1] = {
[TASK_MM] = rwnx_mmid2str,
[TASK_DBG] = rwnx_dbgid2str,
[TASK_SCAN] = rwnx_scanid2str,
[TASK_TDLS] = rwnx_tdlsid2str,
#ifdef CONFIG_RWNX_FULLMAC
[TASK_SCANU] = rwnx_scanuid2str,
[TASK_ME] = rwnx_meid2str,
[TASK_SM] = rwnx_smid2str,
[TASK_APM] = rwnx_apmid2str,
[TASK_MESH] = rwnx_meshid2str,
#endif
};

View file

@ -0,0 +1,31 @@
/**
****************************************************************************************
*
* @file rwnx_strs.h
*
* @brief Miscellaneous debug strings
*
* Copyright (C) RivieraWaves 2014-2019
*
****************************************************************************************
*/
#ifndef _RWNX_STRS_H_
#define _RWNX_STRS_H_
#ifdef CONFIG_RWNX_FHOST
#define RWNX_ID2STR(tag) "Cmd"
#else
#include "lmac_msg.h"
#define RWNX_ID2STR(tag) (((MSG_T(tag) < ARRAY_SIZE(rwnx_id2str)) && \
(rwnx_id2str[MSG_T(tag)]) && \
((rwnx_id2str[MSG_T(tag)])[MSG_I(tag)])) ? \
(rwnx_id2str[MSG_T(tag)])[MSG_I(tag)] : "unknown")
extern const char *const *rwnx_id2str[TASK_LAST_EMB + 1];
#endif /* CONFIG_RWNX_FHOST */
#endif /* _RWNX_STRS_H_ */

View file

@ -0,0 +1,796 @@
/**
******************************************************************************
*
* @file rwnx_tx.c
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
/**
* INCLUDE FILES
******************************************************************************
*/
#include "rwnx_tdls.h"
#include "rwnx_compat.h"
/**
* FUNCTION DEFINITIONS
******************************************************************************
*/
static u16
rwnx_get_tdls_sta_capab(struct rwnx_vif *rwnx_vif, u16 status_code)
{
u16 capab = 0;
/* The capability will be 0 when sending a failure code */
if (status_code != 0)
return capab;
if (rwnx_vif->sta.ap->band != NL80211_BAND_2GHZ)
return capab;
capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
return capab;
}
static int
rwnx_tdls_prepare_encap_data(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
const u8 *peer, u8 action_code, u8 dialog_token,
u16 status_code, struct sk_buff *skb)
{
struct ieee80211_tdls_data *tf;
tf = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_data) - sizeof(tf->u));
// set eth header
memcpy(tf->da, peer, ETH_ALEN);
memcpy(tf->sa, rwnx_hw->wiphy->perm_addr, ETH_ALEN);
tf->ether_type = cpu_to_be16(ETH_P_TDLS);
// set common TDLS info
tf->payload_type = WLAN_TDLS_SNAP_RFTYPE;
tf->category = WLAN_CATEGORY_TDLS;
tf->action_code = action_code;
// set action specific TDLS info
switch (action_code) {
case WLAN_TDLS_SETUP_REQUEST:
skb_put(skb, sizeof(tf->u.setup_req));
tf->u.setup_req.dialog_token = dialog_token;
tf->u.setup_req.capability =
cpu_to_le16(rwnx_get_tdls_sta_capab(rwnx_vif, status_code));
break;
case WLAN_TDLS_SETUP_RESPONSE:
skb_put(skb, sizeof(tf->u.setup_resp));
tf->u.setup_resp.status_code = cpu_to_le16(status_code);
tf->u.setup_resp.dialog_token = dialog_token;
tf->u.setup_resp.capability =
cpu_to_le16(rwnx_get_tdls_sta_capab(rwnx_vif, status_code));
break;
case WLAN_TDLS_SETUP_CONFIRM:
skb_put(skb, sizeof(tf->u.setup_cfm));
tf->u.setup_cfm.status_code = cpu_to_le16(status_code);
tf->u.setup_cfm.dialog_token = dialog_token;
break;
case WLAN_TDLS_TEARDOWN:
skb_put(skb, sizeof(tf->u.teardown));
tf->u.teardown.reason_code = cpu_to_le16(status_code);
break;
case WLAN_TDLS_DISCOVERY_REQUEST:
skb_put(skb, sizeof(tf->u.discover_req));
tf->u.discover_req.dialog_token = dialog_token;
break;
default:
return -EINVAL;
}
return 0;
}
static int
rwnx_prep_tdls_direct(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
const u8 *peer, u8 action_code, u8 dialog_token,
u16 status_code, struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt;
mgmt = (void *)skb_put(skb, 24);
memset(mgmt, 0, 24);
memcpy(mgmt->da, peer, ETH_ALEN);
memcpy(mgmt->sa, rwnx_hw->wiphy->perm_addr, ETH_ALEN);
memcpy(mgmt->bssid, rwnx_vif->sta.ap->mac_addr, ETH_ALEN);
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ACTION);
switch (action_code) {
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
mgmt->u.action.u.tdls_discover_resp.action_code = WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
mgmt->u.action.u.tdls_discover_resp.dialog_token = dialog_token;
mgmt->u.action.u.tdls_discover_resp.capability =
cpu_to_le16(rwnx_get_tdls_sta_capab(rwnx_vif, status_code));
break;
default:
return -EINVAL;
}
return 0;
}
static int
rwnx_add_srates_ie(struct rwnx_hw *rwnx_hw, struct sk_buff *skb)
{
u8 i, rates, *pos;
int rate;
struct ieee80211_supported_band *rwnx_band_2GHz = rwnx_hw->wiphy->bands[NL80211_BAND_2GHZ];
rates = 8;
if (skb_tailroom(skb) < rates + 2)
return -ENOMEM;
pos = skb_put(skb, rates + 2);
*pos++ = WLAN_EID_SUPP_RATES;
*pos++ = rates;
for (i = 0; i < rates; i++) {
rate = rwnx_band_2GHz->bitrates[i].bitrate;
rate = DIV_ROUND_UP(rate, 5);
*pos++ = (u8)rate;
}
return 0;
}
static int
rwnx_add_ext_srates_ie(struct rwnx_hw *rwnx_hw, struct sk_buff *skb)
{
u8 i, exrates, *pos;
int rate;
struct ieee80211_supported_band *rwnx_band_2GHz = rwnx_hw->wiphy->bands[NL80211_BAND_2GHZ];
exrates = rwnx_band_2GHz->n_bitrates - 8;
if (skb_tailroom(skb) < exrates + 2)
return -ENOMEM;
pos = skb_put(skb, exrates + 2);
*pos++ = WLAN_EID_EXT_SUPP_RATES;
*pos++ = exrates;
for (i = 8; i < (8+exrates); i++) {
rate = rwnx_band_2GHz->bitrates[i].bitrate;
rate = DIV_ROUND_UP(rate, 5);
*pos++ = (u8)rate;
}
return 0;
}
static void
rwnx_tdls_add_supp_channels(struct rwnx_hw *rwnx_hw, struct sk_buff *skb)
{
/*
* Add possible channels for TDLS. These are channels that are allowed
* to be active.
*/
u8 subband_cnt = 0;
u8 *pos_subband;
u8 *pos = skb_put(skb, 2);
struct ieee80211_supported_band *rwnx_band_2GHz = rwnx_hw->wiphy->bands[NL80211_BAND_2GHZ];
//#ifdef USE_5G
struct ieee80211_supported_band *rwnx_band_5GHz = rwnx_hw->wiphy->bands[NL80211_BAND_5GHZ];
//#endif
*pos++ = WLAN_EID_SUPPORTED_CHANNELS;
/*
* 5GHz and 2GHz channels numbers can overlap. Ignore this for now, as
* this doesn't happen in real world scenarios.
*/
/* 2GHz, with 5MHz spacing */
pos_subband = skb_put(skb, 2);
if (rwnx_band_2GHz->n_channels > 0)
{
*pos_subband++ = ieee80211_frequency_to_channel(rwnx_band_2GHz->channels[0].center_freq);
*pos_subband++ = rwnx_band_2GHz->n_channels;
subband_cnt++;
}
/* 5GHz, with 20MHz spacing */
pos_subband = skb_put(skb, 2);
//#ifdef USE_5G
if(rwnx_hw->band_5g_support){
if (rwnx_band_5GHz->n_channels > 0)
{
*pos_subband++ = ieee80211_frequency_to_channel(rwnx_band_5GHz->channels[0].center_freq);
*pos_subband++ = rwnx_band_5GHz->n_channels;
subband_cnt++;
}
}
//#endif
/* length */
*pos = 2 * subband_cnt;
}
static void
rwnx_tdls_add_ext_capab(struct rwnx_hw *rwnx_hw, struct sk_buff *skb)
{
u8 *pos = (void *)skb_put(skb, 7);
bool chan_switch = rwnx_hw->wiphy->features &
NL80211_FEATURE_TDLS_CHANNEL_SWITCH;
*pos++ = WLAN_EID_EXT_CAPABILITY;
*pos++ = 5; /* len */
*pos++ = 0x0;
*pos++ = 0x0;
*pos++ = 0x0;
*pos++ = WLAN_EXT_CAPA4_TDLS_BUFFER_STA |
(chan_switch ? WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH : 0);
*pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED;
}
static void
rwnx_add_wmm_info_ie(struct sk_buff *skb, u8 qosinfo)
{
u8 *pos = (void *)skb_put(skb, 9);
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
*pos++ = 7; /* len */
*pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
*pos++ = 0x50;
*pos++ = 0xf2;
*pos++ = 2; /* WME */
*pos++ = 0; /* WME info */
*pos++ = 1; /* WME ver */
*pos++ = qosinfo; /* U-APSD no in use */
}
/* translate numbering in the WMM parameter IE to the mac80211 notation */
static u8 rwnx_ac_from_wmm(int ac)
{
switch (ac) {
default:
WARN_ON_ONCE(1);
case 0:
return AC_BE;
case 1:
return AC_BK;
case 2:
return AC_VI;
case 3:
return AC_VO;
}
}
static void
rwnx_add_wmm_param_ie(struct sk_buff *skb, u8 acm_bits, u32 *ac_params)
{
struct ieee80211_wmm_param_ie *wmm;
int i, j;
u8 cw_min, cw_max;
bool acm;
wmm = (void *)skb_put(skb, sizeof(struct ieee80211_wmm_param_ie));
memset(wmm, 0, sizeof(*wmm));
wmm->element_id = WLAN_EID_VENDOR_SPECIFIC;
wmm->len = sizeof(*wmm) - 2;
wmm->oui[0] = 0x00; /* Microsoft OUI 00:50:F2 */
wmm->oui[1] = 0x50;
wmm->oui[2] = 0xf2;
wmm->oui_type = 2; /* WME */
wmm->oui_subtype = 1; /* WME param */
wmm->version = 1; /* WME ver */
wmm->qos_info = 0; /* U-APSD not in use */
/*
* Use the EDCA parameters defined for the BSS, or default if the AP
* doesn't support it, as mandated by 802.11-2012 section 10.22.4
*/
for (i = 0; i < AC_MAX; i++) {
j = rwnx_ac_from_wmm(i);
cw_min = (ac_params[j] & 0xF0 ) >> 4;
cw_max = (ac_params[j] & 0xF00 ) >> 8;
acm = (acm_bits & (1 << j)) != 0;
wmm->ac[i].aci_aifsn = (i << 5) | (acm << 4) | (ac_params[j] & 0xF);
wmm->ac[i].cw = (cw_max << 4) | cw_min;
wmm->ac[i].txop_limit = (ac_params[j] & 0x0FFFF000 ) >> 12;
}
}
static void
rwnx_tdls_add_oper_classes(struct rwnx_vif *rwnx_vif, struct sk_buff *skb)
{
u8 *pos;
u8 op_class;
struct cfg80211_chan_def chan_def;
struct ieee80211_channel chan;
chan.band = rwnx_vif->sta.ap->band;
chan.center_freq = rwnx_vif->sta.ap->center_freq;
chan_def.chan = &chan;
chan_def.width = rwnx_vif->sta.ap->width;
chan_def.center_freq1 = rwnx_vif->sta.ap->center_freq1;
chan_def.center_freq2 = rwnx_vif->sta.ap->center_freq2;
if (!ieee80211_chandef_to_operating_class(&chan_def, &op_class))
return;
pos = skb_put(skb, 4);
*pos++ = WLAN_EID_SUPPORTED_REGULATORY_CLASSES;
*pos++ = 2; /* len */
// current op class
*pos++ = op_class;
*pos++ = op_class; /* give current operating class as alternate too */
// need to add 5GHz classes?
}
static void
rwnx_ie_build_ht_cap(struct sk_buff *skb, struct ieee80211_sta_ht_cap *ht_cap,
u16 cap)
{
u8 *pos;
__le16 tmp;
pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
*pos++ = WLAN_EID_HT_CAPABILITY;
*pos++ = sizeof(struct ieee80211_ht_cap);
memset(pos, 0, sizeof(struct ieee80211_ht_cap));
/* capability flags */
tmp = cpu_to_le16(cap);
memcpy(pos, &tmp, sizeof(u16));
pos += sizeof(u16);
/* AMPDU parameters */
*pos++ = ht_cap->ampdu_factor |
(ht_cap->ampdu_density <<
IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
/* MCS set */
memcpy(pos, &ht_cap->mcs, sizeof(ht_cap->mcs));
pos += sizeof(ht_cap->mcs);
/* extended capabilities */
pos += sizeof(__le16);
/* BF capabilities */
pos += sizeof(__le32);
/* antenna selection */
pos += sizeof(u8);
}
static void
rwnx_ie_build_vht_cap(struct sk_buff *skb, struct ieee80211_sta_vht_cap *vht_cap,
u32 cap)
{
u8 *pos;
__le32 tmp;
pos = skb_put(skb, 14);
*pos++ = WLAN_EID_VHT_CAPABILITY;
*pos++ = sizeof(struct ieee80211_vht_cap);
memset(pos, 0, sizeof(struct ieee80211_vht_cap));
/* capability flags */
tmp = cpu_to_le32(cap);
memcpy(pos, &tmp, sizeof(u32));
pos += sizeof(u32);
/* VHT MCS set */
memcpy(pos, &vht_cap->vht_mcs, sizeof(vht_cap->vht_mcs));
pos += sizeof(vht_cap->vht_mcs);
}
static void
rwnx_tdls_add_bss_coex_ie(struct sk_buff *skb)
{
u8 *pos = (void *)skb_put(skb, 3);
*pos++ = WLAN_EID_BSS_COEX_2040;
*pos++ = 1; /* len */
*pos++ = WLAN_BSS_COEX_INFORMATION_REQUEST;
}
static void
rwnx_tdls_add_link_ie(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
struct sk_buff *skb, const u8 *peer,
bool initiator)
{
struct ieee80211_tdls_lnkie *lnkid;
const u8 *init_addr, *rsp_addr;
if (initiator) {
init_addr = rwnx_hw->wiphy->perm_addr;
rsp_addr = peer;
} else {
init_addr = peer;
rsp_addr = rwnx_hw->wiphy->perm_addr;
}
lnkid = (void *)skb_put(skb, sizeof(struct ieee80211_tdls_lnkie));
lnkid->ie_type = WLAN_EID_LINK_ID;
lnkid->ie_len = sizeof(struct ieee80211_tdls_lnkie) - 2;
memcpy(lnkid->bssid, rwnx_vif->sta.ap->mac_addr, ETH_ALEN);
memcpy(lnkid->init_sta, init_addr, ETH_ALEN);
memcpy(lnkid->resp_sta, rsp_addr, ETH_ALEN);
}
static void
rwnx_tdls_add_aid_ie(struct rwnx_vif *rwnx_vif, struct sk_buff *skb)
{
u8 *pos = (void *)skb_put(skb, 4);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
*pos++ = WLAN_EID_AID;
#else
*pos++ = 197;
#endif
*pos++ = 2; /* len */
*pos++ = rwnx_vif->sta.ap->aid;
}
static u8 *
rwnx_ie_build_ht_oper(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
u16 prot_mode)
{
struct ieee80211_ht_operation *ht_oper;
/* Build HT Information */
*pos++ = WLAN_EID_HT_OPERATION;
*pos++ = sizeof(struct ieee80211_ht_operation);
ht_oper = (struct ieee80211_ht_operation *)pos;
ht_oper->primary_chan = ieee80211_frequency_to_channel(
rwnx_vif->sta.ap->center_freq);
switch (rwnx_vif->sta.ap->width) {
case NL80211_CHAN_WIDTH_160:
case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_80:
case NL80211_CHAN_WIDTH_40:
if (rwnx_vif->sta.ap->center_freq1 > rwnx_vif->sta.ap->center_freq)
ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
else
ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
break;
default:
ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
break;
}
if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
rwnx_vif->sta.ap->width != NL80211_CHAN_WIDTH_20_NOHT &&
rwnx_vif->sta.ap->width != NL80211_CHAN_WIDTH_20)
ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
ht_oper->operation_mode = cpu_to_le16(prot_mode);
ht_oper->stbc_param = 0x0000;
/* It seems that Basic MCS set and Supported MCS set
are identical for the first 10 bytes */
memset(&ht_oper->basic_set, 0, 16);
memcpy(&ht_oper->basic_set, &ht_cap->mcs, 10);
return pos + sizeof(struct ieee80211_ht_operation);
}
static u8 *
rwnx_ie_build_vht_oper(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
u16 prot_mode)
{
struct ieee80211_vht_operation *vht_oper;
/* Build HT Information */
*pos++ = WLAN_EID_VHT_OPERATION;
*pos++ = sizeof(struct ieee80211_vht_operation);
vht_oper = (struct ieee80211_vht_operation *)pos;
switch (rwnx_vif->sta.ap->width) {
case NL80211_CHAN_WIDTH_80:
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ; // Channel Width
CCFS0(vht_oper) =
ieee80211_frequency_to_channel(rwnx_vif->sta.ap->center_freq); // Channel Center Frequency Segment 0
CCFS1(vht_oper) = 0; // Channel Center Frequency Segment 1 (N.A.)
break;
case NL80211_CHAN_WIDTH_160:
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ; // Channel Width
CCFS0(vht_oper) =
ieee80211_frequency_to_channel(rwnx_vif->sta.ap->center_freq); // Channel Center Frequency Segment 0
CCFS1(vht_oper) = 0; // Channel Center Frequency Segment 1 (N.A.)
break;
case NL80211_CHAN_WIDTH_80P80:
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ; // Channel Width
CCFS0(vht_oper) =
ieee80211_frequency_to_channel(rwnx_vif->sta.ap->center_freq1); // Channel Center Frequency Segment 0
CCFS1(vht_oper) =
ieee80211_frequency_to_channel(rwnx_vif->sta.ap->center_freq2); // Channel Center Frequency Segment 1
break;
default:
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT;
CCFS0(vht_oper) = 0;
CCFS1(vht_oper) = 0;
break;
}
vht_oper->basic_mcs_set = cpu_to_le16(rwnx_hw->mod_params->mcs_map);
return pos + sizeof(struct ieee80211_vht_operation);
}
static void
rwnx_tdls_add_setup_start_ies(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
struct sk_buff *skb, const u8 *peer,
u8 action_code, bool initiator,
const u8 *extra_ies, size_t extra_ies_len)
{
enum nl80211_band band = rwnx_vif->sta.ap->band;
struct ieee80211_supported_band *sband;
struct ieee80211_sta_ht_cap ht_cap;
struct ieee80211_sta_vht_cap vht_cap;
size_t offset = 0, noffset;
u8 *pos;
rcu_read_lock();
rwnx_add_srates_ie(rwnx_hw, skb);
rwnx_add_ext_srates_ie(rwnx_hw, skb);
rwnx_tdls_add_supp_channels(rwnx_hw, skb);
rwnx_tdls_add_ext_capab(rwnx_hw, skb);
/* add the QoS element if we support it */
if (/*local->hw.queues >= IEEE80211_NUM_ACS &&*/
action_code != WLAN_PUB_ACTION_TDLS_DISCOVER_RES)
rwnx_add_wmm_info_ie(skb, 0); /* no U-APSD */
rwnx_tdls_add_oper_classes(rwnx_vif, skb);
/*
* with TDLS we can switch channels, and HT-caps are not necessarily
* the same on all bands. The specification limits the setup to a
* single HT-cap, so use the current band for now.
*/
sband = rwnx_hw->wiphy->bands[band];
memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
if (((action_code == WLAN_TDLS_SETUP_REQUEST) ||
(action_code == WLAN_TDLS_SETUP_RESPONSE) ||
(action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES)) &&
ht_cap.ht_supported /* (!sta || sta->sta.ht_cap.ht_supported)*/) {
rwnx_ie_build_ht_cap(skb, &ht_cap, ht_cap.cap);
}
if (ht_cap.ht_supported &&
(ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
rwnx_tdls_add_bss_coex_ie(skb);
rwnx_tdls_add_link_ie(rwnx_hw, rwnx_vif, skb, peer, initiator);
memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap));
if (vht_cap.vht_supported) {
rwnx_tdls_add_aid_ie(rwnx_vif, skb);
rwnx_ie_build_vht_cap(skb, &vht_cap, vht_cap.cap);
// Operating mode Notification (optional)
}
/* add any remaining IEs */
if (extra_ies_len) {
noffset = extra_ies_len;
pos = skb_put(skb, noffset - offset);
memcpy(pos, extra_ies + offset, noffset - offset);
}
rcu_read_unlock();
}
static void
rwnx_tdls_add_setup_cfm_ies(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
struct sk_buff *skb, const u8 *peer, bool initiator,
const u8 *extra_ies, size_t extra_ies_len)
{
struct ieee80211_supported_band *sband;
enum nl80211_band band = rwnx_vif->sta.ap->band;
struct ieee80211_sta_ht_cap ht_cap;
struct ieee80211_sta_vht_cap vht_cap;
size_t offset = 0, noffset;
struct rwnx_sta *sta, *ap_sta;
u8 *pos;
rcu_read_lock();
sta = rwnx_get_sta(rwnx_hw, peer);
ap_sta = rwnx_vif->sta.ap;
if (WARN_ON_ONCE(!sta || !ap_sta)) {
rcu_read_unlock();
return;
}
/* add the QoS param IE if both the peer and we support it */
if (sta->qos)
rwnx_add_wmm_param_ie(skb, ap_sta->acm, ap_sta->ac_param);
/* if HT support is only added in TDLS, we need an HT-operation IE */
sband = rwnx_hw->wiphy->bands[band];
memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap));
if (ht_cap.ht_supported && !ap_sta->ht && sta->ht) {
pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
/* send an empty HT operation IE */
rwnx_ie_build_ht_oper(rwnx_hw, rwnx_vif, pos, &ht_cap, 0);
}
rwnx_tdls_add_link_ie(rwnx_hw, rwnx_vif, skb, peer, initiator);
memcpy(&vht_cap, &sband->vht_cap, sizeof(vht_cap));
if (vht_cap.vht_supported && !ap_sta->vht && sta->vht) {
pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_operation));
rwnx_ie_build_vht_oper(rwnx_hw, rwnx_vif, pos, &ht_cap, 0);
// Operating mode Notification (optional)
}
/* add any remaining IEs */
if (extra_ies_len) {
noffset = extra_ies_len;
pos = skb_put(skb, noffset - offset);
memcpy(pos, extra_ies + offset, noffset - offset);
}
rcu_read_unlock();
}
static void
rwnx_tdls_add_ies(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
struct sk_buff *skb, const u8 *peer,
u8 action_code, u16 status_code,
bool initiator, const u8 *extra_ies,
size_t extra_ies_len, u8 oper_class,
struct cfg80211_chan_def *chandef)
{
switch (action_code) {
case WLAN_TDLS_SETUP_REQUEST:
case WLAN_TDLS_SETUP_RESPONSE:
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
if (status_code == 0)
rwnx_tdls_add_setup_start_ies(rwnx_hw, rwnx_vif, skb, peer, action_code,
initiator, extra_ies, extra_ies_len);
break;
case WLAN_TDLS_SETUP_CONFIRM:
if (status_code == 0)
rwnx_tdls_add_setup_cfm_ies(rwnx_hw, rwnx_vif, skb, peer, initiator,
extra_ies, extra_ies_len);
break;
case WLAN_TDLS_TEARDOWN:
case WLAN_TDLS_DISCOVERY_REQUEST:
if (extra_ies_len)
memcpy(skb_put(skb, extra_ies_len), extra_ies,
extra_ies_len);
if (status_code == 0 || action_code == WLAN_TDLS_TEARDOWN)
rwnx_tdls_add_link_ie(rwnx_hw, rwnx_vif, skb, peer, initiator);
break;
}
}
int
rwnx_tdls_send_mgmt_packet_data(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
const u8 *peer, u8 action_code, u8 dialog_token,
u16 status_code, u32 peer_capability, bool initiator,
const u8 *extra_ies, size_t extra_ies_len, u8 oper_class,
struct cfg80211_chan_def *chandef)
{
struct sk_buff *skb;
int ret = 0;
struct ieee80211_supported_band *rwnx_band_2GHz = rwnx_hw->wiphy->bands[NL80211_BAND_2GHZ];
//#ifdef USE_5G
struct ieee80211_supported_band *rwnx_band_5GHz = rwnx_hw->wiphy->bands[NL80211_BAND_5GHZ];
//#endif
int channels = rwnx_band_2GHz->n_channels;
if (rwnx_hw->band_5g_support){
channels += rwnx_band_5GHz->n_channels;
}
skb = netdev_alloc_skb(rwnx_vif->ndev,
sizeof(struct ieee80211_tdls_data) + // ethhdr + TDLS info
10 + /* supported rates */
6 + /* extended supported rates */
(2 + channels) + /* supported channels */
//#ifdef USE_5G
//(2 + rwnx_band_2GHz->n_channels + rwnx_band_5GHz->n_channels) + /* supported channels */
//#else
//(2 + rwnx_band_2GHz->n_channels) + /* supported channels */
//#endif
sizeof(struct ieee_types_extcap) +
sizeof(struct ieee80211_wmm_param_ie) +
4 + /* oper classes */
28 + //sizeof(struct ieee80211_ht_cap) +
sizeof(struct ieee_types_bss_co_2040) +
sizeof(struct ieee80211_tdls_lnkie) +
(2 + sizeof(struct ieee80211_vht_cap)) +
4 + /*AID*/
(2 + sizeof(struct ieee80211_ht_operation)) +
extra_ies_len);
if (!skb)
return 0;
switch (action_code) {
case WLAN_TDLS_SETUP_REQUEST:
case WLAN_TDLS_SETUP_RESPONSE:
case WLAN_TDLS_SETUP_CONFIRM:
case WLAN_TDLS_TEARDOWN:
case WLAN_TDLS_DISCOVERY_REQUEST:
ret = rwnx_tdls_prepare_encap_data(rwnx_hw, rwnx_vif, peer, action_code,
dialog_token, status_code, skb);
break;
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
ret = rwnx_prep_tdls_direct(rwnx_hw, rwnx_vif, peer, action_code,
dialog_token, status_code, skb);
break;
default:
ret = -ENOTSUPP;
break;
}
if (ret < 0)
goto fail;
rwnx_tdls_add_ies(rwnx_hw, rwnx_vif, skb, peer, action_code, status_code,
initiator, extra_ies, extra_ies_len, oper_class, chandef);
if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) {
u64 cookie;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
struct cfg80211_mgmt_tx_params params;
params.len = skb->len;
params.buf = skb->data;
ret = rwnx_start_mgmt_xmit(rwnx_vif, NULL, &params, false, &cookie);
#else
ret = rwnx_start_mgmt_xmit(rwnx_vif, NULL, NULL, false, 0, skb->data, skb->len, false, false, &cookie);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
return ret;
}
switch (action_code) {
case WLAN_TDLS_SETUP_REQUEST:
case WLAN_TDLS_SETUP_RESPONSE:
case WLAN_TDLS_SETUP_CONFIRM:
skb->priority = 2;
break;
default:
skb->priority = 5;
break;
}
ret = rwnx_select_txq(rwnx_vif, skb);
ret = rwnx_start_xmit(skb, rwnx_vif->ndev);
return ret;
fail:
dev_kfree_skb(skb);
return ret;
}

View file

@ -0,0 +1,54 @@
/**
******************************************************************************
*
* @file rwnx_tdls.h
*
* @brief TDLS function declarations
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#ifndef RWNX_TDLS_H_
#define RWNX_TDLS_H_
#include "rwnx_defs.h"
struct ieee_types_header {
u8 element_id;
u8 len;
} __packed;
struct ieee_types_bss_co_2040 {
struct ieee_types_header ieee_hdr;
u8 bss_2040co;
} __packed;
struct ieee_types_extcap {
struct ieee_types_header ieee_hdr;
u8 ext_capab[8];
} __packed;
struct ieee_types_vht_cap {
struct ieee_types_header ieee_hdr;
struct ieee80211_vht_cap vhtcap;
} __packed;
struct ieee_types_vht_oper {
struct ieee_types_header ieee_hdr;
struct ieee80211_vht_operation vhtoper;
} __packed;
struct ieee_types_aid {
struct ieee_types_header ieee_hdr;
u16 aid;
} __packed;
int rwnx_tdls_send_mgmt_packet_data(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
const u8 *peer, u8 action_code, u8 dialog_token,
u16 status_code, u32 peer_capability, bool initiator,
const u8 *extra_ies, size_t extra_ies_len, u8 oper_class,
struct cfg80211_chan_def *chandef);
#endif /* RWNX_TDLS_H_ */

View file

@ -0,0 +1,226 @@
/**
****************************************************************************************
*
* @file rwnx_testmode.c
*
* @brief Test mode function definitions
*
* Copyright (C) RivieraWaves 2012-2019
*
****************************************************************************************
*/
#include <net/mac80211.h>
#include <net/netlink.h>
#include "rwnx_testmode.h"
#include "rwnx_msg_tx.h"
#include "rwnx_dini.h"
#include "reg_access.h"
/*
* This function handles the user application commands for register access.
*
* It retrieves command ID carried with RWNX_TM_ATTR_COMMAND and calls to the
* handlers respectively.
*
* If it's an unknown commdn ID, -ENOSYS is returned; or -ENOMSG if the
* mandatory fields(RWNX_TM_ATTR_REG_OFFSET,RWNX_TM_ATTR_REG_VALUE32)
* are missing; Otherwise 0 is replied indicating the success of the command execution.
*
* If RWNX_TM_ATTR_COMMAND is RWNX_TM_CMD_APP2DEV_REG_READ, the register read
* value is returned with RWNX_TM_ATTR_REG_VALUE32.
*
* @hw: ieee80211_hw object that represents the device
* @tb: general message fields from the user space
*/
int rwnx_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
{
struct rwnx_hw *rwnx_hw = hw->priv;
u32 mem_addr, val32;
struct sk_buff *skb;
int status = 0;
/* First check if register address is there */
if (!tb[RWNX_TM_ATTR_REG_OFFSET]) {
printk("Error finding register offset\n");
return -ENOMSG;
}
mem_addr = nla_get_u32(tb[RWNX_TM_ATTR_REG_OFFSET]);
switch (nla_get_u32(tb[RWNX_TM_ATTR_COMMAND])) {
case RWNX_TM_CMD_APP2DEV_REG_READ:
{
struct dbg_mem_read_cfm mem_read_cfm;
/*** Send the command to the LMAC ***/
if ((status = rwnx_send_dbg_mem_read_req(rwnx_hw, mem_addr, &mem_read_cfm)))
return status;
/* Allocate the answer message */
skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
if (!skb) {
printk("Error allocating memory\n");
return -ENOMEM;
}
val32 = mem_read_cfm.memdata;
if (nla_put_u32(skb, RWNX_TM_ATTR_REG_VALUE32, val32))
goto nla_put_failure;
/* Send the answer to upper layer */
status = cfg80211_testmode_reply(skb);
if (status < 0)
printk("Error sending msg : %d\n", status);
}
break;
case RWNX_TM_CMD_APP2DEV_REG_WRITE:
{
if (!tb[RWNX_TM_ATTR_REG_VALUE32]) {
printk("Error finding value to write\n");
return -ENOMSG;
} else {
val32 = nla_get_u32(tb[RWNX_TM_ATTR_REG_VALUE32]);
/* Send the command to the LMAC */
if ((status = rwnx_send_dbg_mem_write_req(rwnx_hw, mem_addr, val32)))
return status;
}
}
break;
default:
printk("Unknown testmode register command ID\n");
return -ENOSYS;
}
return status;
nla_put_failure:
kfree_skb(skb);
return -EMSGSIZE;
}
/*
* This function handles the user application commands for Debug filter settings.
*
* @hw: ieee80211_hw object that represents the device
* @tb: general message fields from the user space
*/
int rwnx_testmode_dbg_filter(struct ieee80211_hw *hw, struct nlattr **tb)
{
struct rwnx_hw *rwnx_hw = hw->priv;
u32 filter;
int status = 0;
/* First check if the filter is there */
if (!tb[RWNX_TM_ATTR_REG_FILTER]) {
printk("Error finding filter value\n");
return -ENOMSG;
}
filter = nla_get_u32(tb[RWNX_TM_ATTR_REG_FILTER]);
RWNX_DBG("testmode debug filter, setting: 0x%x\n", filter);
switch (nla_get_u32(tb[RWNX_TM_ATTR_COMMAND])) {
case RWNX_TM_CMD_APP2DEV_SET_DBGMODFILTER:
{
/* Send the command to the LMAC */
if ((status = rwnx_send_dbg_set_mod_filter_req(rwnx_hw, filter)))
return status;
}
break;
case RWNX_TM_CMD_APP2DEV_SET_DBGSEVFILTER:
{
/* Send the command to the LMAC */
if ((status = rwnx_send_dbg_set_sev_filter_req(rwnx_hw, filter)))
return status;
}
break;
default:
printk("Unknown testmode register command ID\n");
return -ENOSYS;
}
return status;
}
/*
* This function handles the user application commands for register access without using
* the normal LMAC messaging way.
* This time register access will be done through direct PCI BAR windows. This can be used
* to access registers even when the :AMC FW is stuck.
*
* @hw: ieee80211_hw object that represents the device
* @tb: general message fields from the user space
*/
int rwnx_testmode_reg_dbg(struct ieee80211_hw *hw, struct nlattr **tb)
{
struct rwnx_hw *rwnx_hw = hw->priv;
struct rwnx_plat *rwnx_plat = rwnx_hw->plat;
u32 mem_addr;
struct sk_buff *skb;
int status = 0;
volatile unsigned int reg_value = 0;
unsigned int offset;
/* First check if register address is there */
if (!tb[RWNX_TM_ATTR_REG_OFFSET]) {
printk("Error finding register offset\n");
return -ENOMSG;
}
mem_addr = nla_get_u32(tb[RWNX_TM_ATTR_REG_OFFSET]);
offset = mem_addr & 0x00FFFFFF;
switch (nla_get_u32(tb[RWNX_TM_ATTR_COMMAND])) {
case RWNX_TM_CMD_APP2DEV_REG_READ_DBG:
{
/*** Send the command to the LMAC ***/
reg_value = RWNX_REG_READ(rwnx_plat, RWNX_ADDR_SYSTEM, offset);
/* Allocate the answer message */
skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
if (!skb) {
printk("Error allocating memory\n");
return -ENOMEM;
}
if (nla_put_u32(skb, RWNX_TM_ATTR_REG_VALUE32, reg_value))
goto nla_put_failure;
/* Send the answer to upper layer */
status = cfg80211_testmode_reply(skb);
if (status < 0)
printk("Error sending msg : %d\n", status);
}
break;
case RWNX_TM_CMD_APP2DEV_REG_WRITE_DBG:
{
if (!tb[RWNX_TM_ATTR_REG_VALUE32]) {
printk("Error finding value to write\n");
return -ENOMSG;
} else {
reg_value = nla_get_u32(tb[RWNX_TM_ATTR_REG_VALUE32]);
/* Send the command to the LMAC */
RWNX_REG_WRITE(reg_value, rwnx_plat, RWNX_ADDR_SYSTEM,
offset);
}
}
break;
default:
printk("Unknown testmode register command ID\n");
return -ENOSYS;
}
return status;
nla_put_failure:
kfree_skb(skb);
return -EMSGSIZE;
}

View file

@ -0,0 +1,64 @@
/**
****************************************************************************************
*
* @file rwnx_testmode.h
*
* @brief Test mode function declarations
*
* Copyright (C) RivieraWaves 2012-2019
*
****************************************************************************************
*/
#ifndef RWNX_TESTMODE_H_
#define RWNX_TESTMODE_H_
#include <net/mac80211.h>
#include <net/netlink.h>
/* Commands from user space to kernel space(RWNX_TM_CMD_APP2DEV_XX) and
* from and kernel space to user space(RWNX_TM_CMD_DEV2APP_XX).
* The command ID is carried with RWNX_TM_ATTR_COMMAND.
*/
enum rwnx_tm_cmd_t {
/* commands from user application to access register */
RWNX_TM_CMD_APP2DEV_REG_READ = 1,
RWNX_TM_CMD_APP2DEV_REG_WRITE,
/* commands from user application to select the Debug levels */
RWNX_TM_CMD_APP2DEV_SET_DBGMODFILTER,
RWNX_TM_CMD_APP2DEV_SET_DBGSEVFILTER,
/* commands to access registers without sending messages to LMAC layer,
* this must be used when LMAC FW is stuck. */
RWNX_TM_CMD_APP2DEV_REG_READ_DBG,
RWNX_TM_CMD_APP2DEV_REG_WRITE_DBG,
RWNX_TM_CMD_MAX,
};
enum rwnx_tm_attr_t {
RWNX_TM_ATTR_NOT_APPLICABLE = 0,
RWNX_TM_ATTR_COMMAND,
/* When RWNX_TM_ATTR_COMMAND is RWNX_TM_CMD_APP2DEV_REG_XXX,
* The mandatory fields are:
* RWNX_TM_ATTR_REG_OFFSET for the offset of the target register;
* RWNX_TM_ATTR_REG_VALUE32 for value */
RWNX_TM_ATTR_REG_OFFSET,
RWNX_TM_ATTR_REG_VALUE32,
/* When RWNX_TM_ATTR_COMMAND is RWNX_TM_CMD_APP2DEV_SET_DBGXXXFILTER,
* The mandatory field is RWNX_TM_ATTR_REG_FILTER. */
RWNX_TM_ATTR_REG_FILTER,
RWNX_TM_ATTR_MAX,
};
/***********************************************************************/
int rwnx_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb);
int rwnx_testmode_dbg_filter(struct ieee80211_hw *hw, struct nlattr **tb);
int rwnx_testmode_reg_dbg(struct ieee80211_hw *hw, struct nlattr **tb);
#endif /* RWNX_TESTMODE_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,202 @@
/**
******************************************************************************
*
* @file rwnx_tx.h
*
* Copyright (C) RivieraWaves 2012-2019
*
******************************************************************************
*/
#ifndef _RWNX_TX_H_
#define _RWNX_TX_H_
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
#include <linux/netdevice.h>
#include "lmac_types.h"
#include "ipc_shared.h"
#include "rwnx_txq.h"
#include "hal_desc.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
#define IEEE80211_NUM_TIDS 16
#endif
#define RWNX_HWQ_BK 0
#define RWNX_HWQ_BE 1
#define RWNX_HWQ_VI 2
#define RWNX_HWQ_VO 3
#define RWNX_HWQ_BCMC 4
#define RWNX_HWQ_NB NX_TXQ_CNT
#define RWNX_HWQ_ALL_ACS (RWNX_HWQ_BK | RWNX_HWQ_BE | RWNX_HWQ_VI | RWNX_HWQ_VO)
#define RWNX_HWQ_ALL_ACS_BIT ( BIT(RWNX_HWQ_BK) | BIT(RWNX_HWQ_BE) | \
BIT(RWNX_HWQ_VI) | BIT(RWNX_HWQ_VO) )
#define RWNX_TX_LIFETIME_MS 1000
#define RWNX_TX_MAX_RATES NX_TX_MAX_RATES
#define RWNX_SWTXHDR_ALIGN_SZ 4
#define RWNX_SWTXHDR_ALIGN_MSK (RWNX_SWTXHDR_ALIGN_SZ - 1)
#define RWNX_SWTXHDR_ALIGN_PADS(x) \
((RWNX_SWTXHDR_ALIGN_SZ - ((x) & RWNX_SWTXHDR_ALIGN_MSK)) \
& RWNX_SWTXHDR_ALIGN_MSK)
#if RWNX_SWTXHDR_ALIGN_SZ & RWNX_SWTXHDR_ALIGN_MSK
#error bad RWNX_SWTXHDR_ALIGN_SZ
#endif
#define AMSDU_PADDING(x) ((4 - ((x) & 0x3)) & 0x3)
#define TXU_CNTRL_RETRY BIT(0)
#define TXU_CNTRL_MORE_DATA BIT(2)
#define TXU_CNTRL_MGMT BIT(3)
#define TXU_CNTRL_MGMT_NO_CCK BIT(4)
#define TXU_CNTRL_AMSDU BIT(6)
#define TXU_CNTRL_MGMT_ROBUST BIT(7)
#define TXU_CNTRL_USE_4ADDR BIT(8)
#define TXU_CNTRL_EOSP BIT(9)
#define TXU_CNTRL_MESH_FWD BIT(10)
#define TXU_CNTRL_TDLS BIT(11)
extern const int rwnx_tid2hwq[IEEE80211_NUM_TIDS];
/**
* struct rwnx_amsdu_txhdr - Structure added in skb headroom (instead of
* rwnx_txhdr) for amsdu subframe buffer (except for the first subframe
* that has a normal rwnx_txhdr)
*
* @list List of other amsdu subframe (rwnx_sw_txhdr.amsdu.hdrs)
* @map_len Length to be downloaded for this subframe
* @dma_addr Buffer address form embedded point of view
* @skb skb
* @pad padding added before this subframe
* (only use when amsdu must be dismantled)
* @msdu_len Size, in bytes, of the MSDU (without padding nor amsdu header)
*/
struct rwnx_amsdu_txhdr {
struct list_head list;
size_t map_len;
dma_addr_t dma_addr;
struct sk_buff *skb;
u16 pad;
u16 msdu_len;
};
/**
* struct rwnx_amsdu - Structure to manage creation of an A-MSDU, updated
* only In the first subframe of an A-MSDU
*
* @hdrs List of subframe of rwnx_amsdu_txhdr
* @len Current size for this A-MDSU (doesn't take padding into account)
* 0 means that no amsdu is in progress
* @nb Number of subframe in the amsdu
* @pad Padding to add before adding a new subframe
*/
struct rwnx_amsdu {
struct list_head hdrs;
u16 len;
u8 nb;
u8 pad;
};
/**
* struct rwnx_sw_txhdr - Software part of tx header
*
* @rwnx_sta sta to which this buffer is addressed
* @rwnx_vif vif that send the buffer
* @txq pointer to TXQ used to send the buffer
* @hw_queue Index of the HWQ used to push the buffer.
* May be different than txq->hwq->id on confirmation.
* @frame_len Size of the frame (doesn't not include mac header)
* (Only used to update stat, can't we use skb->len instead ?)
* @headroom Headroom added in skb to add rwnx_txhdr
* (Only used to remove it before freeing skb, is it needed ?)
* @amsdu Description of amsdu whose first subframe is this buffer
* (amsdu.nb = 0 means this buffer is not part of amsdu)
* @skb skb received from transmission
* @map_len Length mapped for DMA (only rwnx_hw_txhdr and data are mapped)
* @dma_addr DMA address after mapping
* @desc Buffer description that will be copied in shared mem for FW
*/
struct rwnx_sw_txhdr {
struct rwnx_sta *rwnx_sta;
struct rwnx_vif *rwnx_vif;
struct rwnx_txq *txq;
u8 hw_queue;
u16 frame_len;
u16 headroom;
#ifdef CONFIG_RWNX_AMSDUS_TX
struct rwnx_amsdu amsdu;
#endif
u32 need_cfm;
struct sk_buff *skb;
size_t map_len;
dma_addr_t dma_addr;
struct txdesc_api desc;
u8 raw_frame;
u8 fixed_rate;
u16 rate_config;
};
/**
* struct rwnx_txhdr - Stucture to control transimission of packet
* (Added in skb headroom)
*
* @sw_hdr: Information from driver
* @cache_guard:
* @hw_hdr: Information for/from hardware
*/
struct rwnx_txhdr {
struct rwnx_sw_txhdr *sw_hdr;
char cache_guard[L1_CACHE_BYTES];
struct rwnx_hw_txhdr hw_hdr;
};
u16 rwnx_select_txq(struct rwnx_vif *rwnx_vif, struct sk_buff *skb);
netdev_tx_t rwnx_start_xmit(struct sk_buff *skb, struct net_device *dev);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
struct cfg80211_mgmt_tx_params *params, bool offchan,
u64 *cookie);
#else
int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
struct ieee80211_channel *channel, bool offchan,
unsigned int wait, const u8* buf, size_t len,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0))
bool no_cck,
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
bool dont_wait_for_ack,
#endif
u64 *cookie);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
#ifdef CONFIG_RWNX_MON_XMIT
int rwnx_start_monitor_if_xmit(struct sk_buff *skb, struct net_device *dev);
#endif
int rwnx_txdatacfm(void *pthis, void *host_id);
struct rwnx_hw;
struct rwnx_sta;
void rwnx_set_traffic_status(struct rwnx_hw *rwnx_hw,
struct rwnx_sta *sta,
bool available,
u8 ps_id);
void rwnx_ps_bh_enable(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
bool enable);
void rwnx_ps_bh_traffic_req(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta,
u16 pkt_req, u8 ps_id);
void rwnx_switch_vif_sta_txq(struct rwnx_sta *sta, struct rwnx_vif *old_vif,
struct rwnx_vif *new_vif);
int rwnx_dbgfs_print_sta(char *buf, size_t size, struct rwnx_sta *sta,
struct rwnx_hw *rwnx_hw);
void rwnx_txq_credit_update(struct rwnx_hw *rwnx_hw, int sta_idx, u8 tid,
s8 update);
void rwnx_tx_push(struct rwnx_hw *rwnx_hw, struct rwnx_txhdr *txhdr, int flags);
#ifdef CONFIG_BAND_STEERING
void rwnx_probersp_work(struct work_struct *work);
#endif
#endif /* _RWNX_TX_H_ */

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