net: wireless: rockchip_wlan: update bcmdhd driver

1.version: 101.10.361.11 (wlan=r892223-20210630-1)
2.both wifi5 and wifi6 are supported

Signed-off-by: Alex Zhao <zzc@rock-chips.com>
Change-Id: Ia0724ebc628ba40afed947275d34ff5c47a410b4
This commit is contained in:
Alex Zhao
2021-11-06 14:52:46 +08:00
committed by Tao Huang
parent 54143c6ee3
commit 62c06ae47f
507 changed files with 248083 additions and 336975 deletions

View File

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

View File

@@ -30,3 +30,4 @@ obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
obj-$(CONFIG_VIRT_WIFI) += virt_wifi.o
obj-$(CONFIG_WL_ROCKCHIP) += rockchip_wlan/

View File

@@ -36,21 +36,6 @@ if BCMDHD
source "drivers/net/wireless/rockchip_wlan/rkwifi/Kconfig"
endif
menuconfig RTL_WIRELESS_SOLUTION
bool "Realtek Wireless Device Driver Support"
default y
if RTL_WIRELESS_SOLUTION
source "drivers/net/wireless/rockchip_wlan/rtl8188eu/Kconfig"
source "drivers/net/wireless/rockchip_wlan/rtl8188fu/Kconfig"
source "drivers/net/wireless/rockchip_wlan/rtl8189fs/Kconfig"
source "drivers/net/wireless/rockchip_wlan/rtl8723cs/Kconfig"
source "drivers/net/wireless/rockchip_wlan/rtl8723ds/Kconfig"
source "drivers/net/wireless/rockchip_wlan/rtl8821cs/Kconfig"
source "drivers/net/wireless/rockchip_wlan/rtl8822bs/Kconfig"
endif
source "drivers/net/wireless/rockchip_wlan/mvl88w8977/Kconfig"
source "drivers/net/wireless/rockchip_wlan/cywdhd/Kconfig"
endif # WL_ROCKCHIP

View File

@@ -1,12 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_BCMDHD) += rkwifi/
obj-$(CONFIG_RTL8188EU) += rtl8188eu/
obj-$(CONFIG_RTL8188FU) += rtl8188fu/
obj-$(CONFIG_RTL8189FS) += rtl8189fs/
obj-$(CONFIG_RTL8723CS) += rtl8723cs/
obj-$(CONFIG_RTL8723DS) += rtl8723ds/
obj-$(CONFIG_RTL8821CS) += rtl8821cs/
obj-$(CONFIG_RTL8822BS) += rtl8822bs/
obj-$(CONFIG_MVL88W8977) += mvl88w8977/
obj-$(CONFIG_WL_ROCKCHIP) += rkwifi/rk_wifi_config.o
obj-$(CONFIG_CYW_BCMDHD) += cywdhd/

View File

@@ -1,10 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
choice
prompt "Select driver version for ap6xxx chips"
config AP6XXX
tristate "stable version (wifi5)"
#depends on MMC && WLAN_80211
tristate "ap6xxx wireless cards support"
depends on RFKILL_RK
select CFG80211
select MAC80211
help
@@ -16,23 +13,20 @@ config AP6XXX
If you choose to build a module, it'll be called dhd. Say M if
unsure.
config AP6XXX_WIFI6
tristate "support wifi6(80211ax)"
#depends on MMC && WLAN_80211
select CFG80211
select MAC80211
choice
prompt "Enable Chip Interface"
depends on BCMDHD
default BCMDHD_SDIO
help
This driver supports wifi6 for ap6xxx chipset.
Enable Chip Interface.
This driver uses the kernel's wireless extensions subsystem.
config BCMDHD_SDIO
bool "SDIO bus interface support"
depends on BCMDHD && MMC
If you choose to build a module, it'll be called dhd. Say M if
unsure.
config AP6XXX_INDEP_POWER
tristate "support WiFi keepalive during host shutdown"
select CFG80211
select MAC80211
config BCMDHD_PCIE
bool "PCIe bus interface support"
depends on BCMDHD && PCI
endchoice

View File

@@ -3,8 +3,6 @@
# (gwl)
obj-$(CONFIG_AP6XXX) += bcmdhd/
obj-$(CONFIG_AP6XXX_WIFI6) += bcmdhd_wifi6/
obj-$(CONFIG_AP6XXX_INDEP_POWER) += bcmdhd_indep_power/
.PHONY: clean

View File

251
drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/Makefile Normal file → Executable file
View File

@@ -1,8 +1,10 @@
# SPDX-License-Identifier: GPL-2.0
# bcmdhd
MODULE_NAME = bcmdhd
CONFIG_BCMDHD_SDIO := y
MODULE_NAME := bcmdhd
#CONFIG_BCMDHD := m
#CONFIG_BCMDHD_SDIO := y
#CONFIG_BCMDHD_PCIE := y
#CONFIG_BCMDHD_USB := y
@@ -11,36 +13,73 @@ CONFIG_BCMDHD_OOB := y
CONFIG_BCMDHD_PROPTXSTATUS := y
CONFIG_BCMDHD_AG := y
#CONFIG_DHD_USE_STATIC_BUF := y
CONFIG_VTS_SUPPORT := y
CONFIG_BCMDHD_VTS := y
CONFIG_BCMDHD_AUTO_SELECT := y
CONFIG_BCMDHD_DEBUG := y
#CONFIG_BCMDHD_WAPI := y
#CONFIG_BCMDHD_RANDOM_MAC := y
CONFIG_MACH_PLATFORM := y
#CONFIG_BCMDHD_DTS := y
DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \
-DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \
-DDHDTHREAD -DDHD_DEBUG -DSHOW_EVENTS -DBCMDBG -DGET_OTP_MAC_ENABLE \
DHDCFLAGS = -Wall -Wstrict-prototypes -Wno-date-time \
-Dlinux -DLINUX -DBCMDRIVER -Wno-implicit-fallthrough \
-DBCMDONGLEHOST -DBCMDMA32 -DBCMFILEIMAGE \
-DDHDTHREAD -DDHD_DEBUG -DSHOW_EVENTS -DGET_OTP_MAC_ENABLE \
-DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DSUPPORT_PM2_ONLY \
-DKEEP_ALIVE -DPKT_FILTER_SUPPORT -DDHDTCPACK_SUPPRESS \
-DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT \
-DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT -DOEM_ANDROID \
-DMULTIPLE_SUPPLICANT -DTSQ_MULTIPLIER -DMFP -DDHD_8021X_DUMP \
-DPOWERUP_MAX_RETRY=0 -DIFACE_HANG_FORCE_DEV_CLOSE -DWAIT_DEQUEUE \
-DUSE_NEW_RSPEC_DEFS -Wno-declaration-after-statement \
-DWL_EXT_IAPSTA -DWL_ESCAN -DCCODE_LIST \
-DENABLE_INSMOD_NO_FW_LOAD -DDHD_UNSUPPORT_IF_CNTS \
-Idrivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd \
-Idrivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/include
-DENABLE_INSMOD_NO_FW_LOAD -DBCM_USE_PLATFORM_STRLCPY
DHDOFILES = aiutils.o siutils.o sbutils.o bcmutils.o bcmwifi_channels.o \
dhd_linux.o dhd_linux_platdev.o dhd_linux_sched.o dhd_pno.o \
dhd_common.o dhd_ip.o dhd_linux_wq.o dhd_custom_gpio.o \
bcmevent.o hndpmu.o linux_osl.o wldev_common.o wl_android.o bcmxtlv.o \
dhd_debug_linux.o dhd_debug.o dhd_mschdbg.o hnd_pktq.o hnd_pktpool.o \
dhd_config.o dhd_ccode.o wl_event.o wl_android_ext.o wl_escan.o
bcmevent.o hndpmu.o linux_osl.o wldev_common.o wl_android.o \
dhd_debug_linux.o dhd_debug.o dhd_mschdbg.o dhd_dbg_ring.o \
hnd_pktq.o hnd_pktpool.o bcmxtlv.o linux_pkt.o bcmstdlib_s.o frag.o \
dhd_linux_exportfs.o dhd_linux_pktdump.o dhd_mschdbg.o \
dhd_config.o dhd_ccode.o wl_event.o wl_android_ext.o \
wl_iapsta.o wl_escan.o
ifneq ($(CONFIG_WIRELESS_EXT),)
DHDOFILES += wl_iw.o
DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT -DUSE_IW
endif
ifneq ($(CONFIG_CFG80211),)
DHDOFILES += wl_cfg80211.o wl_cfgscan.o wl_cfgp2p.o
DHDOFILES += wl_linux_mon.o wl_cfg_btcoex.o wl_cfgvendor.o
DHDOFILES += dhd_cfg80211.o wl_cfgvif.o
DHDCFLAGS += -DWL_CFG80211 -DWLP2P -DWL_CFG80211_STA_EVENT
# DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS
DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10
DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL
DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES
DHDCFLAGS += -DESCAN_RESULT_PATCH -DESCAN_BUF_OVERFLOW_MGMT
DHDCFLAGS += -DVSDB -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
DHDCFLAGS += -DWLTDLS -DMIRACAST_AMPDU_SIZE=8
DHDCFLAGS += -DWL_VIRTUAL_APSTA
DHDCFLAGS += -DPNO_SUPPORT -DEXPLICIT_DISCIF_CLEANUP
DHDCFLAGS += -DDHD_USE_SCAN_WAKELOCK
DHDCFLAGS += -DSPECIFIC_MAC_GEN_SCHEME
DHDCFLAGS += -DWL_IFACE_MGMT
DHDCFLAGS += -DWLFBT
DHDCFLAGS += -DDHD_LOSSLESS_ROAMING
# DHDCFLAGS += -DWL_STATIC_IF
# DHDCFLAGS += -DWL_CLIENT_SAE
endif
#BCMDHD_SDIO
ifneq ($(CONFIG_BCMDHD_SDIO),)
DHDCFLAGS += -DBCMSDIO -DMMC_SDIO_ABORT -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR \
-DSDTEST -DBDC -DDHD_USE_IDLECOUNT -DCUSTOM_SDIO_F2_BLKSIZE=256 \
-DBCMSDIOH_TXGLOM -DBCMSDIOH_TXGLOM_EXT -DRXFRAME_THREAD \
-DDHDENABLE_TAILPAD -DSUPPORT_P2P_GO_PS -DBCMSDIO_RXLIM_POST
-DDHDENABLE_TAILPAD -DSUPPORT_P2P_GO_PS \
-DBCMSDIO_RXLIM_POST -DBCMSDIO_TXSEQ_SYNC -DCONSOLE_DPC \
-DBCMSDIO_INTSTATUS_WAR
ifeq ($(CONFIG_BCMDHD_OOB),y)
DHDCFLAGS += -DOOB_INTR_ONLY -DCUSTOMER_OOB -DHW_OOB
ifeq ($(CONFIG_BCMDHD_DISABLE_WOWLAN),y)
@@ -57,12 +96,18 @@ endif
ifneq ($(CONFIG_BCMDHD_PCIE),)
DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1 \
-DDONGLE_ENABLE_ISOLATION
DHDCFLAGS += -DDHD_LB -DDHD_LB_RXP -DDHD_LB_STATS #-DDHD_LB_TXP
DHDCFLAGS += -DDHD_LB -DDHD_LB_RXP -DDHD_LB_STATS -DDHD_LB_TXP
DHDCFLAGS += -DDHD_PKTID_AUDIT_ENABLED
DHDCFLAGS += -DINSMOD_FW_LOAD
DHDCFLAGS += -DCHIP_INTR_CONTROL
ifeq ($(CONFIG_BCMDHD_OOB),y)
DHDCFLAGS += -DCUSTOMER_OOB -DBCMPCIE_OOB_HOST_WAKE
endif
ifneq ($(CONFIG_PCI_MSI),)
DHDCFLAGS += -DDHD_USE_MSI
DHDCFLAGS += -DDHD_MSI_SUPPORT
endif
DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o \
dhd_msgbuf.o
dhd_msgbuf.o dhd_linux_lb.o
endif
#BCMDHD_USB
@@ -84,21 +129,51 @@ ifneq ($(CONFIG_BCMDHD_USB),)
DHDCFLAGS += -DPROP_TXSTATUS
endif
ifneq ($(CONFIG_BCMDHD_SDIO),)
DHDCFLAGS += -DPROP_TXSTATUS
DHDCFLAGS += -DPROP_TXSTATUS -DPROPTX_MAXCOUNT
endif
ifneq ($(CONFIG_CFG80211),)
DHDCFLAGS += -DPROP_TXSTATUS_VSDB
endif
endif
#VTS_SUPPORT
ifeq ($(CONFIG_VTS_SUPPORT),y)
ifeq ($(CONFIG_64BIT),y)
DHDCFLAGS := $(filter-out -DBCMDMA32,$(DHDCFLAGS))
DHDCFLAGS += -DBCMDMA64OSL
endif
# For Android VTS
ifeq ($(CONFIG_BCMDHD_VTS),y)
DHDCFLAGS += -DDHD_NOTIFY_MAC_CHANGED
ifneq ($(CONFIG_CFG80211),)
DHDCFLAGS += -DGSCAN_SUPPORT -DRTT_SUPPORT -DLINKSTAT_SUPPORT \
-DCUSTOM_COUNTRY_CODE \
-DDEBUGABILITY -DDBG_PKT_MON -DDHD_FW_COREDUMP \
-DAPF -DNDO_CONFIG_SUPPORT -DRSSI_MONITOR_SUPPORT -DDHD_WAKE_STATUS
DHDOFILES += dhd_rtt.o bcm_app_utils.o
DHDCFLAGS += -DGSCAN_SUPPORT -DRTT_SUPPORT -DLINKSTAT_SUPPORT
DHDCFLAGS += -DCUSTOM_COUNTRY_CODE -DDHD_GET_VALID_CHANNELS
DHDCFLAGS += -DDEBUGABILITY -DDBG_PKT_MON
# DHDCFLAGS += -DDHD_LOG_DUMP
DHDCFLAGS += -DDHD_FW_COREDUMP
DHDCFLAGS += -DAPF -DNDO_CONFIG_SUPPORT -DRSSI_MONITOR_SUPPORT
DHDCFLAGS += -DDHD_WAKE_STATUS
DHDOFILES += dhd_rtt.o bcm_app_utils.o
endif
endif
# For Debug
ifeq ($(CONFIG_BCMDHD_DEBUG),y)
DHDCFLAGS += -DDHD_ARP_DUMP -DDHD_DHCP_DUMP -DDHD_ICMP_DUMP
DHDCFLAGS += -DDHD_DNS_DUMP -DDHD_TRX_DUMP
DHDCFLAGS += -DTPUT_MONITOR
DHDCFLAGS += -DCHECK_DOWNLOAD_FW
# DHDCFLAGS += -DDHD_PKTDUMP_TOFW
endif
# For Debug2
ifeq ($(CONFIG_BCMDHD_DEBUG2),y)
DHDCFLAGS += -DDEBUGFS_CFG80211
DHDCFLAGS += -DSHOW_LOGTRACE -DDHD_LOG_DUMP -DDHD_FW_COREDUMP
DHDCFLAGS += -DBCMASSERT_LOG -DSI_ERROR_ENFORCE
ifneq ($(CONFIG_BCMDHD_PCIE),)
DHDCFLAGS += -DEWP_EDL
DHDCFLAGS += -DDNGL_EVENT_SUPPORT
DHDCFLAGS += -DDHD_SSSR_DUMP
endif
endif
@@ -113,21 +188,77 @@ ifneq ($(CONFIG_BCMDHD_PCIE),)
endif
DHDCFLAGS += -DDHD_UPDATE_INTF_MAC
DHDCFLAGS :=$(filter-out -DDHD_FW_COREDUMP,$(DHDCFLAGS))
DHDCFLAGS :=$(filter-out -DSET_RANDOM_MAC_SOFTAP,$(DHDCFLAGS))
DHDCFLAGS :=$(filter-out -DWL_STATIC_IF,$(DHDCFLAGS))
endif
#obj-$(CONFIG_RKWIFI) += $(MODULE_NAME).o
obj-$(CONFIG_AP6XXX) += $(MODULE_NAME).o
$(MODULE_NAME)-objs += $(DHDOFILES)
ifeq ($(CONFIG_BCMDHD_EASYMESH),y)
DHDCFLAGS :=$(filter-out -DDHD_FW_COREDUMP,$(DHDCFLAGS))
DHDCFLAGS :=$(filter-out -DDHD_LOG_DUMP,$(DHDCFLAGS))
DHDCFLAGS += -DWLEASYMESH -DWL_STATIC_IF -DWLDWDS -DFOURADDR_AUTO_BRG
endif
#CSI_SUPPORT
ifeq ($(CONFIG_CSI_SUPPORT),y)
DHDCFLAGS += -DCSI_SUPPORT
DHDOFILES += dhd_csi.o
endif
# For TPUT_IMPROVE
ifeq ($(CONFIG_BCMDHD_TPUT),y)
DHDCFLAGS += -DDHD_TPUT_PATCH
ifneq ($(CONFIG_BCMDHD_SDIO),)
DHDCFLAGS += -DDYNAMIC_MAX_HDR_READ
DHDCFLAGS :=$(filter-out -DSDTEST,$(DHDCFLAGS))
endif
ifneq ($(CONFIG_BCMDHD_PCIE),)
DHDCFLAGS += -DDHD_LB_TXP_DEFAULT_ENAB
DHDCFLAGS += -DSET_RPS_CPUS -DSET_XPS_CPUS
DHDCFLAGS += -DDHD_LB_PRIMARY_CPUS=0xF0 -DDHD_LB_SECONDARY_CPUS=0x0E
endif
endif
# For Zero configure
ifeq ($(CONFIG_BCMDHD_ZEROCONFIG),y)
DHDCFLAGS += -DWL_EXT_GENL -DSENDPROB
DHDOFILES += wl_ext_genl.o
endif
# For WAPI
ifeq ($(CONFIG_BCMDHD_WAPI),y)
DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI
endif
# For scan random mac
ifneq ($(CONFIG_BCMDHD_RANDOM_MAC),)
ifneq ($(CONFIG_CFG80211),)
DHDCFLAGS += -DSUPPORT_RANDOM_MAC_SCAN -DWL_USE_RANDOMIZED_SCAN
endif
endif
# For NAN
ifneq ($(CONFIG_BCMDHD_NAN),)
DHDCFLAGS += -DWL_NAN -DWL_NAN_DISC_CACHE
DHDOFILES += wl_cfgnan.o bcmbloom.o
endif
# For Module auto-selection
ifeq ($(CONFIG_BCMDHD_AUTO_SELECT),y)
DHDCFLAGS += -DUPDATE_MODULE_NAME
ifneq ($(CONFIG_BCMDHD_SDIO),)
DHDCFLAGS += -DGET_OTP_MODULE_NAME -DCOMPAT_OLD_MODULE
endif
endif
ifeq ($(CONFIG_BCMDHD),m)
DHDCFLAGS += -DBCMDHD_MODULAR
endif
ifeq ($(CONFIG_MACH_PLATFORM),y)
DHDOFILES += dhd_gpio.o
ifeq ($(CONFIG_BCMDHD_DTS),y)
DHDCFLAGS += -DCONFIG_DTS
else
DHDCFLAGS += -DCUSTOMER_HW -DDHD_OF_SUPPORT
DHDCFLAGS += -DBCMDHD_DTS
endif
# DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI
DHDCFLAGS += -DCUSTOMER_HW -DDHD_OF_SUPPORT
endif
ifeq ($(CONFIG_BCMDHD_AG),y)
@@ -137,33 +268,41 @@ endif
ifeq ($(CONFIG_DHD_USE_STATIC_BUF),y)
obj-m += dhd_static_buf.o
DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -DENHANCED_STATIC_BUF
DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP -DCONFIG_DHD_USE_STATIC_BUF
DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF
DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP
ifneq ($(CONFIG_BCMDHD_PCIE),)
DHDCFLAGS += -DDHD_USE_STATIC_CTRLBUF
endif
endif
ifneq ($(CONFIG_WIRELESS_EXT),)
DHDOFILES += wl_iw.o
DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT -DUSE_IW
endif
ifneq ($(CONFIG_CFG80211),)
DHDOFILES += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o wl_cfg_btcoex.o wl_cfgvendor.o
DHDOFILES += dhd_cfg80211.o
DHDCFLAGS += -DWL_CFG80211 -DWLP2P -DWL_CFG80211_STA_EVENT -DWL_ENABLE_P2P_IF
# DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS
DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=7
DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL
DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES
DHDCFLAGS += -DESCAN_RESULT_PATCH -DESCAN_BUF_OVERFLOW_MGMT
DHDCFLAGS += -DVSDB -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
DHDCFLAGS += -DWLTDLS -DMIRACAST_AMPDU_SIZE=8
DHDCFLAGS += -DWL_VIRTUAL_APSTA
DHDCFLAGS += -DPNO_SUPPORT -DEXPLICIT_DISCIF_CLEANUP
DHDCFLAGS += -DWL_SAE
endif
ARCH ?= arm64
BCMDHD_ROOT = $(src)
#$(warning "BCMDHD_ROOT=$(BCMDHD_ROOT)")
EXTRA_CFLAGS = $(DHDCFLAGS)
EXTRA_CFLAGS += -DDHD_COMPILED=\"$(BCMDHD_ROOT)\"
EXTRA_CFLAGS += -I$(BCMDHD_ROOT)/include/ -I$(BCMDHD_ROOT)/
ifeq ($(CONFIG_BCMDHD),m)
EXTRA_LDFLAGS += --strip-debug
endif
EXTRA_CFLAGS += -Wno-parentheses-equality
EXTRA_CFLAGS += -Wno-unused-const-variable
EXTRA_CFLAGS += -Wno-non-literal-null-conversion
obj-$(CONFIG_AP6XXX) += $(MODULE_NAME).o
$(MODULE_NAME)-objs += $(DHDOFILES)
ccflags-y := $(EXTRA_CFLAGS)
all: bcmdhd_pcie bcmdhd_sdio bcmdhd_usb
bcmdhd_pcie:
$(warning "building BCMDHD_PCIE..........")
$(MAKE) -C $(LINUXDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules CONFIG_BCMDHD=m CONFIG_BCMDHD_PCIE=y
bcmdhd_sdio:
$(warning "building BCMDHD_SDIO..........")
$(MAKE) -C $(LINUXDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules CONFIG_BCMDHD=m CONFIG_BCMDHD_SDIO=y
bcmdhd_usb:
$(warning "building BCMDHD_USB..........")
$(MAKE) -C $(LINUXDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules CONFIG_BCMDHD=m CONFIG_BCMDHD_USB=y
clean:
rm -rf *.o *.ko *.mod.c *~ .*.cmd *.o.cmd .*.o.cmd *.mod \
Module.symvers modules.order .tmp_versions modules.builtin

File diff suppressed because it is too large Load Diff

View File

@@ -3,14 +3,14 @@
* Contents are wifi-specific, used by any kernel or app-level
* software that might want wifi things as it grows.
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -18,15 +18,9 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcm_app_utils.c 623866 2016-03-09 11:58:34Z $
* <<Broadcom-WL-IPTag/Dual:>>
*/
#include <typedefs.h>
@@ -47,7 +41,7 @@
#include <bcmwifi_channels.h>
#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
#include <bcmstdlib.h> /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */
#include <bcmstdlib.h> /* For wlexe/Makefile.wlm_dll */
#endif
#include <bcmutils.h>
@@ -119,7 +113,7 @@ spec_to_chan(chanspec_t chspec)
center_ch = CHSPEC_CHANNEL(chspec);
if (CHSPEC_BW_LE20(chspec)) {
if (CHSPEC_IS20(chspec)) {
return center_ch;
} else {
/* the lower edge of the wide channel is half the bw from
@@ -265,6 +259,9 @@ cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chans
#define IDX_IN_WL_CNT_VER_6_T(cntmember) \
((OFFSETOF(wl_cnt_ver_6_t, cntmember) - OFFSETOF(wl_cnt_ver_6_t, txframe)) / sizeof(uint32))
#define IDX_IN_WL_CNT_VER_7_T(cntmember) \
((OFFSETOF(wl_cnt_ver_7_t, cntmember) - OFFSETOF(wl_cnt_ver_7_t, txframe)) / sizeof(uint32))
#define IDX_IN_WL_CNT_VER_11_T(cntmember) \
((OFFSETOF(wl_cnt_ver_11_t, cntmember) - OFFSETOF(wl_cnt_ver_11_t, txframe)) \
/ sizeof(uint32))
@@ -276,12 +273,16 @@ cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chans
#define NUM_OF_WLCCNT_IN_WL_CNT_VER_6_T \
(NUM_OF_CNT_IN_WL_CNT_VER_6_T - (WL_CNT_MCST_VAR_NUM - 2))
/* Exclude version and length fields */
#define NUM_OF_CNT_IN_WL_CNT_VER_7_T \
((sizeof(wl_cnt_ver_7_t) - 2 * sizeof(uint16)) / sizeof(uint32))
/* Exclude version and length fields */
#define NUM_OF_CNT_IN_WL_CNT_VER_11_T \
((sizeof(wl_cnt_ver_11_t) - 2 * sizeof(uint16)) / sizeof(uint32))
/* Exclude 64 macstat cnt variables. */
#define NUM_OF_WLCCNT_IN_WL_CNT_VER_11_T \
(NUM_OF_CNT_IN_WL_CNT_VER_11_T - WL_CNT_MCST_VAR_NUM)
#define NUM_OF_WLCCNT_IN_WL_CNT_VER_11_T \
((sizeof(wl_cnt_wlc_t)) / sizeof(uint32))
/* Index conversion table from wl_cnt_ver_6_t to wl_cnt_wlc_t */
static const uint8 wlcntver6t_to_wlcntwlct[NUM_OF_WLCCNT_IN_WL_CNT_VER_6_T] = {
@@ -411,6 +412,165 @@ static const uint8 wlcntver6t_to_wlcntwlct[NUM_OF_WLCCNT_IN_WL_CNT_VER_6_T] = {
IDX_IN_WL_CNT_VER_6_T(wepexcluded_mcst)
};
#define INVALID_IDX ((uint8)(-1))
/* Index conversion table from wl_cnt_ver_7_t to wl_cnt_wlc_t */
static const uint8 wlcntver7t_to_wlcntwlct[] = {
IDX_IN_WL_CNT_VER_7_T(txframe),
IDX_IN_WL_CNT_VER_7_T(txbyte),
IDX_IN_WL_CNT_VER_7_T(txretrans),
IDX_IN_WL_CNT_VER_7_T(txerror),
IDX_IN_WL_CNT_VER_7_T(txctl),
IDX_IN_WL_CNT_VER_7_T(txprshort),
IDX_IN_WL_CNT_VER_7_T(txserr),
IDX_IN_WL_CNT_VER_7_T(txnobuf),
IDX_IN_WL_CNT_VER_7_T(txnoassoc),
IDX_IN_WL_CNT_VER_7_T(txrunt),
IDX_IN_WL_CNT_VER_7_T(txchit),
IDX_IN_WL_CNT_VER_7_T(txcmiss),
IDX_IN_WL_CNT_VER_7_T(txuflo),
IDX_IN_WL_CNT_VER_7_T(txphyerr),
IDX_IN_WL_CNT_VER_7_T(txphycrs),
IDX_IN_WL_CNT_VER_7_T(rxframe),
IDX_IN_WL_CNT_VER_7_T(rxbyte),
IDX_IN_WL_CNT_VER_7_T(rxerror),
IDX_IN_WL_CNT_VER_7_T(rxctl),
IDX_IN_WL_CNT_VER_7_T(rxnobuf),
IDX_IN_WL_CNT_VER_7_T(rxnondata),
IDX_IN_WL_CNT_VER_7_T(rxbadds),
IDX_IN_WL_CNT_VER_7_T(rxbadcm),
IDX_IN_WL_CNT_VER_7_T(rxfragerr),
IDX_IN_WL_CNT_VER_7_T(rxrunt),
IDX_IN_WL_CNT_VER_7_T(rxgiant),
IDX_IN_WL_CNT_VER_7_T(rxnoscb),
IDX_IN_WL_CNT_VER_7_T(rxbadproto),
IDX_IN_WL_CNT_VER_7_T(rxbadsrcmac),
IDX_IN_WL_CNT_VER_7_T(rxbadda),
IDX_IN_WL_CNT_VER_7_T(rxfilter),
IDX_IN_WL_CNT_VER_7_T(rxoflo),
IDX_IN_WL_CNT_VER_7_T(rxuflo),
IDX_IN_WL_CNT_VER_7_T(rxuflo) + 1,
IDX_IN_WL_CNT_VER_7_T(rxuflo) + 2,
IDX_IN_WL_CNT_VER_7_T(rxuflo) + 3,
IDX_IN_WL_CNT_VER_7_T(rxuflo) + 4,
IDX_IN_WL_CNT_VER_7_T(rxuflo) + 5,
IDX_IN_WL_CNT_VER_7_T(d11cnt_txrts_off),
IDX_IN_WL_CNT_VER_7_T(d11cnt_rxcrc_off),
IDX_IN_WL_CNT_VER_7_T(d11cnt_txnocts_off),
IDX_IN_WL_CNT_VER_7_T(dmade),
IDX_IN_WL_CNT_VER_7_T(dmada),
IDX_IN_WL_CNT_VER_7_T(dmape),
IDX_IN_WL_CNT_VER_7_T(reset),
IDX_IN_WL_CNT_VER_7_T(tbtt),
IDX_IN_WL_CNT_VER_7_T(txdmawar),
IDX_IN_WL_CNT_VER_7_T(pkt_callback_reg_fail),
IDX_IN_WL_CNT_VER_7_T(txfrag),
IDX_IN_WL_CNT_VER_7_T(txmulti),
IDX_IN_WL_CNT_VER_7_T(txfail),
IDX_IN_WL_CNT_VER_7_T(txretry),
IDX_IN_WL_CNT_VER_7_T(txretrie),
IDX_IN_WL_CNT_VER_7_T(rxdup),
IDX_IN_WL_CNT_VER_7_T(txrts),
IDX_IN_WL_CNT_VER_7_T(txnocts),
IDX_IN_WL_CNT_VER_7_T(txnoack),
IDX_IN_WL_CNT_VER_7_T(rxfrag),
IDX_IN_WL_CNT_VER_7_T(rxmulti),
IDX_IN_WL_CNT_VER_7_T(rxcrc),
IDX_IN_WL_CNT_VER_7_T(txfrmsnt),
IDX_IN_WL_CNT_VER_7_T(rxundec),
IDX_IN_WL_CNT_VER_7_T(tkipmicfaill),
IDX_IN_WL_CNT_VER_7_T(tkipcntrmsr),
IDX_IN_WL_CNT_VER_7_T(tkipreplay),
IDX_IN_WL_CNT_VER_7_T(ccmpfmterr),
IDX_IN_WL_CNT_VER_7_T(ccmpreplay),
IDX_IN_WL_CNT_VER_7_T(ccmpundec),
IDX_IN_WL_CNT_VER_7_T(fourwayfail),
IDX_IN_WL_CNT_VER_7_T(wepundec),
IDX_IN_WL_CNT_VER_7_T(wepicverr),
IDX_IN_WL_CNT_VER_7_T(decsuccess),
IDX_IN_WL_CNT_VER_7_T(tkipicverr),
IDX_IN_WL_CNT_VER_7_T(wepexcluded),
IDX_IN_WL_CNT_VER_7_T(txchanrej),
IDX_IN_WL_CNT_VER_7_T(psmwds),
IDX_IN_WL_CNT_VER_7_T(phywatchdog),
IDX_IN_WL_CNT_VER_7_T(prq_entries_handled),
IDX_IN_WL_CNT_VER_7_T(prq_undirected_entries),
IDX_IN_WL_CNT_VER_7_T(prq_bad_entries),
IDX_IN_WL_CNT_VER_7_T(atim_suppress_count),
IDX_IN_WL_CNT_VER_7_T(bcn_template_not_ready),
IDX_IN_WL_CNT_VER_7_T(bcn_template_not_ready_done),
IDX_IN_WL_CNT_VER_7_T(late_tbtt_dpc),
IDX_IN_WL_CNT_VER_7_T(rx1mbps),
IDX_IN_WL_CNT_VER_7_T(rx2mbps),
IDX_IN_WL_CNT_VER_7_T(rx5mbps5),
IDX_IN_WL_CNT_VER_7_T(rx6mbps),
IDX_IN_WL_CNT_VER_7_T(rx9mbps),
IDX_IN_WL_CNT_VER_7_T(rx11mbps),
IDX_IN_WL_CNT_VER_7_T(rx12mbps),
IDX_IN_WL_CNT_VER_7_T(rx18mbps),
IDX_IN_WL_CNT_VER_7_T(rx24mbps),
IDX_IN_WL_CNT_VER_7_T(rx36mbps),
IDX_IN_WL_CNT_VER_7_T(rx48mbps),
IDX_IN_WL_CNT_VER_7_T(rx54mbps),
IDX_IN_WL_CNT_VER_7_T(rx108mbps),
IDX_IN_WL_CNT_VER_7_T(rx162mbps),
IDX_IN_WL_CNT_VER_7_T(rx216mbps),
IDX_IN_WL_CNT_VER_7_T(rx270mbps),
IDX_IN_WL_CNT_VER_7_T(rx324mbps),
IDX_IN_WL_CNT_VER_7_T(rx378mbps),
IDX_IN_WL_CNT_VER_7_T(rx432mbps),
IDX_IN_WL_CNT_VER_7_T(rx486mbps),
IDX_IN_WL_CNT_VER_7_T(rx540mbps),
IDX_IN_WL_CNT_VER_7_T(rfdisable),
IDX_IN_WL_CNT_VER_7_T(txexptime),
IDX_IN_WL_CNT_VER_7_T(txmpdu_sgi),
IDX_IN_WL_CNT_VER_7_T(rxmpdu_sgi),
IDX_IN_WL_CNT_VER_7_T(txmpdu_stbc),
IDX_IN_WL_CNT_VER_7_T(rxmpdu_stbc),
IDX_IN_WL_CNT_VER_7_T(rxundec_mcst),
IDX_IN_WL_CNT_VER_7_T(tkipmicfaill_mcst),
IDX_IN_WL_CNT_VER_7_T(tkipcntrmsr_mcst),
IDX_IN_WL_CNT_VER_7_T(tkipreplay_mcst),
IDX_IN_WL_CNT_VER_7_T(ccmpfmterr_mcst),
IDX_IN_WL_CNT_VER_7_T(ccmpreplay_mcst),
IDX_IN_WL_CNT_VER_7_T(ccmpundec_mcst),
IDX_IN_WL_CNT_VER_7_T(fourwayfail_mcst),
IDX_IN_WL_CNT_VER_7_T(wepundec_mcst),
IDX_IN_WL_CNT_VER_7_T(wepicverr_mcst),
IDX_IN_WL_CNT_VER_7_T(decsuccess_mcst),
IDX_IN_WL_CNT_VER_7_T(tkipicverr_mcst),
IDX_IN_WL_CNT_VER_7_T(wepexcluded_mcst),
IDX_IN_WL_CNT_VER_7_T(dma_hang),
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
IDX_IN_WL_CNT_VER_7_T(rxrtry)
};
/* Max wl_cnt_wlc_t fields including rxrtry */
#define NUM_OF_WLCCNT_IN_WL_CNT_VER_7_T \
(sizeof(wlcntver7t_to_wlcntwlct) / sizeof(uint8))
/* Index conversion table from wl_cnt_ver_11_t to wl_cnt_wlc_t */
static const uint8 wlcntver11t_to_wlcntwlct[NUM_OF_WLCCNT_IN_WL_CNT_VER_11_T] = {
IDX_IN_WL_CNT_VER_11_T(txframe),
@@ -594,7 +754,18 @@ static const uint8 wlcntver11t_to_wlcntwlct[NUM_OF_WLCCNT_IN_WL_CNT_VER_11_T] =
IDX_IN_WL_CNT_VER_11_T(ampdu_wds),
IDX_IN_WL_CNT_VER_11_T(txlost),
IDX_IN_WL_CNT_VER_11_T(txdatamcast),
IDX_IN_WL_CNT_VER_11_T(txdatabcast)
IDX_IN_WL_CNT_VER_11_T(txdatabcast),
INVALID_IDX,
IDX_IN_WL_CNT_VER_11_T(rxback),
IDX_IN_WL_CNT_VER_11_T(txback),
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
INVALID_IDX,
IDX_IN_WL_CNT_VER_11_T(txbcast),
IDX_IN_WL_CNT_VER_11_T(txdropped),
IDX_IN_WL_CNT_VER_11_T(rxbcast),
IDX_IN_WL_CNT_VER_11_T(rxdropped)
};
/* Index conversion table from wl_cnt_ver_11_t to
@@ -737,7 +908,6 @@ static const uint8 wlcntver11t_to_wlcntvle10mcstt[WL_CNT_MCST_VAR_NUM] = {
IDX_IN_WL_CNT_VER_11_T(bphy_badplcp)
};
/* Index conversion table from wl_cnt_ver_6_t to wl_cnt_v_le10_mcst_t */
static const uint8 wlcntver6t_to_wlcntvle10mcstt[WL_CNT_MCST_VAR_NUM] = {
IDX_IN_WL_CNT_VER_6_T(txallfrm),
@@ -806,6 +976,74 @@ static const uint8 wlcntver6t_to_wlcntvle10mcstt[WL_CNT_MCST_VAR_NUM] = {
IDX_IN_WL_CNT_VER_6_T(bphy_badplcp)
};
/* Index conversion table from wl_cnt_ver_7_t to wl_cnt_v_le10_mcst_t */
static const uint8 wlcntver7t_to_wlcntvle10mcstt[WL_CNT_MCST_VAR_NUM] = {
IDX_IN_WL_CNT_VER_7_T(txallfrm),
IDX_IN_WL_CNT_VER_7_T(txrtsfrm),
IDX_IN_WL_CNT_VER_7_T(txctsfrm),
IDX_IN_WL_CNT_VER_7_T(txackfrm),
IDX_IN_WL_CNT_VER_7_T(txdnlfrm),
IDX_IN_WL_CNT_VER_7_T(txbcnfrm),
IDX_IN_WL_CNT_VER_7_T(txfunfl),
IDX_IN_WL_CNT_VER_7_T(txfunfl) + 1,
IDX_IN_WL_CNT_VER_7_T(txfunfl) + 2,
IDX_IN_WL_CNT_VER_7_T(txfunfl) + 3,
IDX_IN_WL_CNT_VER_7_T(txfunfl) + 4,
IDX_IN_WL_CNT_VER_7_T(txfunfl) + 5,
INVALID_MCST_IDX,
INVALID_MCST_IDX,
IDX_IN_WL_CNT_VER_7_T(txtplunfl),
IDX_IN_WL_CNT_VER_7_T(txphyerror),
IDX_IN_WL_CNT_VER_7_T(pktengrxducast),
IDX_IN_WL_CNT_VER_7_T(pktengrxdmcast),
IDX_IN_WL_CNT_VER_7_T(rxfrmtoolong),
IDX_IN_WL_CNT_VER_7_T(rxfrmtooshrt),
IDX_IN_WL_CNT_VER_7_T(rxinvmachdr),
IDX_IN_WL_CNT_VER_7_T(rxbadfcs),
IDX_IN_WL_CNT_VER_7_T(rxbadplcp),
IDX_IN_WL_CNT_VER_7_T(rxcrsglitch),
IDX_IN_WL_CNT_VER_7_T(rxstrt),
IDX_IN_WL_CNT_VER_7_T(rxdfrmucastmbss),
IDX_IN_WL_CNT_VER_7_T(rxmfrmucastmbss),
IDX_IN_WL_CNT_VER_7_T(rxcfrmucast),
IDX_IN_WL_CNT_VER_7_T(rxrtsucast),
IDX_IN_WL_CNT_VER_7_T(rxctsucast),
IDX_IN_WL_CNT_VER_7_T(rxackucast),
IDX_IN_WL_CNT_VER_7_T(rxdfrmocast),
IDX_IN_WL_CNT_VER_7_T(rxmfrmocast),
IDX_IN_WL_CNT_VER_7_T(rxcfrmocast),
IDX_IN_WL_CNT_VER_7_T(rxrtsocast),
IDX_IN_WL_CNT_VER_7_T(rxctsocast),
IDX_IN_WL_CNT_VER_7_T(rxdfrmmcast),
IDX_IN_WL_CNT_VER_7_T(rxmfrmmcast),
IDX_IN_WL_CNT_VER_7_T(rxcfrmmcast),
IDX_IN_WL_CNT_VER_7_T(rxbeaconmbss),
IDX_IN_WL_CNT_VER_7_T(rxdfrmucastobss),
IDX_IN_WL_CNT_VER_7_T(rxbeaconobss),
IDX_IN_WL_CNT_VER_7_T(rxrsptmout),
IDX_IN_WL_CNT_VER_7_T(bcntxcancl),
INVALID_MCST_IDX,
IDX_IN_WL_CNT_VER_7_T(rxf0ovfl),
IDX_IN_WL_CNT_VER_7_T(rxf1ovfl),
IDX_IN_WL_CNT_VER_7_T(rxf2ovfl),
IDX_IN_WL_CNT_VER_7_T(txsfovfl),
IDX_IN_WL_CNT_VER_7_T(pmqovfl),
IDX_IN_WL_CNT_VER_7_T(rxcgprqfrm),
IDX_IN_WL_CNT_VER_7_T(rxcgprsqovfl),
IDX_IN_WL_CNT_VER_7_T(txcgprsfail),
IDX_IN_WL_CNT_VER_7_T(txcgprssuc),
IDX_IN_WL_CNT_VER_7_T(prs_timeout),
IDX_IN_WL_CNT_VER_7_T(rxnack),
IDX_IN_WL_CNT_VER_7_T(frmscons),
IDX_IN_WL_CNT_VER_7_T(txnack),
INVALID_MCST_IDX,
INVALID_MCST_IDX,
IDX_IN_WL_CNT_VER_7_T(bphy_rxcrsglitch),
INVALID_MCST_IDX,
INVALID_MCST_IDX,
INVALID_MCST_IDX
};
/* copy wlc layer counters from old type cntbuf to wl_cnt_wlc_t type. */
static int
wl_copy_wlccnt(uint16 cntver, uint32 *dst, uint32 *src, uint8 src_max_idx)
@@ -828,11 +1066,24 @@ wl_copy_wlccnt(uint16 cntver, uint32 *dst, uint32 *src, uint8 src_max_idx)
}
dst[i] = src[wlcntver6t_to_wlcntwlct[i]];
}
} else if (cntver == WL_CNT_VERSION_7) {
for (i = 0; i < NUM_OF_WLCCNT_IN_WL_CNT_VER_7_T; i++) {
if (wlcntver7t_to_wlcntwlct[i] >= src_max_idx ||
wlcntver7t_to_wlcntwlct[i] == INVALID_IDX) {
continue;
}
dst[i] = src[wlcntver7t_to_wlcntwlct[i]];
}
} else {
for (i = 0; i < NUM_OF_WLCCNT_IN_WL_CNT_VER_11_T; i++) {
if (wlcntver11t_to_wlcntwlct[i] >= src_max_idx) {
/* src buffer does not have counters from here */
break;
if (wlcntver11t_to_wlcntwlct[i] == INVALID_IDX) {
continue;
}
else {
/* src buffer does not have counters from here */
break;
}
}
dst[i] = src[wlcntver11t_to_wlcntwlct[i]];
}
@@ -859,6 +1110,15 @@ wl_copy_macstat_upto_ver10(uint16 cntver, uint32 *dst, uint32 *src)
dst[i] = src[wlcntver6t_to_wlcntvle10mcstt[i]];
}
}
} else if (cntver == WL_CNT_VERSION_7) {
for (i = 0; i < WL_CNT_MCST_VAR_NUM; i++) {
if (wlcntver7t_to_wlcntvle10mcstt[i] == INVALID_MCST_IDX) {
/* This mcst counter does not exist in wl_cnt_ver_7_t */
dst[i] = INVALID_CNT_VAL;
} else {
dst[i] = src[wlcntver7t_to_wlcntvle10mcstt[i]];
}
}
} else {
for (i = 0; i < WL_CNT_MCST_VAR_NUM; i++) {
if (wlcntver11t_to_wlcntvle10mcstt[i] == INVALID_MCST_IDX) {
@@ -904,7 +1164,7 @@ wl_cntbuf_to_xtlv_format(void *ctx, void *cntbuf, int buflen, uint32 corerev)
uint16 mcst_xtlv_id;
int res = BCME_OK;
wl_cnt_info_t *cntinfo = cntbuf;
void *xtlvbuf_p = cntinfo->data;
uint8 *xtlvbuf_p = cntinfo->data;
uint16 ver = cntinfo->version;
uint16 xtlvbuflen = (uint16)buflen;
uint16 src_max_idx;
@@ -927,13 +1187,14 @@ wl_cntbuf_to_xtlv_format(void *ctx, void *cntbuf, int buflen, uint32 corerev)
macstat = (uint32 *)malloc(WL_CNT_MCST_STRUCT_SZ);
#endif
if (!wlccnt || !macstat) {
printf("%s: malloc fail!\n", __FUNCTION__);
printf("wl_cntbuf_to_xtlv_format: malloc fail!\n");
res = BCME_NOMEM;
goto exit;
}
/* Check if the max idx in the struct exceeds the boundary of uint8 */
if (NUM_OF_CNT_IN_WL_CNT_VER_6_T > ((uint8)(-1) + 1) ||
NUM_OF_CNT_IN_WL_CNT_VER_7_T > ((uint8)(-1) + 1) ||
NUM_OF_CNT_IN_WL_CNT_VER_11_T > ((uint8)(-1) + 1)) {
printf("wlcntverXXt_to_wlcntwlct and src_max_idx need"
" to be of uint16 instead of uint8\n");

View File

@@ -0,0 +1,766 @@
/*
* L2 Filter handling functions
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
*
* <<Broadcom-WL-IPTag/Dual:>>
*
*/
#include <bcmutils.h>
#include <bcmendian.h>
#include <bcmdefs.h>
#include <bcmdevs.h>
#include <ethernet.h>
#include <bcmip.h>
#include <bcmipv6.h>
#include <bcmudp.h>
#include <bcmarp.h>
#include <bcmicmp.h>
#include <bcmproto.h>
#include <bcmdhcp.h>
#include <802.11.h>
#include <bcm_l2_filter.h>
#ifdef BCMDBG_ERR
#define L2_FILTER_ERROR(args) printf args
#else
#define L2_FILTER_ERROR(args)
#endif /* BCMDBG_ERR */
#ifdef BCMDBG_MSG
#define L2_FILTER_MSG(args) printf args
#else
#define L2_FILTER_MSG(args)
#endif /* BCMDBG_msg */
struct arp_table {
parp_entry_t *parp_table[BCM_PARP_TABLE_SIZE]; /* proxyarp entries in cache table */
parp_entry_t *parp_candidate_list; /* proxyarp entries in candidate list */
uint8 parp_smac[ETHER_ADDR_LEN]; /* L2 SMAC from DHCP Req */
uint8 parp_cmac[ETHER_ADDR_LEN]; /* Bootp Client MAC from DHCP Req */
};
#ifdef DHD_DUMP_ARPTABLE
void bcm_l2_parp_dump_table(arp_table_t* arp_tbl);
void
bcm_l2_parp_dump_table(arp_table_t* arp_tbl)
{
parp_entry_t *entry;
uint16 idx, ip_len;
arp_table_t *ptable;
ip_len = IPV4_ADDR_LEN;
ptable = arp_tbl;
for (idx = 0; idx < BCM_PARP_TABLE_SIZE; idx++) {
entry = ptable->parp_table[idx];
while (entry) {
printf("Cached entries..\n");
printf("%d: %d.%d.%d.%d", idx, entry->ip.data[0], entry->ip.data[1],
entry->ip.data[2], entry->ip.data[3]);
printf("%02x:%02x:%02x:%02x:%02x:%02x", entry->ea.octet[0],
entry->ea.octet[1], entry->ea.octet[2], entry->ea.octet[3],
entry->ea.octet[4], entry->ea.octet[5]);
printf("\n");
entry = entry->next;
}
}
entry = ptable->parp_candidate_list;
while (entry) {
printf("Candidate entries..\n");
printf("%d.%d.%d.%d", entry->ip.data[0], entry->ip.data[1],
entry->ip.data[2], entry->ip.data[3]);
printf("%02x:%02x:%02x:%02x:%02x:%02x", entry->ea.octet[0],
entry->ea.octet[1], entry->ea.octet[2], entry->ea.octet[3],
entry->ea.octet[4], entry->ea.octet[5]);
printf("\n");
entry = entry->next;
}
}
#endif /* DHD_DUMP_ARPTABLE */
arp_table_t* init_l2_filter_arp_table(osl_t* osh)
{
return ((arp_table_t*)MALLOCZ(osh, sizeof(arp_table_t)));
}
void deinit_l2_filter_arp_table(osl_t* osh, arp_table_t* ptable)
{
MFREE(osh, ptable, sizeof(arp_table_t));
}
/* returns 0 if gratuitous ARP or unsolicited neighbour advertisement */
int
bcm_l2_filter_gratuitous_arp(osl_t *osh, void *pktbuf)
{
uint8 *frame = PKTDATA(osh, pktbuf);
uint16 ethertype;
int send_ip_offset, target_ip_offset;
int iplen;
int minlen;
uint8 *data;
int datalen;
bool snap;
if (get_pkt_ether_type(osh, pktbuf, &data, &datalen, &ethertype, &snap) != BCME_OK)
return BCME_ERROR;
if (!ETHER_ISBCAST(frame + ETHER_DEST_OFFSET) &&
bcmp(&ether_ipv6_mcast, frame + ETHER_DEST_OFFSET, sizeof(ether_ipv6_mcast))) {
return BCME_ERROR;
}
if (ethertype == ETHER_TYPE_ARP) {
L2_FILTER_MSG(("bcm_l2_filter_gratuitous_arp: ARP RX data : %p: datalen : %d\n",
data, datalen));
send_ip_offset = ARP_SRC_IP_OFFSET;
target_ip_offset = ARP_TGT_IP_OFFSET;
iplen = IPV4_ADDR_LEN;
minlen = ARP_DATA_LEN;
} else if (ethertype == ETHER_TYPE_IPV6) {
send_ip_offset = NEIGHBOR_ADVERTISE_SRC_IPV6_OFFSET;
target_ip_offset = NEIGHBOR_ADVERTISE_TGT_IPV6_OFFSET;
iplen = IPV6_ADDR_LEN;
minlen = target_ip_offset + iplen;
/* check for neighbour advertisement */
if (datalen >= minlen && (data[IPV6_NEXT_HDR_OFFSET] != IP_PROT_ICMP6 ||
data[NEIGHBOR_ADVERTISE_TYPE_OFFSET] != NEIGHBOR_ADVERTISE_TYPE))
return BCME_ERROR;
/* Dont drop Unsolicitated NA fm AP with allnode mcast dest addr (HS2-4.5.E) */
if (datalen >= minlen &&
(data[IPV6_NEXT_HDR_OFFSET] == IP_PROT_ICMP6) &&
(data[NEIGHBOR_ADVERTISE_TYPE_OFFSET] == NEIGHBOR_ADVERTISE_TYPE) &&
(data[NEIGHBOR_ADVERTISE_OPTION_OFFSET] == OPT_TYPE_TGT_LINK_ADDR)) {
L2_FILTER_MSG(("Unsolicitated Neighbour Advertisement from AP "
"with allnode mcast dest addr tx'ed (%d)\n", datalen));
return -1;
}
} else {
return BCME_ERROR;
}
if (datalen < minlen) {
L2_FILTER_MSG(("BCM: dhd_gratuitous_arp: truncated packet (%d)\n", datalen));
return BCME_ERROR;
}
if (bcmp(data + send_ip_offset, data + target_ip_offset, iplen) == 0) {
L2_FILTER_MSG((" returning BCME_OK in bcm_l2_filter_gratuitous_arp\n"));
return BCME_OK;
}
return BCME_ERROR;
}
int
get_pkt_ether_type(osl_t *osh, void *pktbuf,
uint8 **data_ptr, int *len_ptr, uint16 *et_ptr, bool *snap_ptr)
{
uint8 *frame = PKTDATA(osh, pktbuf);
int length = PKTLEN(osh, pktbuf);
uint8 *pt; /* Pointer to type field */
uint16 ethertype;
bool snap = FALSE;
/* Process Ethernet II or SNAP-encapsulated 802.3 frames */
if (length < ETHER_HDR_LEN) {
L2_FILTER_MSG(("BCM: get_pkt_ether_type: short eth frame (%d)\n",
length));
return BCME_ERROR;
} else if (ntoh16_ua(frame + ETHER_TYPE_OFFSET) >= ETHER_TYPE_MIN) {
/* Frame is Ethernet II */
pt = frame + ETHER_TYPE_OFFSET;
} else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN &&
!bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) {
pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN;
snap = TRUE;
} else {
L2_FILTER_MSG((" get_pkt_ether_type: non-SNAP 802.3 frame\n"));
return BCME_ERROR;
}
ethertype = ntoh16_ua(pt);
/* Skip VLAN tag, if any */
if (ethertype == ETHER_TYPE_8021Q) {
pt += VLAN_TAG_LEN;
if ((pt + ETHER_TYPE_LEN) > (frame + length)) {
L2_FILTER_MSG(("BCM: get_pkt_ether_type: short VLAN frame (%d)\n",
length));
return BCME_ERROR;
}
ethertype = ntoh16_ua(pt);
}
*data_ptr = pt + ETHER_TYPE_LEN;
*len_ptr = length - (int32)(pt + ETHER_TYPE_LEN - frame);
*et_ptr = ethertype;
*snap_ptr = snap;
return BCME_OK;
}
int
get_pkt_ip_type(osl_t *osh, void *pktbuf,
uint8 **data_ptr, int *len_ptr, uint8 *prot_ptr)
{
struct ipv4_hdr *iph; /* IP frame pointer */
int iplen; /* IP frame length */
uint16 ethertype, iphdrlen, ippktlen;
uint16 iph_frag;
uint8 prot;
bool snap;
if (get_pkt_ether_type(osh, pktbuf, (uint8 **)&iph,
&iplen, &ethertype, &snap) != 0)
return BCME_ERROR;
if (ethertype != ETHER_TYPE_IP) {
return BCME_ERROR;
}
/* We support IPv4 only */
if (iplen < IPV4_OPTIONS_OFFSET || (IP_VER(iph) != IP_VER_4)) {
return BCME_ERROR;
}
/* Header length sanity */
iphdrlen = IPV4_HLEN(iph);
/*
* Packet length sanity; sometimes we receive eth-frame size bigger
* than the IP content, which results in a bad tcp chksum
*/
ippktlen = ntoh16(iph->tot_len);
if (ippktlen < iplen) {
L2_FILTER_MSG(("get_pkt_ip_type: extra frame length ignored\n"));
iplen = ippktlen;
} else if (ippktlen > iplen) {
L2_FILTER_MSG(("get_pkt_ip_type: truncated IP packet (%d)\n",
ippktlen - iplen));
return BCME_ERROR;
}
if (iphdrlen < IPV4_OPTIONS_OFFSET || iphdrlen > iplen) {
L2_FILTER_ERROR((" get_pkt_ip_type: IP-header-len (%d) out of range (%d-%d)\n",
iphdrlen, IPV4_OPTIONS_OFFSET, iplen));
return BCME_ERROR;
}
/*
* We don't handle fragmented IP packets. A first frag is indicated by the MF
* (more frag) bit and a subsequent frag is indicated by a non-zero frag offset.
*/
iph_frag = ntoh16(iph->frag);
if ((iph_frag & IPV4_FRAG_MORE) || (iph_frag & IPV4_FRAG_OFFSET_MASK) != 0) {
L2_FILTER_ERROR(("get_pkt_ip_type: IP fragment not handled\n"));
return BCME_ERROR;
}
prot = IPV4_PROT(iph);
*data_ptr = (((uint8 *)iph) + iphdrlen);
*len_ptr = iplen - iphdrlen;
*prot_ptr = prot;
return BCME_OK;
}
/* Check if packet type is ICMP ECHO */
int bcm_l2_filter_block_ping(osl_t *osh, void *pktbuf)
{
struct bcmicmp_hdr *icmph;
int udpl;
uint8 prot;
if (get_pkt_ip_type(osh, pktbuf, (uint8 **)&icmph, &udpl, &prot) != 0)
return BCME_ERROR;
if (prot == IP_PROT_ICMP) {
if (icmph->type == ICMP_TYPE_ECHO_REQUEST)
return BCME_OK;
}
return BCME_ERROR;
}
int bcm_l2_filter_get_mac_addr_dhcp_pkt(osl_t *osh, void *pktbuf,
int ifidx, uint8** mac_addr)
{
uint8 *eh = PKTDATA(osh, pktbuf);
uint8 *udph;
uint8 *dhcp;
int udpl;
int dhcpl;
uint16 port;
uint8 prot;
if (!ETHER_ISMULTI(eh + ETHER_DEST_OFFSET))
return BCME_ERROR;
if (get_pkt_ip_type(osh, pktbuf, &udph, &udpl, &prot) != 0)
return BCME_ERROR;
if (prot != IP_PROT_UDP)
return BCME_ERROR;
/* check frame length, at least UDP_HDR_LEN */
if (udpl < UDP_HDR_LEN) {
L2_FILTER_MSG(("BCM: bcm_l2_filter_get_mac_addr_dhcp_pkt: short UDP frame,"
" ignored\n"));
return BCME_ERROR;
}
port = ntoh16_ua(udph + UDP_DEST_PORT_OFFSET);
/* only process DHCP packets from server to client */
if (port != DHCP_PORT_CLIENT)
return BCME_ERROR;
dhcp = udph + UDP_HDR_LEN;
dhcpl = udpl - UDP_HDR_LEN;
if (dhcpl < DHCP_CHADDR_OFFSET + ETHER_ADDR_LEN) {
L2_FILTER_MSG(("BCM: bcm_l2_filter_get_mac_addr_dhcp_pkt: short DHCP frame,"
" ignored\n"));
return BCME_ERROR;
}
/* only process DHCP reply(offer/ack) packets */
if (*(dhcp + DHCP_TYPE_OFFSET) != DHCP_TYPE_REPLY)
return BCME_ERROR;
/* chaddr = dhcp + DHCP_CHADDR_OFFSET; */
*mac_addr = dhcp + DHCP_CHADDR_OFFSET;
return BCME_OK;
}
/* modify the mac address for IP, in arp table */
int
bcm_l2_filter_parp_modifyentry(arp_table_t* arp_tbl, struct ether_addr *ea,
uint8 *ip, uint8 ip_ver, bool cached, unsigned int entry_tickcnt)
{
parp_entry_t *entry;
uint8 idx, ip_len;
arp_table_t *ptable;
if (ip_ver == IP_VER_4 && !IPV4_ADDR_NULL(ip) && !IPV4_ADDR_BCAST(ip)) {
idx = BCM_PARP_TABLE_INDEX(ip[IPV4_ADDR_LEN - 1]);
ip_len = IPV4_ADDR_LEN;
}
else if (ip_ver == IP_VER_6 && !IPV6_ADDR_NULL(ip)) {
idx = BCM_PARP_TABLE_INDEX(ip[IPV6_ADDR_LEN - 1]);
ip_len = IPV6_ADDR_LEN;
}
else {
return BCME_ERROR;
}
ptable = arp_tbl;
if (cached) {
entry = ptable->parp_table[idx];
} else {
entry = ptable->parp_candidate_list;
}
while (entry) {
if (bcmp(entry->ip.data, ip, ip_len) == 0) {
/* entry matches, overwrite mac content and return */
bcopy((void *)ea, (void *)&entry->ea, ETHER_ADDR_LEN);
entry->used = entry_tickcnt;
#ifdef DHD_DUMP_ARPTABLE
bcm_l2_parp_dump_table(arp_tbl);
#endif
return BCME_OK;
}
entry = entry->next;
}
#ifdef DHD_DUMP_ARPTABLE
bcm_l2_parp_dump_table(arp_tbl);
#endif
return BCME_ERROR;
}
/* Add the IP entry in ARP table based on Cached argument, if cached argument is
* non zero positive value: it adds to parp_table, else adds to
* parp_candidate_list
*/
int
bcm_l2_filter_parp_addentry(osl_t *osh, arp_table_t* arp_tbl, struct ether_addr *ea,
uint8 *ip, uint8 ip_ver, bool cached, unsigned int entry_tickcnt)
{
parp_entry_t *entry;
uint8 idx, ip_len;
arp_table_t *ptable;
if (ip_ver == IP_VER_4 && !IPV4_ADDR_NULL(ip) && !IPV4_ADDR_BCAST(ip)) {
idx = BCM_PARP_TABLE_INDEX(ip[IPV4_ADDR_LEN - 1]);
ip_len = IPV4_ADDR_LEN;
}
else if (ip_ver == IP_VER_6 && !IPV6_ADDR_NULL(ip)) {
idx = BCM_PARP_TABLE_INDEX(ip[IPV6_ADDR_LEN - 1]);
ip_len = IPV6_ADDR_LEN;
}
else {
return BCME_ERROR;
}
if ((entry = MALLOCZ(osh, sizeof(parp_entry_t) + ip_len)) == NULL) {
L2_FILTER_MSG(("Allocating new parp_entry for IPv%d failed!!\n", ip_ver));
return BCME_NOMEM;
}
bcopy((void *)ea, (void *)&entry->ea, ETHER_ADDR_LEN);
entry->used = entry_tickcnt;
entry->ip.id = ip_ver;
entry->ip.len = ip_len;
bcopy(ip, entry->ip.data, ip_len);
ptable = arp_tbl;
if (cached) {
entry->next = ptable->parp_table[idx];
ptable->parp_table[idx] = entry;
} else {
entry->next = ptable->parp_candidate_list;
ptable->parp_candidate_list = entry;
}
#ifdef DHD_DUMP_ARPTABLE
bcm_l2_parp_dump_table(arp_tbl);
#endif
return BCME_OK;
}
/* Delete the IP entry in ARP table based on Cached argument, if cached argument is
* non zero positive value: it delete from parp_table, else delete from
* parp_candidate_list
*/
int
bcm_l2_filter_parp_delentry(osl_t* osh, arp_table_t *arp_tbl, struct ether_addr *ea,
uint8 *ip, uint8 ip_ver, bool cached)
{
parp_entry_t *entry, *prev = NULL;
uint8 idx, ip_len;
arp_table_t *ptable;
if (ip_ver == IP_VER_4) {
idx = BCM_PARP_TABLE_INDEX(ip[IPV4_ADDR_LEN - 1]);
ip_len = IPV4_ADDR_LEN;
}
else if (ip_ver == IP_VER_6) {
idx = BCM_PARP_TABLE_INDEX(ip[IPV6_ADDR_LEN - 1]);
ip_len = IPV6_ADDR_LEN;
}
else {
return BCME_ERROR;
}
ptable = arp_tbl;
if (cached) {
entry = ptable->parp_table[idx];
} else {
entry = ptable->parp_candidate_list;
}
while (entry) {
if (entry->ip.id == ip_ver &&
bcmp(entry->ip.data, ip, ip_len) == 0 &&
bcmp(&entry->ea, ea, ETHER_ADDR_LEN) == 0) {
if (prev == NULL) {
if (cached) {
ptable->parp_table[idx] = entry->next;
} else {
ptable->parp_candidate_list = entry->next;
}
} else {
prev->next = entry->next;
}
break;
}
prev = entry;
entry = entry->next;
}
if (entry != NULL)
MFREE(osh, entry, sizeof(parp_entry_t) + ip_len);
#ifdef DHD_DUMP_ARPTABLE
bcm_l2_parp_dump_table(arp_tbl);
#endif
return BCME_OK;
}
/* search the IP entry in ARP table based on Cached argument, if cached argument is
* non zero positive value: it searches from parp_table, else search from
* parp_candidate_list
*/
parp_entry_t *
bcm_l2_filter_parp_findentry(arp_table_t* arp_tbl, uint8 *ip, uint8 ip_ver, bool cached,
unsigned int entry_tickcnt)
{
parp_entry_t *entry;
uint8 idx, ip_len;
arp_table_t *ptable;
if (ip_ver == IP_VER_4) {
idx = BCM_PARP_TABLE_INDEX(ip[IPV4_ADDR_LEN - 1]);
ip_len = IPV4_ADDR_LEN;
} else if (ip_ver == IP_VER_6) {
idx = BCM_PARP_TABLE_INDEX(ip[IPV6_ADDR_LEN - 1]);
ip_len = IPV6_ADDR_LEN;
} else {
return NULL;
}
ptable = arp_tbl;
if (cached) {
entry = ptable->parp_table[idx];
} else {
entry = ptable->parp_candidate_list;
}
while (entry) {
if (entry->ip.id == ip_ver && bcmp(entry->ip.data, ip, ip_len) == 0) {
/* time stamp of adding the station entry to arp table for ifp */
entry->used = entry_tickcnt;
break;
}
entry = entry->next;
}
return entry;
}
/* update arp table entries for every proxy arp enable interface */
void
bcm_l2_filter_arp_table_update(osl_t *osh, arp_table_t* arp_tbl, bool all, uint8 *del_ea,
bool periodic, unsigned int tickcnt)
{
parp_entry_t *prev, *entry, *delentry;
uint8 idx, ip_ver;
struct ether_addr ea;
uint8 ip[IPV6_ADDR_LEN];
arp_table_t *ptable;
ptable = arp_tbl;
for (idx = 0; idx < BCM_PARP_TABLE_SIZE; idx++) {
entry = ptable->parp_table[idx];
while (entry) {
/* check if the entry need to be removed */
if (all || (periodic && BCM_PARP_IS_TIMEOUT(tickcnt, entry)) ||
(del_ea != NULL && !bcmp(del_ea, &entry->ea, ETHER_ADDR_LEN))) {
/* copy frame here */
ip_ver = entry->ip.id;
bcopy(entry->ip.data, ip, entry->ip.len);
bcopy(&entry->ea, &ea, ETHER_ADDR_LEN);
entry = entry->next;
bcm_l2_filter_parp_delentry(osh, ptable, &ea, ip, ip_ver, TRUE);
}
else {
entry = entry->next;
}
}
}
/* remove candidate or promote to real entry */
prev = delentry = NULL;
entry = ptable->parp_candidate_list;
while (entry) {
/* remove candidate */
if (all || (periodic && BCM_PARP_ANNOUNCE_WAIT_REACH(tickcnt, entry)) ||
(del_ea != NULL && !bcmp(del_ea, (uint8 *)&entry->ea, ETHER_ADDR_LEN))) {
bool promote = (periodic && BCM_PARP_ANNOUNCE_WAIT_REACH(tickcnt, entry)) ?
TRUE: FALSE;
parp_entry_t *node = NULL;
ip_ver = entry->ip.id;
if (prev == NULL)
ptable->parp_candidate_list = entry->next;
else
prev->next = entry->next;
node = bcm_l2_filter_parp_findentry(ptable,
entry->ip.data, IP_VER_6, TRUE, tickcnt);
if (promote && node == NULL) {
bcm_l2_filter_parp_addentry(osh, ptable, &entry->ea,
entry->ip.data, entry->ip.id, TRUE, tickcnt);
}
MFREE(osh, entry, sizeof(parp_entry_t) + entry->ip.len);
if (prev == NULL) {
entry = ptable->parp_candidate_list;
} else {
entry = prev->next;
}
}
else {
prev = entry;
entry = entry->next;
}
}
}
/* create 42 byte ARP packet for ARP response, aligned the Buffer */
void *
bcm_l2_filter_proxyarp_alloc_reply(osl_t* osh, uint16 pktlen, struct ether_addr *src_ea,
struct ether_addr *dst_ea, uint16 ea_type, bool snap, void **p)
{
void *pkt;
uint8 *frame;
/* adjust pktlen since skb->data is aligned to 2 */
pktlen += ALIGN_ADJ_BUFLEN;
if ((pkt = PKTGET(osh, pktlen, FALSE)) == NULL) {
L2_FILTER_ERROR(("bcm_l2_filter_proxyarp_alloc_reply: PKTGET failed\n"));
return NULL;
}
/* adjust for pkt->data aligned */
PKTPULL(osh, pkt, ALIGN_ADJ_BUFLEN);
frame = PKTDATA(osh, pkt);
/* Create 14-byte eth header, plus snap header if applicable */
bcopy(src_ea, frame + ETHER_SRC_OFFSET, ETHER_ADDR_LEN);
bcopy(dst_ea, frame + ETHER_DEST_OFFSET, ETHER_ADDR_LEN);
if (snap) {
hton16_ua_store(pktlen, frame + ETHER_TYPE_OFFSET);
bcopy(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN);
hton16_ua_store(ea_type, frame + ETHER_HDR_LEN + SNAP_HDR_LEN);
} else
hton16_ua_store(ea_type, frame + ETHER_TYPE_OFFSET);
*p = (void *)(frame + ETHER_HDR_LEN + (snap ? SNAP_HDR_LEN + ETHER_TYPE_LEN : 0));
return pkt;
}
/* copy the smac entry from parp_table */
void bcm_l2_filter_parp_get_smac(arp_table_t* ptable, void* smac)
{
bcopy(ptable->parp_smac, smac, ETHER_ADDR_LEN);
}
/* copy the cmac entry from parp_table */
void bcm_l2_filter_parp_get_cmac(arp_table_t* ptable, void* cmac)
{
bcopy(ptable->parp_cmac, cmac, ETHER_ADDR_LEN);
}
/* copy the smac entry to smac entry in parp_table */
void bcm_l2_filter_parp_set_smac(arp_table_t* ptable, void* smac)
{
bcopy(smac, ptable->parp_smac, ETHER_ADDR_LEN);
}
/* copy the cmac entry to cmac entry in parp_table */
void bcm_l2_filter_parp_set_cmac(arp_table_t* ptable, void* cmac)
{
bcopy(cmac, ptable->parp_cmac, ETHER_ADDR_LEN);
}
uint16
calc_checksum(uint8 *src_ipa, uint8 *dst_ipa, uint32 ul_len, uint8 prot, uint8 *ul_data)
{
uint16 *startpos;
uint32 sum = 0;
int i;
uint16 answer = 0;
if (src_ipa) {
uint8 ph[8] = {0, };
for (i = 0; i < (IPV6_ADDR_LEN / 2); i++) {
sum += *((uint16 *)src_ipa);
src_ipa += 2;
}
for (i = 0; i < (IPV6_ADDR_LEN / 2); i++) {
sum += *((uint16 *)dst_ipa);
dst_ipa += 2;
}
*((uint32 *)ph) = hton32(ul_len);
*((uint32 *)(ph+4)) = 0;
ph[7] = prot;
startpos = (uint16 *)ph;
for (i = 0; i < 4; i++) {
sum += *startpos++;
}
}
startpos = (uint16 *)ul_data;
while (ul_len > 1) {
sum += *startpos++;
ul_len -= 2;
}
if (ul_len == 1) {
*((uint8 *)(&answer)) = *((uint8 *)startpos);
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return answer;
}
/*
* The length of the option including
* the type and length fields in units of 8 octets
*/
bcm_tlv_t *
parse_nd_options(void *buf, int buflen, uint key)
{
bcm_tlv_t *elt;
int totlen;
elt = (bcm_tlv_t*)buf;
totlen = buflen;
/* find tagged parameter */
while (totlen >= TLV_HDR_LEN) {
int len = elt->len * 8;
/* validate remaining totlen */
if ((elt->id == key) &&
(totlen >= len))
return (elt);
elt = (bcm_tlv_t*)((uint8*)elt + len);
totlen -= len;
}
return NULL;
}
/* returns 0 if tdls set up request or tdls discovery request */
int
bcm_l2_filter_block_tdls(osl_t *osh, void *pktbuf)
{
uint16 ethertype;
uint8 *data;
int datalen;
bool snap;
uint8 action_field;
if (get_pkt_ether_type(osh, pktbuf, &data, &datalen, &ethertype, &snap) != BCME_OK)
return BCME_ERROR;
if (ethertype != ETHER_TYPE_89_0D)
return BCME_ERROR;
/* validate payload type */
if (datalen < TDLS_PAYLOAD_TYPE_LEN + 2) {
L2_FILTER_ERROR(("bcm_l2_filter_block_tdls: wrong length for 89-0d eth frame %d\n",
datalen));
return BCME_ERROR;
}
/* validate payload type */
if (*data != TDLS_PAYLOAD_TYPE) {
L2_FILTER_ERROR(("bcm_l2_filter_block_tdls: wrong payload type for 89-0d"
" eth frame %d\n",
*data));
return BCME_ERROR;
}
data += TDLS_PAYLOAD_TYPE_LEN;
/* validate TDLS action category */
if (*data != TDLS_ACTION_CATEGORY_CODE) {
L2_FILTER_ERROR(("bcm_l2_filter_block_tdls: wrong TDLS Category %d\n", *data));
return BCME_ERROR;
}
data++;
action_field = *data;
if ((action_field == TDLS_SETUP_REQ) || (action_field == TDLS_DISCOVERY_REQ))
return BCME_OK;
return BCME_ERROR;
}

View File

@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Bloom filter support
*
* Copyright (C) 1999-2019, Broadcom.
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -18,14 +17,8 @@
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmbloom.c 788740 2018-11-13 21:45:01Z $
* <<Broadcom-WL-IPTag/Dual:>>
*/
#include <typedefs.h>
@@ -41,7 +34,7 @@
#include <string.h>
#ifndef ASSERT
#define ASSERT(exp)
#endif // endif
#endif
#endif /* !BCMDRIVER */
#include <bcmutils.h>
@@ -76,17 +69,16 @@ bcm_bloom_create(bcm_bloom_alloc_t alloc_cb,
err = BCME_NOMEM;
goto done;
}
memset(bp, 0, sizeof(*bp));
bp->cb_ctx = cb_ctx;
bp->max_hash = max_hash;
bp->hash = (*alloc_cb)(cb_ctx, sizeof(*bp->hash) * max_hash);
memset(bp->hash, 0, sizeof(*bp->hash) * max_hash);
if (!bp->hash) {
err = BCME_NOMEM;
goto done;
}
memset(bp->hash, 0, sizeof(*bp->hash) * max_hash);
if (filter_size > 0) {
bp->filter = (*alloc_cb)(cb_ctx, filter_size);
@@ -190,9 +182,7 @@ bcm_bloom_is_member(bcm_bloom_filter_t *bp,
pos = (*bp->hash[i])(bp->cb_ctx, i, tag, tag_len);
/* all bits must be set for a match */
CLANG_DIAGNOSTIC_PUSH_SUPPRESS_CAST()
if (isclr(buf, pos % BLOOM_BIT_LEN(buf_len))) {
CLANG_DIAGNOSTIC_POP()
err = BCME_NOTFOUND;
break;
}

View File

@@ -1,14 +1,14 @@
/*
* bcmevent read-only data shared by kernel or app layers
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,15 +16,9 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmevent.c 707287 2017-06-27 06:44:29Z $
* <<Broadcom-WL-IPTag/Dual:>>
*/
#include <typedefs.h>
@@ -44,6 +38,9 @@ typedef struct {
/* Use the actual name for event tracing */
#define BCMEVENT_NAME(_event) {(_event), #_event}
/* this becomes static data when all code is changed to use
* the bcmevent_get_name() API
*/
static const bcmevent_name_str_t bcmevent_names[] = {
BCMEVENT_NAME(WLC_E_SET_SSID),
BCMEVENT_NAME(WLC_E_JOIN),
@@ -84,6 +81,14 @@ static const bcmevent_name_str_t bcmevent_names[] = {
BCMEVENT_NAME(WLC_E_JOIN_START),
BCMEVENT_NAME(WLC_E_ROAM_START),
BCMEVENT_NAME(WLC_E_ASSOC_START),
#ifdef EXT_STA
BCMEVENT_NAME(WLC_E_RESET_COMPLETE),
BCMEVENT_NAME(WLC_E_JOIN_START),
BCMEVENT_NAME(WLC_E_ROAM_START),
BCMEVENT_NAME(WLC_E_ASSOC_START),
BCMEVENT_NAME(WLC_E_ASSOC_RECREATED),
BCMEVENT_NAME(WLC_E_SPEEDY_RECREATE_FAIL),
#endif /* EXT_STA */
#if defined(IBSS_PEER_DISCOVERY_EVENT)
BCMEVENT_NAME(WLC_E_IBSS_ASSOC),
#endif /* defined(IBSS_PEER_DISCOVERY_EVENT) */
@@ -104,14 +109,28 @@ static const bcmevent_name_str_t bcmevent_names[] = {
#endif
BCMEVENT_NAME(WLC_E_RSSI),
BCMEVENT_NAME(WLC_E_PFN_SCAN_COMPLETE),
BCMEVENT_NAME(WLC_E_EXTLOG_MSG),
BCMEVENT_NAME(WLC_E_ACTION_FRAME),
BCMEVENT_NAME(WLC_E_ACTION_FRAME_RX),
BCMEVENT_NAME(WLC_E_ACTION_FRAME_COMPLETE),
#if defined(NDIS)
BCMEVENT_NAME(WLC_E_PRE_ASSOC_IND),
BCMEVENT_NAME(WLC_E_PRE_REASSOC_IND),
BCMEVENT_NAME(WLC_E_CHANNEL_ADOPTED),
BCMEVENT_NAME(WLC_E_AP_STARTED),
BCMEVENT_NAME(WLC_E_DFS_AP_STOP),
BCMEVENT_NAME(WLC_E_DFS_AP_RESUME),
BCMEVENT_NAME(WLC_E_ASSOC_IND_NDIS),
BCMEVENT_NAME(WLC_E_REASSOC_IND_NDIS),
BCMEVENT_NAME(WLC_E_ACTION_FRAME_RX_NDIS),
BCMEVENT_NAME(WLC_E_AUTH_REQ),
BCMEVENT_NAME(WLC_E_IBSS_COALESCE),
#endif /* #if defined(NDIS) */
#ifdef BCMWAPI_WAI
BCMEVENT_NAME(WLC_E_WAI_STA_EVENT),
BCMEVENT_NAME(WLC_E_WAI_MSG),
#endif /* BCMWAPI_WAI */
BCMEVENT_NAME(WLC_E_ESCAN_RESULT),
BCMEVENT_NAME(WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE),
#ifdef WLP2P
@@ -124,9 +143,6 @@ static const bcmevent_name_str_t bcmevent_names[] = {
BCMEVENT_NAME(WLC_E_WAKE_EVENT),
BCMEVENT_NAME(WLC_E_DCS_REQUEST),
BCMEVENT_NAME(WLC_E_RM_COMPLETE),
#ifdef WLMEDIA_HTSF
BCMEVENT_NAME(WLC_E_HTSFSYNC),
#endif
BCMEVENT_NAME(WLC_E_OVERLAY_REQ),
BCMEVENT_NAME(WLC_E_CSA_COMPLETE_IND),
BCMEVENT_NAME(WLC_E_EXCESS_PM_WAKE_EVENT),
@@ -153,7 +169,7 @@ static const bcmevent_name_str_t bcmevent_names[] = {
#ifdef WLWNM
BCMEVENT_NAME(WLC_E_WNM_STA_SLEEP),
#endif /* WLWNM */
#if defined(WL_PROXDETECT)
#if defined(WL_PROXDETECT) || defined(RTT_SUPPORT)
BCMEVENT_NAME(WLC_E_PROXD),
#endif
BCMEVENT_NAME(WLC_E_CCA_CHAN_QUAL),
@@ -163,6 +179,9 @@ static const bcmevent_name_str_t bcmevent_names[] = {
#endif
BCMEVENT_NAME(WLC_E_PSTA_PRIMARY_INTF_IND),
BCMEVENT_NAME(WLC_E_TXFAIL_THRESH),
#ifdef WLAIBSS
BCMEVENT_NAME(WLC_E_AIBSS_TXFAIL),
#endif /* WLAIBSS */
#ifdef GSCAN_SUPPORT
BCMEVENT_NAME(WLC_E_PFN_GSCAN_FULL_RESULT),
BCMEVENT_NAME(WLC_E_PFN_SSID_EXT),
@@ -174,10 +193,17 @@ static const bcmevent_name_str_t bcmevent_names[] = {
BCMEVENT_NAME(WLC_E_BT_WIFI_HANDOVER_REQ),
#endif
#ifdef WLFBT
BCMEVENT_NAME(WLC_E_FBT_AUTH_REQ_IND),
BCMEVENT_NAME(WLC_E_FBT),
#endif /* WLFBT */
BCMEVENT_NAME(WLC_E_AUTHORIZED),
BCMEVENT_NAME(WLC_E_PROBREQ_MSG_RX),
#ifdef WLAWDL
BCMEVENT_NAME(WLC_E_AWDL_AW),
BCMEVENT_NAME(WLC_E_AWDL_ROLE),
BCMEVENT_NAME(WLC_E_AWDL_EVENT),
#endif /* WLAWDL */
BCMEVENT_NAME(WLC_E_CSA_START_IND),
BCMEVENT_NAME(WLC_E_CSA_DONE_IND),
BCMEVENT_NAME(WLC_E_CSA_FAILURE_IND),
@@ -186,11 +212,41 @@ static const bcmevent_name_str_t bcmevent_names[] = {
BCMEVENT_NAME(WLC_E_ALLOW_CREDIT_BORROW),
BCMEVENT_NAME(WLC_E_MSCH),
BCMEVENT_NAME(WLC_E_ULP),
BCMEVENT_NAME(WLC_E_NAN),
BCMEVENT_NAME(WLC_E_PKT_FILTER),
BCMEVENT_NAME(WLC_E_DMA_TXFLUSH_COMPLETE),
BCMEVENT_NAME(WLC_E_PSK_AUTH),
BCMEVENT_NAME(WLC_E_SDB_TRANSITION),
BCMEVENT_NAME(WLC_E_PFN_SCAN_BACKOFF),
BCMEVENT_NAME(WLC_E_PFN_BSSID_SCAN_BACKOFF),
BCMEVENT_NAME(WLC_E_AGGR_EVENT),
BCMEVENT_NAME(WLC_E_TVPM_MITIGATION),
BCMEVENT_NAME(WLC_E_SCAN),
BCMEVENT_NAME(WLC_E_SLOTTED_BSS_PEER_OP),
BCMEVENT_NAME(WLC_E_PHY_CAL),
#ifdef WL_NAN
BCMEVENT_NAME(WLC_E_NAN_CRITICAL),
BCMEVENT_NAME(WLC_E_NAN_NON_CRITICAL),
BCMEVENT_NAME(WLC_E_NAN),
#endif /* WL_NAN */
BCMEVENT_NAME(WLC_E_RPSNOA),
BCMEVENT_NAME(WLC_E_WA_LQM),
BCMEVENT_NAME(WLC_E_OBSS_DETECTION),
BCMEVENT_NAME(WLC_E_SC_CHAN_QUAL),
BCMEVENT_NAME(WLC_E_DYNSAR),
BCMEVENT_NAME(WLC_E_ROAM_CACHE_UPDATE),
BCMEVENT_NAME(WLC_E_AP_BCN_DRIFT),
BCMEVENT_NAME(WLC_E_PFN_SCAN_ALLGONE_EXT),
#ifdef WL_CLIENT_SAE
BCMEVENT_NAME(WLC_E_AUTH_START),
#endif /* WL_CLIENT_SAE */
#ifdef WL_TWT
BCMEVENT_NAME(WLC_E_TWT_SETUP),
BCMEVENT_NAME(WLC_E_TWT_TEARDOWN),
BCMEVENT_NAME(WLC_E_TWT_INFO_FRM)
#endif /* WL_TWT */
};
const char *bcmevent_get_name(uint event_type)
{
/* note: first coded this as a static const but some
@@ -287,11 +343,15 @@ is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype,
/* check length in bcmeth_hdr */
#ifdef BCMDONGLEHOST
/* temporary - header length not always set properly. When the below
* !BCMDONGLEHOST is in all branches that use trunk DHD, the code
* under BCMDONGLEHOST can be removed.
*/
evlen = (uint16)(pktend - (uint8 *)&bcm_event->bcm_hdr.version);
#else
evlen = ntoh16_ua((void *)&bcm_event->bcm_hdr.length);
#endif /* BCMDONGLEHOST */
evend = (uint8 *)&bcm_event->bcm_hdr.version + evlen;
if (evend != pktend) {
err = BCME_BADLEN;
@@ -342,7 +402,7 @@ is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype,
break;
case BCMILCP_BCM_SUBTYPE_DNGLEVENT:
#if defined(DNGL_EVENT_SUPPORT)
#if defined(HEALTH_CHECK) || defined(DNGL_EVENT_SUPPORT)
if ((pktlen < sizeof(bcm_dngl_event_t)) ||
(evend < ((uint8 *)bcm_event + sizeof(bcm_dngl_event_t)))) {
err = BCME_BADLEN;
@@ -372,7 +432,7 @@ is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype,
#else
err = BCME_UNSUPPORTED;
break;
#endif
#endif /* HEALTH_CHECK || DNGL_EVENT_SUPPORT */
default:
err = BCME_NOTFOUND;

View File

@@ -0,0 +1,88 @@
#
# Broadcom Proprietary and Confidential. Copyright (C) 2020,
# All Rights Reserved.
#
# This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
# the contents of this file may not be disclosed to third parties,
# copied or duplicated in any form, in whole or in part, without
# the prior written permission of Broadcom.
#
#
# <<Broadcom-WL-IPTag/Secret:>>
# This file should be seen only by internal builds because it will
# be mentioned only in internal filelists like brcm.flist.
# See extended comment bcminternal.mk for details.
BCMINTERNAL := 1
BCMINTERNAL_DFLAGS += -DDHD_NO_MOG
ifneq ($(CONFIG_BCMDHD_PCIE),)
# Enable Register access via dhd IOVAR
BCMINTERNAL_DFLAGS += -DDHD_PCIE_REG_ACCESS
# latency timestamping
BCMINTERNAL_DFLAGS += -DDHD_PKTTS
# Traffic Pattern Analysis on Socket Flow
BCMINTERNAL_DFLAGS += -DDHD_QOS_ON_SOCK_FLOW
# QoS unit testing support
BCMINTERNAL_DFLAGS += -DDHD_QOS_ON_SOCK_FLOW_UT
# Auto QOS
BCMINTERNAL_DFLAGS += -DWL_AUTO_QOS
ifneq ($(filter -DCUSTOMER_HW4, $(DHDCFLAGS)),)
# These will be moved to hw4 Makefile for 4389b0
BCMINTERNAL_DFLAGS += -DWBRC
BCMINTERNAL_DFLAGS += -DWLAN_ACCEL_BOOT
BCMINTERNAL_DFLAGS += -DDHD_HTPUT_TUNABLES
# BCMINTERNAL_DFLAGS += -DDHD_FIS_DUMP
# SCAN TYPES, if kernel < 4.17 ..back port support required
ifneq ($(CONFIG_CFG80211_SCANTYPE_BKPORT),)
DHDCFLAGS += -DWL_SCAN_TYPE
endif
# Jig builds
# No reset during dhd attach
BCMINTERNAL_DFLAGS += -DDHD_SKIP_DONGLE_RESET_IN_ATTACH
# Dongle Isolation will ensure no resets devreset ON/OFF
BCMINTERNAL_DFLAGS += -DDONGLE_ENABLE_ISOLATION
# Quiesce dongle using DB7 trap
BCMINTERNAL_DFLAGS += -DDHD_DONGLE_TRAP_IN_DETACH
# Collect socram during dongle init failurs for internal builds
BCMINTERNAL_DFLAGS += -DDEBUG_DNGL_INIT_FAIL
# Dongle reset during Wifi ON to keep in sane state
BCMINTERNAL_DFLAGS += -DFORCE_DONGLE_RESET_IN_DEVRESET_ON
# Perform Backplane Reset else FLR will happen
# BCMINTERNAL_DFLAGS += -DDHD_USE_BP_RESET_SS_CTRL
BCMINTERNAL_DFLAGS += -DWIFI_TURNOFF_DELAY=10
endif
# NCI_BUS support
BCMINTERNAL_DFLAGS += -DSOCI_NCI_BUS
endif
BCMINTERNAL_DFLAGS += -DDHD_BUS_MEM_ACCESS
# Support multiple chips
BCMINTERNAL_DFLAGS += -DSUPPORT_MULTIPLE_CHIPS
# Support unreleased chips
BCMINTERNAL_DFLAGS += -DUNRELEASEDCHIP
# Collect socram if readshared fails
BCMINTERNAL_DFLAGS += -DDEBUG_DNGL_INIT_FAIL
# Force enable memdump value to DUMP_MEMFILE if it is disabled
BCMINTERNAL_DFLAGS += -DDHD_INIT_DEFAULT_MEMDUMP
ifneq ($(filter -DDHD_QOS_ON_SOCK_FLOW,$(BCMINTERNAL_DFLAGS)),)
BCMINTERNAL_DHDOFILES += dhd_linux_sock_qos.o
endif
ifneq ($(filter -DSOCI_NCI_BUS,$(BCMINTERNAL_DFLAGS)),)
BCMINTERNAL_DHDOFILES += nciutils.o
endif
ifneq ($(filter -DWBRC,$(BCMINTERNAL_DFLAGS)),)
BCMINTERNAL_DHDOFILES += wb_regon_coordinator.o
endif
# vim: filetype=make shiftwidth=2

View File

@@ -0,0 +1,60 @@
#
# Broadcom Proprietary and Confidential. Copyright (C) 2020,
# All Rights Reserved.
#
# This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
# the contents of this file may not be disclosed to third parties,
# copied or duplicated in any form, in whole or in part, without
# the prior written permission of Broadcom.
#
#
# <<Broadcom-WL-IPTag/Secret:>>
# This file should be seen only by internal builds because it will
# be mentioned only in internal filelists like brcm.flist. The idea
# is that it will be conditionally included by makefiles using the
# "-include" syntax, with the result that internal builds will see
# this file and set BCMINTERNAL which will eventually result in a
# -DBCMINTERNAL option passed to the compiler along with possible
# other effects. External builds will never see it and it will be
# silently ignored.
#
# Any settings which should not be exposed to customers may be
# placed here. For instance, if we were working on a super-secret
# new feature in supersecret.c we could set a variable here like
# BCMINTERNAL_OBJECTS := supersecret.o
# and later say
# OBJECTS += $(BCMINTERNAL_OBJECTS)
# within the main makefile.
#
# The key point is that this file is never shipped to customers
# because it's present only in internal filelists so anything
# here is private.
BCMINTERNAL := 1
BCMINTERNAL_DFLAGS += -DBCMINTERNAL
BCMINTERNAL_DFLAGS += -DDHD_NO_MOG
# Support unreleased chips
BCMINTERNAL_DFLAGS += -DUNRELEASEDCHIP
ifneq ($(findstring -fwtrace,-$(TARGET)-),)
BCMINTERNAL_DFLAGS += -DDHD_FWTRACE
BCMINTERNAL_CFILES += dhd_fwtrace.c
endif
# support only for SDIO MFG Fedora builds
ifneq ($(findstring -sdstd-,-$(TARGET)-),)
ifneq ($(findstring -mfgtest-,-$(TARGET)-),)
BCMINTERNAL_DFLAGS += -DDHD_SPROM
BCMINTERNAL_CFILES += bcmsrom.c bcmotp.c
endif
endif
ifneq ($(findstring -pciefd-,$(TARGET)-),)
# NCI_BUS support
BCMINTERNAL_DFLAGS += -DSOCI_NCI_BUS -DBOOKER_NIC400_INF
BCMINTERNAL_CFILES += nciutils.c
endif
# vim: filetype=make shiftwidth=2

View File

@@ -2,14 +2,14 @@
* BCMSDH interface glue
* implement bcmsdh API for SDIOH driver
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -17,15 +17,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmsdh.c 671319 2016-11-21 14:27:29Z $
* $Id$
*/
/**
@@ -40,6 +36,9 @@
#include <bcmutils.h>
#include <hndsoc.h>
#include <siutils.h>
#if !defined(BCMDONGLEHOST)
#include <bcmsrom.h>
#endif /* !defined(BCMDONGLEHOST) */
#include <osl.h>
#include <bcmsdh.h> /* BRCM API for SDIO clients (such as wl, dhd) */
@@ -47,7 +46,7 @@
#include <sbsdio.h> /* SDIO device core hardware definitions. */
#include <sdio.h> /* SDIO Device and Protocol Specs */
#if defined(BT_OVER_SDIO)
#if defined (BT_OVER_SDIO)
#include <dhd_bt_interface.h>
#endif /* defined (BT_OVER_SDIO) */
@@ -57,13 +56,16 @@ const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL;
/* local copy of bcm sd handler */
bcmsdh_info_t * l_bcmsdh = NULL;
#if defined(BT_OVER_SDIO)
#if defined (BT_OVER_SDIO)
struct sdio_func *func_f3 = NULL;
static f3intr_handler processf3intr = NULL;
static dhd_hang_notification process_dhd_hang_notification = NULL;
static dhd_hang_state_t g_dhd_hang_state = NO_HANG_STATE;
#endif /* defined (BT_OVER_SDIO) */
#if defined(NDIS) && (NDISVER < 0x0630)
extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd);
#endif
#if defined(OOB_INTR_ONLY) && defined(HW_OOB) || defined(FORCE_WOWLAN)
extern int
@@ -76,7 +78,7 @@ bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable)
}
#endif
#if defined(BT_OVER_SDIO)
#if defined (BT_OVER_SDIO)
void bcmsdh_btsdio_process_hang_state(dhd_hang_state_t new_state)
{
bool state_change = false;
@@ -97,6 +99,7 @@ void bcmsdh_btsdio_process_hang_state(dhd_hang_state_t new_state)
if (HANG_RECOVERY_STATE == new_state ||
NO_HANG_STATE == new_state)
state_change = true;
break;
case HANG_RECOVERY_STATE:
@@ -173,12 +176,12 @@ bcmsdh_attach(osl_t *osh, void *sdioh, ulong *regsva)
bcmsdh->sdioh = sdioh;
bcmsdh->osh = osh;
bcmsdh->init_success = TRUE;
*regsva = SI_ENUM_BASE;
*regsva = si_enum_base(0);
bcmsdh_force_sbwad_calc(bcmsdh, FALSE);
/* Report the BAR, to fix if needed */
bcmsdh->sbwad = SI_ENUM_BASE;
bcmsdh->sbwad = si_enum_base(0);
/* save the handler locally */
l_bcmsdh = bcmsdh;
@@ -192,6 +195,10 @@ bcmsdh_detach(osl_t *osh, void *sdh)
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
if (bcmsdh != NULL) {
#if defined(NDIS) && (NDISVER < 0x0630)
if (bcmsdh->sdioh)
sdioh_detach(osh, bcmsdh->sdioh);
#endif
MFREE(osh, bcmsdh, sizeof(bcmsdh_info_t));
}
@@ -202,7 +209,7 @@ bcmsdh_detach(osl_t *osh, void *sdh)
int
bcmsdh_iovar_op(void *sdh, const char *name,
void *params, int plen, void *arg, int len, bool set)
void *params, uint plen, void *arg, uint len, bool set)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
return sdioh_iovar_op(bcmsdh->sdioh, name, params, plen, arg, len, set);
@@ -228,9 +235,17 @@ bcmsdh_intr_enable(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
#ifdef BCMSPI_ANDROID
uint32 data;
#endif /* BCMSPI_ANDROID */
ASSERT(bcmsdh);
status = sdioh_interrupt_set(bcmsdh->sdioh, TRUE);
#ifdef BCMSPI_ANDROID
data = bcmsdh_cfg_read_word(sdh, 0, 4, NULL);
data |= 0xE0E70000;
bcmsdh_cfg_write_word(sdh, 0, 4, data, NULL);
#endif /* BCMSPI_ANDROID */
return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
}
@@ -239,9 +254,17 @@ bcmsdh_intr_disable(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
#ifdef BCMSPI_ANDROID
uint32 data;
#endif /* BCMSPI_ANDROID */
ASSERT(bcmsdh);
status = sdioh_interrupt_set(bcmsdh->sdioh, FALSE);
#ifdef BCMSPI_ANDROID
data = bcmsdh_cfg_read_word(sdh, 0, 4, NULL);
data &= ~0xE0E70000;
bcmsdh_cfg_write_word(sdh, 0, 4, data, NULL);
#endif /* BCMSPI_ANDROID */
return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
}
@@ -275,7 +298,7 @@ bcmsdh_intr_dereg(void *sdh)
return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
}
#if defined(DHD_DEBUG)
#if defined(DHD_DEBUG) || defined(BCMDBG)
bool
bcmsdh_intr_pending(void *sdh)
{
@@ -286,7 +309,6 @@ bcmsdh_intr_pending(void *sdh)
}
#endif
int
bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh)
{
@@ -412,7 +434,6 @@ bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *er
addr, data));
}
int
bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length)
{
@@ -495,6 +516,11 @@ bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set)
/* invalidate cached window var */
bcmsdh->sbwad = 0;
#ifdef BCMDBG
if (err)
BCMSDH_ERROR(("%s: error setting address window %08x\n",
__FUNCTION__, address));
#endif /* BCMDBG */
}
return err;
@@ -514,7 +540,7 @@ bcmsdh_reg_read(void *sdh, uintptr addr, uint size)
ASSERT(bcmsdh->init_success);
if (bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)) {
if (bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, bcmsdh->force_sbwad_calc)) {
bcmsdh->regfail = TRUE; // terence 20130621: prevent dhd_dpc in dead lock
return 0xFFFFFFFF;
}
@@ -531,6 +557,7 @@ bcmsdh_reg_read(void *sdh, uintptr addr, uint size)
BCMSDH_INFO(("uint32data = 0x%x\n", word));
/* if ok, return appropriately masked word */
/* XXX Masking was put in for NDIS port, remove if not needed */
if (SDIOH_API_SUCCESS(status)) {
switch (size) {
case sizeof(uint8):
@@ -715,16 +742,57 @@ bcmsdh_stop(void *sdh)
int
bcmsdh_waitlockfree(void *sdh)
{
#ifdef LINUX
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
return sdioh_waitlockfree(bcmsdh->sdioh);
#else
return 0;
#endif
}
int
bcmsdh_query_device(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
#if defined(BCMDONGLEHOST)
bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0;
#else
uint8 *fn0cis[1];
int err;
char *vars;
uint varsz;
osl_t *osh = bcmsdh->osh;
bcmsdh->vendevid = ~(0);
if (!(fn0cis[0] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
BCMSDH_ERROR(("%s: CIS malloc failed\n", __FUNCTION__));
return (bcmsdh->vendevid);
}
bzero(fn0cis[0], SBSDIO_CIS_SIZE_LIMIT);
if ((err = bcmsdh_cis_read(sdh, 0, fn0cis[0], SBSDIO_CIS_SIZE_LIMIT))) {
BCMSDH_ERROR(("%s: CIS read err %d, report unknown BRCM device\n",
__FUNCTION__, err));
bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0;
MFREE(osh, fn0cis[0], SBSDIO_CIS_SIZE_LIMIT);
return (bcmsdh->vendevid);
}
if (!err) {
if ((err = srom_parsecis(NULL, osh, fn0cis, 1, &vars, &varsz))) {
BCMSDH_ERROR(("%s: Error parsing CIS = %d\n", __FUNCTION__, err));
} else {
bcmsdh->vendevid = (getintvar(vars, "vendid") << 16) |
getintvar(vars, "devid");
MFREE(osh, vars, varsz);
}
}
MFREE(osh, fn0cis[0], SBSDIO_CIS_SIZE_LIMIT);
#endif /* BCMDONGLEHOST */
return (bcmsdh->vendevid);
}
@@ -747,6 +815,7 @@ bcmsdh_reset(bcmsdh_info_t *sdh)
return sdioh_sdio_reset(bcmsdh->sdioh);
}
/* XXX For use by NDIS port, remove if not needed. */
void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh)
{
ASSERT(sdh);
@@ -757,7 +826,13 @@ void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh)
uint32
bcmsdh_get_dstatus(void *sdh)
{
#ifdef BCMSPI
bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
return sdioh_get_dstatus(sd);
#else
return 0;
#endif /* BCMSPI */
}
uint32
bcmsdh_cur_sbwad(void *sdh)
@@ -786,9 +861,25 @@ bcmsdh_force_sbwad_calc(void *sdh, bool force)
void
bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev)
{
#ifdef BCMSPI
bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
sdioh_chipinfo(sd, chip, chiprev);
#else
return;
#endif /* BCMSPI */
}
#ifdef BCMSPI
void
bcmsdh_dwordmode(void *sdh, bool set)
{
bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
sdioh_dwordmode(sd, set);
return;
}
#endif /* BCMSPI */
int
bcmsdh_sleep(void *sdh, bool enab)
@@ -845,3 +936,12 @@ bcmsdh_set_mode(void *sdh, uint mode)
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
return (sdioh_set_mode(bcmsdh->sdioh, mode));
}
#ifdef PKT_STATICS
uint32
bcmsdh_get_spend_time(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
return (sdioh_get_spend_time(bcmsdh->sdioh));
}
#endif

View File

@@ -1,14 +1,14 @@
/*
* SDIO access interface for drivers - linux specific (pci only)
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,15 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmsdh_linux.c 672609 2016-11-29 07:00:46Z $
* $Id$
*/
/**
@@ -84,7 +80,13 @@ typedef struct bcmsdh_os_info {
} bcmsdh_os_info_t;
/* debugging macros */
#define SDLX_MSG(x) printf x
#ifdef BCMDBG_ERR
#define SDLX_ERR(x) printf x
#define SDLX_MSG(x) printf x
#else
#define SDLX_ERR(x) printf x
#define SDLX_MSG(x) printf x
#endif /* BCMDBG_ERR */
/**
* Checks to see if vendor and device IDs match a supported SDIO Host Controller.
@@ -93,6 +95,23 @@ bool
bcmsdh_chipmatch(uint16 vendor, uint16 device)
{
/* Add other vendors and devices as required */
#ifdef BCMINTERNAL
#ifdef BCMSDIOH_BCM
if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) {
return (TRUE);
}
if (device == BCM_SDIOH_ID && vendor == VENDOR_BROADCOM) {
return (TRUE);
}
if (device == BCM4710_DEVICE_ID && vendor == VENDOR_BROADCOM) {
return (TRUE);
}
/* For now still accept the old devid */
if (device == 0x4380 && vendor == VENDOR_BROADCOM) {
return (TRUE);
}
#endif /* BCMSDIOH_BCM */
#endif /* BCMINTERNAL */
#ifdef BCMSDIOH_STD
/* Check for Arasan host controller */
@@ -123,6 +142,12 @@ bcmsdh_chipmatch(uint16 vendor, uint16 device)
return (TRUE);
}
#ifdef BCMINTERNAL
/* Check for Jinvani (C-Guys) host controller */
if (device == JINVANI_SDIOH_ID && vendor == VENDOR_JINVANI) {
return (TRUE);
}
#endif /* BCMINTERNAL */
#endif /* BCMSDIOH_STD */
#ifdef BCMSDIOH_SPI
/* This is the PciSpiHost. */
@@ -131,8 +156,28 @@ bcmsdh_chipmatch(uint16 vendor, uint16 device)
return (TRUE);
}
#ifdef BCMINTERNAL
/* This is the SPI Host for QT. */
if (device == BCM_SPIH_ID && vendor == VENDOR_BROADCOM) {
printf("Found SPI Host Controller\n");
return (TRUE);
}
#endif /* BCMINTERNAL */
#endif /* BCMSDIOH_SPI */
#ifdef BCMINTERNAL
/*
* XXX - This is a hack to get the GPL SdioLinux driver to load on Arasan/x86
* This is accomplished by installing a PciSpiHost into the system alongside the
* Arasan controller. The PciSpiHost is just used to get BCMSDH loaded.
*/
#ifdef BCMSDH_FD
if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) {
printf("Found SdioLinux Host Controller\n");
return (TRUE);
}
#endif /* BCMSDH_FD */
#endif /* BCMINTERNAL */
return (FALSE);
}
@@ -146,12 +191,12 @@ void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint
bcmsdh = bcmsdh_attach(osh, sdioh, &regs);
if (bcmsdh == NULL) {
SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
SDLX_ERR(("%s: bcmsdh_attach failed\n", __FUNCTION__));
goto err;
}
bcmsdh_osinfo = MALLOC(osh, sizeof(bcmsdh_os_info_t));
if (bcmsdh_osinfo == NULL) {
SDLX_MSG(("%s: failed to allocate bcmsdh_os_info_t\n", __FUNCTION__));
SDLX_ERR(("%s: failed to allocate bcmsdh_os_info_t\n", __FUNCTION__));
goto err;
}
bzero((char *)bcmsdh_osinfo, sizeof(bcmsdh_os_info_t));
@@ -171,7 +216,7 @@ void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint
bcmsdh_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter_info,
&bcmsdh_osinfo->oob_irq_flags);
if (bcmsdh_osinfo->oob_irq_num < 0) {
SDLX_MSG(("%s: Host OOB irq is not defined\n", __FUNCTION__));
SDLX_ERR(("%s: Host OOB irq is not defined\n", __FUNCTION__));
goto err;
}
#endif /* defined(BCMLXSDMMC) */
@@ -182,7 +227,7 @@ void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint
bcmsdh_osinfo->context = drvinfo.probe((vendevid >> 16), (vendevid & 0xFFFF), bus_num,
slot_num, 0, bus_type, (void *)regs, osh, bcmsdh);
if (bcmsdh_osinfo->context == NULL) {
SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
SDLX_ERR(("%s: device attach failed\n", __FUNCTION__));
goto err;
}
@@ -285,7 +330,7 @@ bcmsdh_register(bcmsdh_driver_t *driver)
SDLX_MSG(("%s: register client driver\n", __FUNCTION__));
error = bcmsdh_register_client_driver();
if (error)
SDLX_MSG(("%s: failed %d\n", __FUNCTION__, error));
SDLX_ERR(("%s: failed %d\n", __FUNCTION__, error));
return error;
}
@@ -324,7 +369,14 @@ bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *bcmsdh)
return bcmsdh_osinfo->dev_wake_enabled;
}
#if defined(OOB_INTR_ONLY)
#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
int bcmsdh_get_oob_intr_num(bcmsdh_info_t *bcmsdh)
{
bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
return bcmsdh_osinfo->oob_irq_num;
}
void bcmsdh_oob_intr_set(bcmsdh_info_t *bcmsdh, bool enable)
{
unsigned long flags;
@@ -345,14 +397,27 @@ void bcmsdh_oob_intr_set(bcmsdh_info_t *bcmsdh, bool enable)
spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags);
}
#ifdef ENABLE_WAKEUP_PKT_DUMP
extern volatile bool dhd_mmc_suspend;
extern volatile bool dhd_mmc_wake;
#endif /* ENABLE_WAKEUP_PKT_DUMP */
static irqreturn_t wlan_oob_irq(int irq, void *dev_id)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)dev_id;
bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
#ifndef BCMSPI_ANDROID
bcmsdh_oob_intr_set(bcmsdh, FALSE);
#endif /* !BCMSPI_ANDROID */
bcmsdh_osinfo->oob_irq_handler(bcmsdh_osinfo->oob_irq_handler_context);
#ifdef ENABLE_WAKEUP_PKT_DUMP
if (dhd_mmc_suspend) {
dhd_mmc_wake = TRUE;
}
#endif /* ENABLE_WAKEUP_PKT_DUMP */
return IRQ_HANDLED;
}
@@ -363,15 +428,15 @@ int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handl
bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
if (bcmsdh_osinfo->oob_irq_registered) {
SDLX_MSG(("%s: irq is already registered\n", __FUNCTION__));
SDLX_ERR(("%s: irq is already registered\n", __FUNCTION__));
return -EBUSY;
}
#ifdef HW_OOB
printf("%s: HW_OOB irq=%d flags=0x%X\n", __FUNCTION__,
(int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags);
SDLX_MSG(("%s: HW_OOB irq=%d flags=0x%X\n", __FUNCTION__,
(int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags));
#else
printf("%s: SW_OOB irq=%d flags=0x%X\n", __FUNCTION__,
(int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags);
SDLX_MSG(("%s: SW_OOB irq=%d flags=0x%X\n", __FUNCTION__,
(int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags));
#endif
bcmsdh_osinfo->oob_irq_handler = oob_irq_handler;
bcmsdh_osinfo->oob_irq_handler_context = oob_irq_handler_context;
@@ -385,7 +450,7 @@ int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handl
bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh);
#endif /* defined(CONFIG_ARCH_ODIN) */
if (err) {
SDLX_MSG(("%s: request_irq failed with %d\n", __FUNCTION__, err));
SDLX_ERR(("%s: request_irq failed with %d\n", __FUNCTION__, err));
bcmsdh_osinfo->oob_irq_enabled = FALSE;
bcmsdh_osinfo->oob_irq_registered = FALSE;
return err;
@@ -395,11 +460,17 @@ int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handl
SDLX_MSG(("%s: disable_irq_wake\n", __FUNCTION__));
bcmsdh_osinfo->oob_irq_wake_enabled = FALSE;
#else
err = enable_irq_wake(bcmsdh_osinfo->oob_irq_num);
if (err)
SDLX_MSG(("%s: enable_irq_wake failed with %d\n", __FUNCTION__, err));
else
bcmsdh_osinfo->oob_irq_wake_enabled = TRUE;
#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
if (device_may_wakeup(bcmsdh_osinfo->dev)) {
#endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
err = enable_irq_wake(bcmsdh_osinfo->oob_irq_num);
if (err)
SDLX_ERR(("%s: enable_irq_wake failed with %d\n", __FUNCTION__, err));
else
bcmsdh_osinfo->oob_irq_wake_enabled = TRUE;
#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
}
#endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
#endif
return 0;
@@ -416,9 +487,15 @@ void bcmsdh_oob_intr_unregister(bcmsdh_info_t *bcmsdh)
return;
}
if (bcmsdh_osinfo->oob_irq_wake_enabled) {
err = disable_irq_wake(bcmsdh_osinfo->oob_irq_num);
if (!err)
bcmsdh_osinfo->oob_irq_wake_enabled = FALSE;
#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
if (device_may_wakeup(bcmsdh_osinfo->dev)) {
#endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
err = disable_irq_wake(bcmsdh_osinfo->oob_irq_num);
if (!err)
bcmsdh_osinfo->oob_irq_wake_enabled = FALSE;
#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
}
#endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
}
if (bcmsdh_osinfo->oob_irq_enabled) {
disable_irq(bcmsdh_osinfo->oob_irq_num);
@@ -427,9 +504,10 @@ void bcmsdh_oob_intr_unregister(bcmsdh_info_t *bcmsdh)
free_irq(bcmsdh_osinfo->oob_irq_num, bcmsdh);
bcmsdh_osinfo->oob_irq_registered = FALSE;
}
#endif
#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
/* Module parameters specific to each host-controller driver */
/* XXX Need to move these to where they really belong! */
extern uint sd_msglevel; /* Debug message level */
module_param(sd_msglevel, uint, 0);
@@ -478,11 +556,11 @@ EXPORT_SYMBOL(bcmsdh_intr_disable);
EXPORT_SYMBOL(bcmsdh_intr_reg);
EXPORT_SYMBOL(bcmsdh_intr_dereg);
#if defined(DHD_DEBUG)
#if defined(DHD_DEBUG) || defined(BCMDBG)
EXPORT_SYMBOL(bcmsdh_intr_pending);
#endif
#if defined(BT_OVER_SDIO)
#if defined (BT_OVER_SDIO)
EXPORT_SYMBOL(bcmsdh_btsdio_interface_init);
#endif /* defined (BT_OVER_SDIO) */

View File

@@ -1,14 +1,14 @@
/*
* BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,15 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Proprietary,Open:>>
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmsdh_sdmmc.c 710913 2017-07-14 10:17:51Z $
* $Id$
*/
#include <typedefs.h>
@@ -38,22 +34,7 @@
#include <sdiovar.h> /* ioctl/iovars */
#include <linux/mmc/core.h>
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 0, 0))
#include <drivers/mmc/core/host.h>
void
mmc_host_clk_hold(struct mmc_host *host)
{
BCM_REFERENCE(host);
return;
}
void
mmc_host_clk_release(struct mmc_host *host)
{
BCM_REFERENCE(host);
return;
}
#elif (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 0, 8))
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 0, 8))
#include <drivers/mmc/core/host.h>
#else
#include <linux/mmc/host.h>
@@ -66,12 +47,35 @@ mmc_host_clk_release(struct mmc_host *host)
#include <dhd.h>
#include <dhd_dbg.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_PM_SLEEP)
#include <linux/suspend.h>
extern volatile bool dhd_mmc_suspend;
#endif
#include "bcmsdh_sdmmc.h"
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 0, 0)) || \
(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
static inline void
mmc_host_clk_hold(struct mmc_host *host)
{
BCM_REFERENCE(host);
return;
}
static inline void
mmc_host_clk_release(struct mmc_host *host)
{
BCM_REFERENCE(host);
return;
}
static inline unsigned int
mmc_host_clk_rate(struct mmc_host *host)
{
return host->ios.clock;
}
#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(3, 0, 0) */
#ifndef BCMSDH_MODULE
extern int sdio_function_init(void);
extern void sdio_function_cleanup(void);
@@ -83,8 +87,12 @@ static void IRQHandlerF2(struct sdio_func *func);
#endif /* !defined(OOB_INTR_ONLY) */
static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr);
#if defined(ENABLE_INSMOD_NO_FW_LOAD) && !defined(BUS_POWER_RESTORE)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
extern int mmc_sw_reset(struct mmc_host *host);
#else
extern int sdio_reset_comm(struct mmc_card *card);
#endif
#endif
#ifdef GLOBAL_SDMMC_INSTANCE
extern PBCMSDH_SDMMC_INSTANCE gInstance;
#endif
@@ -105,7 +113,7 @@ uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */
uint sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE;
uint sd_f1_blocksize = CUSTOM_SDIO_F1_BLKSIZE;
#if defined(BT_OVER_SDIO)
#if defined (BT_OVER_SDIO)
uint sd_f3_blocksize = 64;
#endif /* defined (BT_OVER_SDIO) */
@@ -114,7 +122,7 @@ uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */
uint sd_power = 1; /* Default to SD Slot powered ON */
uint sd_clock = 1; /* Default to SD Clock turned ON */
uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */
uint sd_msglevel = 0x01;
uint sd_msglevel = SDH_ERROR_VAL;
uint sd_use_dma = TRUE;
#ifndef CUSTOM_RXCHAIN
@@ -130,11 +138,12 @@ DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait);
#define MMC_SDIO_ABORT_RETRY_LIMIT 5
int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data);
#ifdef NOTYET
static int
sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data);
#endif /* NOTYET */
void sdmmc_set_clock_rate(sdioh_info_t *sd, uint hz);
uint sdmmc_get_clock_rate(sdioh_info_t *sd);
void sdmmc_set_clock_divisor(sdioh_info_t *sd, uint sd_div);
#if defined(BT_OVER_SDIO)
#if defined (BT_OVER_SDIO)
extern
void sdioh_sdmmc_card_enable_func_f3(sdioh_info_t *sd, struct sdio_func *func)
{
@@ -143,6 +152,10 @@ void sdioh_sdmmc_card_enable_func_f3(sdioh_info_t *sd, struct sdio_func *func)
}
#endif /* defined (BT_OVER_SDIO) */
void sdmmc_set_clock_rate(sdioh_info_t *sd, uint hz);
uint sdmmc_get_clock_rate(sdioh_info_t *sd);
void sdmmc_set_clock_divisor(sdioh_info_t *sd, uint sd_div);
static int
sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd)
{
@@ -215,7 +228,7 @@ sdioh_attach(osl_t *osh, struct sdio_func *func)
sd->func[func->num] = func;
#endif
#if defined(BT_OVER_SDIO)
#if defined (BT_OVER_SDIO)
sd->func[3] = NULL;
#endif /* defined (BT_OVER_SDIO) */
@@ -240,6 +253,9 @@ sdioh_attach(osl_t *osh, struct sdio_func *func)
}
sdio_claim_host(sd->func[2]);
if ((func->device == BCM43362_CHIP_ID || func->device == BCM4330_CHIP_ID) &&
sd_f2_blocksize > 128)
sd_f2_blocksize = 128;
sd->client_block_size[2] = sd_f2_blocksize;
printf("%s: set sd_f2_blocksize %d\n", __FUNCTION__, sd_f2_blocksize);
err_ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize);
@@ -262,7 +278,6 @@ fail:
return NULL;
}
extern SDIOH_API_RC
sdioh_detach(osl_t *osh, sdioh_info_t *sd)
{
@@ -315,7 +330,7 @@ sdioh_enable_func_intr(sdioh_info_t *sd)
/* Enable F1 and F2 interrupts, clear master enable */
reg &= ~INTR_CTL_MASTER_EN;
reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN);
#if defined(BT_OVER_SDIO)
#if defined (BT_OVER_SDIO)
reg |= (INTR_CTL_FUNC3_EN);
#endif /* defined (BT_OVER_SDIO) */
sdio_writeb(sd->func[0], reg, SDIOD_CCCR_INTEN, &err);
@@ -438,7 +453,7 @@ sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
return SDIOH_API_RC_SUCCESS;
}
#if defined(DHD_DEBUG)
#if defined(DHD_DEBUG) || defined(BCMDBG)
extern bool
sdioh_interrupt_pending(sdioh_info_t *sd)
{
@@ -480,28 +495,34 @@ const bcm_iovar_t sdioh_iovars[] = {
{"sd_ints", IOV_USEINTS, 0, 0, IOVT_BOOL, 0 },
{"sd_numints", IOV_NUMINTS, 0, 0, IOVT_UINT32, 0 },
{"sd_numlocalints", IOV_NUMLOCALINTS, 0, 0, IOVT_UINT32, 0 },
#ifdef BCMINTERNAL
{"sd_hostreg", IOV_HOSTREG, 0, 0, IOVT_BUFFER, sizeof(sdreg_t) },
{"sd_devreg", IOV_DEVREG, 0, 0, IOVT_BUFFER, sizeof(sdreg_t) },
#endif /* BCMINTERNAL */
{"sd_divisor", IOV_DIVISOR, 0, 0, IOVT_UINT32, 0 },
{"sd_power", IOV_POWER, 0, 0, IOVT_UINT32, 0 },
{"sd_clock", IOV_CLOCK, 0, 0, IOVT_UINT32, 0 },
{"sd_mode", IOV_SDMODE, 0, 0, IOVT_UINT32, 100},
{"sd_highspeed", IOV_HISPEED, 0, 0, IOVT_UINT32, 0 },
{"sd_rxchain", IOV_RXCHAIN, 0, 0, IOVT_BOOL, 0 },
#ifdef BCMDBG
{"sd_hciregs", IOV_HCIREGS, 0, 0, IOVT_BUFFER, 0 },
#endif
{NULL, 0, 0, 0, 0, 0 }
};
int
sdioh_iovar_op(sdioh_info_t *si, const char *name,
void *params, int plen, void *arg, int len, bool set)
void *params, int plen, void *arg, uint len, bool set)
{
const bcm_iovar_t *vi = NULL;
int bcmerror = 0;
int val_size;
uint val_size;
int32 int_val = 0;
bool bool_val;
uint32 actionid;
ASSERT(name);
ASSERT(len >= 0);
/* Get must have return space; Set does not take qualifiers */
ASSERT(set || (arg && len));
@@ -517,6 +538,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name,
if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0)
goto exit;
/* XXX Copied from dhd, copied from wl; certainly overkill here? */
/* Set up params so get and set can share the convenience variables */
if (params == NULL) {
params = arg;
@@ -577,6 +599,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name,
break;
}
/* XXX These hardcoded sizes are a hack, remove after proper CIS parsing. */
switch (func) {
case 0: maxsize = 32; break;
case 1: maxsize = BLOCK_SIZE_4318; break;
@@ -699,16 +722,102 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name,
int_val = (int32)0;
bcopy(&int_val, arg, val_size);
break;
#ifdef BCMINTERNAL
case IOV_GVAL(IOV_HOSTREG):
{
/* XXX Should copy for alignment reasons */
sdreg_t *sd_ptr = (sdreg_t *)params;
if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
bcmerror = BCME_BADARG;
break;
}
sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__,
(sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
sd_ptr->offset));
if (sd_ptr->offset & 1)
int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */
else if (sd_ptr->offset & 2)
int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */
else
int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */
bcopy(&int_val, arg, sizeof(int_val));
break;
}
case IOV_SVAL(IOV_HOSTREG):
{
/* XXX Should copy for alignment reasons */
sdreg_t *sd_ptr = (sdreg_t *)params;
if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
bcmerror = BCME_BADARG;
break;
}
sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value,
(sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
sd_ptr->offset));
break;
}
case IOV_GVAL(IOV_DEVREG):
{
/* XXX Should copy for alignment reasons */
sdreg_t *sd_ptr = (sdreg_t *)params;
uint8 data = 0;
if ((uint)sd_ptr->func > si->num_funcs) {
bcmerror = BCME_BADARG;
break;
}
if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) {
bcmerror = BCME_SDIO_ERROR;
break;
}
int_val = (int)data;
bcopy(&int_val, arg, sizeof(int_val));
break;
}
case IOV_SVAL(IOV_DEVREG):
{
/* XXX Should copy for alignment reasons */
sdreg_t *sd_ptr = (sdreg_t *)params;
uint8 data = (uint8)sd_ptr->value;
if ((uint)sd_ptr->func > si->num_funcs) {
bcmerror = BCME_BADARG;
break;
}
if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) {
bcmerror = BCME_SDIO_ERROR;
break;
}
break;
}
#endif /* BCMINTERNAL */
default:
bcmerror = BCME_UNSUPPORTED;
break;
}
exit:
/* XXX Remove protective lock after clients all clean... */
return bcmerror;
}
#if (defined(OOB_INTR_ONLY) && defined(HW_OOB)) || defined(FORCE_WOWLAN)
/*
* XXX dhd -i eth0 sd_devreg 0 0xf2 0x3
*/
SDIOH_API_RC
sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
@@ -717,11 +826,7 @@ sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
uint8 data;
if (enable)
#ifdef HW_OOB_LOW_LEVEL
data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
#else
data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI;
#endif
else
data = SDIO_SEPINT_ACT_HI; /* disable hw oob interrupt */
@@ -813,8 +918,6 @@ sdioh_cisaddr_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 offset)
return SDIOH_API_RC_FAIL;
}
sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func]));
if (sdioh_sdmmc_card_regread (sd, 0, sd->func_cis_ptr[func]+offset, 1, &foo) < 0) {
sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__));
return SDIOH_API_RC_FAIL;
@@ -847,7 +950,7 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by
* as a special case.
*/
if (regaddr == SDIOD_CCCR_IOEN) {
#if defined(BT_OVER_SDIO)
#if defined (BT_OVER_SDIO)
do {
if (sd->func[3]) {
sd_info(("bcmsdh_sdmmc F3: *byte 0x%x\n", *byte));
@@ -912,13 +1015,17 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by
}
sdio_release_host(sd->func[2]);
}
#if defined(BT_OVER_SDIO)
#if defined (BT_OVER_SDIO)
} while (0);
#endif /* defined (BT_OVER_SDIO) */
}
#if defined(MMC_SDIO_ABORT)
/* to allow abort command through F1 */
else if (regaddr == SDIOD_CCCR_IOABORT) {
/* XXX Because of SDIO3.0 host issue on Manta,
* sometimes the abort fails.
* Retrying again will fix this issue.
*/
while (sdio_abort_retry--) {
if (sd->func[func]) {
sdio_claim_host(sd->func[func]);
@@ -936,7 +1043,6 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by
}
}
#endif /* MMC_SDIO_ABORT */
/* to allow abort command through F1 */
#if defined(SDIO_ISR_THREAD)
else if (regaddr == SDIOD_CCCR_INTR_EXTN) {
while (sdio_abort_retry--) {
@@ -989,7 +1095,14 @@ sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *by
}
if (err_ret) {
if ((regaddr == 0x1001F) && ((err_ret == -ETIMEDOUT) || (err_ret == -EILSEQ))) {
if ((regaddr == 0x1001F) && ((err_ret == -ETIMEDOUT) || (err_ret == -EILSEQ)
|| (err_ret == -EIO))) {
/* XXX: Read/Write to SBSDIO_FUNC1_SLEEPCSR could return -110(timeout)
* or -84(CRC) error in case the host tries to wake the device up.
* Skip error log message if err code is -110 or -84 when accessing
* to SBSDIO_FUNC1_SLEEPCSR to avoid QA misunderstand and DHD shoul
* print error log message if retry count over the MAX_KSO_ATTEMPTS.
*/
} else {
sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
rw ? "Write" : "Read", func, regaddr, *byte, err_ret));
@@ -1016,6 +1129,14 @@ sdioh_set_mode(sdioh_info_t *sd, uint mode)
return (sd->txglom_mode);
}
#ifdef PKT_STATICS
uint32
sdioh_get_spend_time(sdioh_info_t *sd)
{
return (sd->sdio_spent_time_us);
}
#endif
extern SDIOH_API_RC
sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr,
uint32 *word, uint nbytes)
@@ -1128,7 +1249,9 @@ sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func
DHD_PM_RESUME_WAIT(sdioh_request_packet_wait);
DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
#ifndef PKT_STATICS
if (sd_msglevel & SDH_COST_VAL)
#endif
osl_do_gettimeofday(&before);
blk_size = sd->client_block_size[func];
@@ -1168,7 +1291,9 @@ sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func
* a restriction on max tx/glom count (based on host->max_segs).
*/
if (sg_count >= ARRAYSIZE(sd->sg_list)) {
sd_err(("%s: sg list entries exceed limit %d\n", __FUNCTION__, sg_count));
sd_err(("%s: sg list entries(%u) exceed limit(%zu),"
" sd blk_size=%u\n",
__FUNCTION__, sg_count, (size_t)ARRAYSIZE(sd->sg_list), blk_size));
return (SDIOH_API_RC_FAIL);
}
pdata += pkt_offset;
@@ -1180,8 +1305,9 @@ sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func
* DMA descriptor, use multiple sg buffers when xfer_size is bigger than
* max_seg_size
*/
if (sg_data_size > host->max_seg_size)
if (sg_data_size > host->max_seg_size) {
sg_data_size = host->max_seg_size;
}
sg_set_buf(&sd->sg_list[sg_count++], pdata, sg_data_size);
ttl_len += sg_data_size;
@@ -1262,21 +1388,13 @@ txglomfail:
pkt_len += blk_size - (pkt_len % blk_size);
if ((write) && (!fifo))
err_ret = sdio_memcpy_toio(
sd->func[func],
addr, buf, pkt_len);
err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, pkt_len);
else if (write)
err_ret = sdio_memcpy_toio(
sd->func[func],
addr, buf, pkt_len);
err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, pkt_len);
else if (fifo)
err_ret = sdio_readsb(
sd->func[func],
buf, addr, pkt_len);
err_ret = sdio_readsb(sd->func[func], buf, addr, pkt_len);
else
err_ret = sdio_memcpy_fromio(
sd->func[func],
buf, addr, pkt_len);
err_ret = sdio_memcpy_fromio(sd->func[func], buf, addr, pkt_len);
if (err_ret)
sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=%d\n",
@@ -1302,12 +1420,20 @@ txglomfail:
if (localbuf)
MFREE(sd->osh, localbuf, ttl_len);
if (sd_msglevel & SDH_COST_VAL) {
#ifndef PKT_STATICS
if (sd_msglevel & SDH_COST_VAL)
#endif
{
osl_do_gettimeofday(&now);
sd_cost(("%s: rw=%d, ttl_len=%d, cost=%lds %luus\n", __FUNCTION__,
write, ttl_len, now.tv_sec-before.tv_sec, now.tv_nsec/1000-before.tv_nsec/1000));
}
#ifdef PKT_STATICS
if (write && (func == 2))
sd->sdio_spent_time_us = osl_do_gettimediff(&now, &before);
#endif
sd_trace(("%s: Exit\n", __FUNCTION__));
return SDIOH_API_RC_SUCCESS;
}
@@ -1367,7 +1493,6 @@ sdioh_buffer_tofrom_bus(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
}
/*
* This function takes a buffer or packet, and fixes everything up so that in the
* end, a DMA-able packet is created.
@@ -1385,6 +1510,7 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u
{
SDIOH_API_RC status;
void *tmppkt;
int is_vmalloc = FALSE;
struct osl_timespec now, before;
sd_trace(("%s: Enter\n", __FUNCTION__));
@@ -1410,10 +1536,20 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u
}
ASSERT(buffer);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 24)
is_vmalloc = is_vmalloc_addr(buffer);
#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 24) */
/* buffer and length are aligned, use it directly so we can avoid memory copy */
if (((ulong)buffer & DMA_ALIGN_MASK) == 0 && (buf_len & DMA_ALIGN_MASK) == 0)
if ((((ulong)buffer & DMA_ALIGN_MASK) == 0) && ((buf_len & DMA_ALIGN_MASK) == 0) &&
(!is_vmalloc)) {
return sdioh_buffer_tofrom_bus(sd, fix_inc, write, func, addr, buffer, buf_len);
}
if (is_vmalloc) {
sd_trace(("%s: Need to memory copy due to virtual memory address.\n",
__FUNCTION__));
}
sd_trace(("%s: [%d] doing memory copy buf=%p, len=%d\n",
__FUNCTION__, write, buffer, buf_len));
@@ -1454,6 +1590,7 @@ sdioh_abort(sdioh_info_t *sd, uint func)
#endif /* defined(MMC_SDIO_ABORT) */
sd_trace(("%s: Enter\n", __FUNCTION__));
/* XXX Standard Linux SDIO Stack cannot perform an abort. */
#if defined(MMC_SDIO_ABORT)
/* issue abort cmd52 command through F1 */
sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func);
@@ -1504,7 +1641,6 @@ sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize
if (sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize)) {
return BCME_SDIO_ERROR;
}
if (regsize == 2)
*data &= 0xffff;
@@ -1531,7 +1667,10 @@ static void IRQHandler(struct sdio_func *func)
ASSERT(sd->intr_handler);
ASSERT(sd->intr_handler_arg);
(sd->intr_handler)(sd->intr_handler_arg);
} else {
} else { /* XXX - Do not remove these sd_err messages. Need to figure
out how to keep interrupts disabled until DHD registers
a handler.
*/
sd_err(("bcmsdh_sdmmc: ***IRQHandler\n"));
sd_err(("%s: Not ready for intr: enabled %d, handler %p\n",
@@ -1575,9 +1714,33 @@ sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsiz
}
#endif /* NOTUSED */
#if defined(ENABLE_INSMOD_NO_FW_LOAD) && !defined(BUS_POWER_RESTORE)
static int sdio_sw_reset(sdioh_info_t *sd)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
struct mmc_host *host = sd->func[0]->card->host;
#endif
int err = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
printf("%s: Enter\n", __FUNCTION__);
sdio_claim_host(sd->func[0]);
err = mmc_sw_reset(host);
sdio_release_host(sd->func[0]);
#else
err = sdio_reset_comm(sd->func[0]->card);
#endif
if (err)
sd_err(("%s Failed, error = %d\n", __FUNCTION__, err));
return err;
}
#endif
int
sdioh_start(sdioh_info_t *sd, int stage)
{
#if defined(OEM_ANDROID)
int ret;
if (!sd) {
@@ -1601,7 +1764,8 @@ sdioh_start(sdioh_info_t *sd, int stage)
patch for it
*/
#if defined(ENABLE_INSMOD_NO_FW_LOAD) && !defined(BUS_POWER_RESTORE)
if ((ret = sdio_reset_comm(sd->func[0]->card))) {
//if ((ret = sdio_reset_comm(sd->func[0]->card))) {
if ((ret = sdio_sw_reset(sd))) {
sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
return ret;
} else
@@ -1663,6 +1827,7 @@ sdioh_start(sdioh_info_t *sd, int stage)
}
else
sd_err(("%s Failed\n", __FUNCTION__));
#endif /* defined(OEM_ANDROID) */
return (0);
}
@@ -1670,6 +1835,7 @@ sdioh_start(sdioh_info_t *sd, int stage)
int
sdioh_stop(sdioh_info_t *sd)
{
#if defined(OEM_ANDROID)
/* MSM7201A Android sdio stack has bug with interrupt
So internaly within SDIO stack they are polling
which cause issue when device is turned off. So
@@ -1693,6 +1859,7 @@ sdioh_stop(sdioh_info_t *sd)
}
else
sd_err(("%s Failed\n", __FUNCTION__));
#endif /* defined(OEM_ANDROID) */
return (0);
}
@@ -1702,6 +1869,15 @@ sdioh_waitlockfree(sdioh_info_t *sd)
return (1);
}
#ifdef BCMINTERNAL
extern SDIOH_API_RC
sdioh_test_diag(sdioh_info_t *sd)
{
sd_trace(("%s: Enter\n", __FUNCTION__));
sd_trace(("%s: Exit\n", __FUNCTION__));
return (0);
}
#endif /* BCMINTERNAL */
SDIOH_API_RC
sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio)
@@ -1739,7 +1915,6 @@ sdmmc_get_clock_rate(sdioh_info_t *sd)
#endif
}
void
sdmmc_set_clock_rate(sdioh_info_t *sd, uint hz)
{

View File

@@ -1,14 +1,14 @@
/*
* BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,15 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Proprietary,Open:>>
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmsdh_sdmmc_linux.c 644124 2016-06-17 07:59:34Z $
* $Id$
*/
#include <typedefs.h>
@@ -43,6 +39,7 @@
#include <dhd_linux.h>
#include <bcmsdh_sdmmc.h>
#include <dhd_dbg.h>
#include <bcmdevs.h>
#if !defined(SDIO_VENDOR_ID_BROADCOM)
#define SDIO_VENDOR_ID_BROADCOM 0x02d0
@@ -50,31 +47,6 @@
#define SDIO_DEVICE_ID_BROADCOM_DEFAULT 0x0000
#if !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB)
#define SDIO_DEVICE_ID_BROADCOM_4325_SDGWB 0x0492 /* BCM94325SDGWB */
#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) */
#if !defined(SDIO_DEVICE_ID_BROADCOM_4325)
#define SDIO_DEVICE_ID_BROADCOM_4325 0x0493
#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */
#if !defined(SDIO_DEVICE_ID_BROADCOM_4329)
#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329
#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */
#if !defined(SDIO_DEVICE_ID_BROADCOM_4319)
#define SDIO_DEVICE_ID_BROADCOM_4319 0x4319
#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4319) */
#if !defined(SDIO_DEVICE_ID_BROADCOM_4330)
#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330
#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4330) */
#if !defined(SDIO_DEVICE_ID_BROADCOM_4334)
#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334
#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4334) */
#if !defined(SDIO_DEVICE_ID_BROADCOM_4324)
#define SDIO_DEVICE_ID_BROADCOM_4324 0x4324
#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4324) */
#if !defined(SDIO_DEVICE_ID_BROADCOM_43239)
#define SDIO_DEVICE_ID_BROADCOM_43239 43239
#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_43239) */
extern void wl_cfg80211_set_parent_dev(void *dev);
extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd);
extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd);
@@ -115,9 +87,7 @@ static int sdioh_probe(struct sdio_func *func)
adapter = dhd_wifi_platform_get_adapter(SDIO_BUS, host_idx, rca);
if (adapter != NULL) {
sd_err(("found adapter info '%s'\n", adapter->name));
#ifdef BUS_POWER_RESTORE
adapter->sdio_func = func;
#endif
} else
sd_err(("can't find adapter info for this chip\n"));
@@ -217,14 +187,23 @@ static void bcmsdh_sdmmc_remove(struct sdio_func *func)
/* devices we support, null terminated */
static const struct sdio_device_id bcmsdh_sdmmc_ids[] = {
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4324) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) },
/* XXX This should not be in the external release, as it will attach to any SDIO
* device, even non-WLAN devices.
* Need to add IDs for the FALCON-based chips and put this under BCMINTERNAL
{ SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) },
*/
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM4362_CHIP_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43751_CHIP_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43752_CHIP_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43012_CHIP_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43014_CHIP_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43014_D11N_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43014_D11N2G_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43014_D11N5G_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43013_CHIP_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43013_D11N_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43013_D11N2G_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43013_D11N5G_ID) },
{ SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) },
{ 0, 0, 0, 0 /* end: all zeroes */
},
@@ -303,6 +282,7 @@ static struct semaphore *notify_semaphore = NULL;
static int dummy_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
sd_err(("%s: enter\n", __FUNCTION__));
if (func && (func->num != 2)) {
return 0;
}

View File

@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer
*
* Copyright (C) 1999-2019, Broadcom.
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -18,28 +17,37 @@
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmsdspi.h 514727 2014-11-12 03:02:48Z $
* $Id: bcmsdspi.h 833013 2019-08-02 16:26:31Z jl904071 $
*/
#ifndef _BCM_SD_SPI_H
#define _BCM_SD_SPI_H
/* global msglevel for debug messages - bitvals come from sdiovar.h */
#ifdef BCMDBG
#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0)
#define sd_trace(x) do { if (sd_msglevel & SDH_TRACE_VAL) printf x; } while (0)
#define sd_info(x) do { if (sd_msglevel & SDH_INFO_VAL) printf x; } while (0)
#define sd_debug(x) do { if (sd_msglevel & SDH_DEBUG_VAL) printf x; } while (0)
#define sd_data(x) do { if (sd_msglevel & SDH_DATA_VAL) printf x; } while (0)
#define sd_ctrl(x) do { if (sd_msglevel & SDH_CTRL_VAL) printf x; } while (0)
#else
#define sd_err(x)
#define sd_trace(x)
#define sd_info(x)
#define sd_debug(x)
#define sd_data(x)
#define sd_ctrl(x)
#endif
#ifdef BCMPERFSTATS
#define sd_log(x) do { if (sd_msglevel & SDH_LOG_VAL) bcmlog x; } while (0)
#else
#define sd_log(x)
#endif
#define SDIOH_ASSERT(exp) \
do { if (!(exp)) \

View File

@@ -1,14 +1,14 @@
/*
* Broadcom SPI Host Controller Driver - Linux Per-port
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,15 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmsdspi_linux.c 514727 2014-11-12 03:02:48Z $
* $Id$
*/
#include <typedefs.h>
@@ -33,29 +29,40 @@
#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
#include <sdiovar.h> /* to get msglevel bit values */
#ifdef BCMSPI_ANDROID
#include <bcmsdh.h>
#include <bcmspibrcm.h>
#include <linux/spi/spi.h>
#else
#include <pcicfg.h>
#include <sdio.h> /* SDIO Device and Protocol Specs */
#include <linux/sched.h> /* request_irq(), free_irq() */
#include <bcmsdspi.h>
#include <bcmspi.h>
#endif /* BCMSPI_ANDROID */
#ifndef BCMSPI_ANDROID
extern uint sd_crc;
module_param(sd_crc, uint, 0);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
#define KERNEL26
#endif
#endif /* !BCMSPI_ANDROID */
struct sdos_info {
sdioh_info_t *sd;
spinlock_t lock;
#ifndef BCMSPI_ANDROID
wait_queue_head_t intr_wait_queue;
#endif /* !BCMSPI_ANDROID */
};
#ifndef BCMSPI_ANDROID
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
#define BLOCKABLE() (!in_atomic())
#else
#define BLOCKABLE() (!in_interrupt())
#define BLOCKABLE() (!in_interrupt()) /* XXX Doesn't handle CONFIG_PREEMPT? */
#endif
/* Interrupt handler */
@@ -88,17 +95,91 @@ sdspi_isr(int irq, void *dev_id
return IRQ_RETVAL(ours);
}
}
#endif /* !BCMSPI_ANDROID */
#ifdef BCMSPI_ANDROID
static struct spi_device *gBCMSPI = NULL;
extern int bcmsdh_probe(struct device *dev);
extern int bcmsdh_remove(struct device *dev);
static int bcmsdh_spi_probe(struct spi_device *spi_dev)
{
int ret = 0;
gBCMSPI = spi_dev;
#ifdef SPI_PIO_32BIT_RW
spi_dev->bits_per_word = 32;
#else
spi_dev->bits_per_word = 8;
#endif /* SPI_PIO_32BIT_RW */
ret = spi_setup(spi_dev);
if (ret) {
sd_err(("bcmsdh_spi_probe: spi_setup fail with %d\n", ret));
}
sd_err(("bcmsdh_spi_probe: spi_setup with %d, bits_per_word=%d\n",
ret, spi_dev->bits_per_word));
ret = bcmsdh_probe(&spi_dev->dev);
return ret;
}
static int bcmsdh_spi_remove(struct spi_device *spi_dev)
{
int ret = 0;
ret = bcmsdh_remove(&spi_dev->dev);
gBCMSPI = NULL;
return ret;
}
static struct spi_driver bcmsdh_spi_driver = {
.probe = bcmsdh_spi_probe,
.remove = bcmsdh_spi_remove,
.driver = {
.name = "wlan_spi",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
};
/*
* module init
*/
int bcmsdh_register_client_driver(void)
{
int error = 0;
sd_trace(("bcmsdh_gspi: %s Enter\n", __FUNCTION__));
error = spi_register_driver(&bcmsdh_spi_driver);
return error;
}
/*
* module cleanup
*/
void bcmsdh_unregister_client_driver(void)
{
sd_trace(("%s Enter\n", __FUNCTION__));
spi_unregister_driver(&bcmsdh_spi_driver);
}
#endif /* BCMSPI_ANDROID */
/* Register with Linux for interrupts */
int
spi_register_irq(sdioh_info_t *sd, uint irq)
{
#ifndef BCMSPI_ANDROID
sd_trace(("Entering %s: irq == %d\n", __FUNCTION__, irq));
if (request_irq(irq, sdspi_isr, IRQF_SHARED, "bcmsdspi", sd) < 0) {
sd_err(("%s: request_irq() failed\n", __FUNCTION__));
return ERROR;
}
#endif /* !BCMSPI_ANDROID */
return SUCCESS;
}
@@ -106,10 +187,13 @@ spi_register_irq(sdioh_info_t *sd, uint irq)
void
spi_free_irq(uint irq, sdioh_info_t *sd)
{
#ifndef BCMSPI_ANDROID
free_irq(irq, sd);
#endif /* !BCMSPI_ANDROID */
}
/* Map Host controller registers */
#ifndef BCMSPI_ANDROID
uint32 *
spi_reg_map(osl_t *osh, uintptr addr, int size)
{
@@ -121,6 +205,7 @@ spi_reg_unmap(osl_t *osh, uintptr addr, int size)
{
REG_UNMAP((void*)(uintptr)addr);
}
#endif /* !BCMSPI_ANDROID */
int
spi_osinit(sdioh_info_t *sd)
@@ -134,7 +219,9 @@ spi_osinit(sdioh_info_t *sd)
sdos->sd = sd;
spin_lock_init(&sdos->lock);
#ifndef BCMSPI_ANDROID
init_waitqueue_head(&sdos->intr_wait_queue);
#endif /* !BCMSPI_ANDROID */
return BCME_OK;
}
@@ -165,19 +252,23 @@ sdioh_interrupt_set(sdioh_info_t *sd, bool enable)
return SDIOH_API_RC_FAIL;
}
#ifndef BCMSPI_ANDROID
if (enable && !(sd->intr_handler && sd->intr_handler_arg)) {
sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__));
return SDIOH_API_RC_FAIL;
}
#endif /* !BCMSPI_ANDROID */
/* Ensure atomicity for enable/disable calls */
spin_lock_irqsave(&sdos->lock, flags);
sd->client_intr_enabled = enable;
#ifndef BCMSPI_ANDROID
if (enable && !sd->lockcount)
spi_devintr_on(sd);
else
spi_devintr_off(sd);
#endif /* !BCMSPI_ANDROID */
spin_unlock_irqrestore(&sdos->lock, flags);
@@ -201,7 +292,12 @@ spi_lock(sdioh_info_t *sd)
sd_err(("%s: Already locked!\n", __FUNCTION__));
ASSERT(sd->lockcount == 0);
}
#ifdef BCMSPI_ANDROID
if (sd->client_intr_enabled)
bcmsdh_oob_intr_set(0);
#else
spi_devintr_off(sd);
#endif /* BCMSPI_ANDROID */
sd->lockcount++;
spin_unlock_irqrestore(&sdos->lock, flags);
}
@@ -221,11 +317,16 @@ spi_unlock(sdioh_info_t *sd)
spin_lock_irqsave(&sdos->lock, flags);
if (--sd->lockcount == 0 && sd->client_intr_enabled) {
#ifdef BCMSPI_ANDROID
bcmsdh_oob_intr_set(1);
#else
spi_devintr_on(sd);
#endif /* BCMSPI_ANDROID */
}
spin_unlock_irqrestore(&sdos->lock, flags);
}
#ifndef BCMSPI_ANDROID
void spi_waitbits(sdioh_info_t *sd, bool yield)
{
#ifndef BCMSDYIELD
@@ -250,3 +351,83 @@ void spi_waitbits(sdioh_info_t *sd, bool yield)
}
}
#else /* !BCMSPI_ANDROID */
int bcmgspi_dump = 0; /* Set to dump complete trace of all SPI bus transactions */
static void
hexdump(char *pfx, unsigned char *msg, int msglen)
{
int i, col;
char buf[80];
ASSERT(strlen(pfx) + 49 <= sizeof(buf));
col = 0;
for (i = 0; i < msglen; i++, col++) {
if (col % 16 == 0)
strcpy(buf, pfx);
sprintf(buf + strlen(buf), "%02x", msg[i]);
if ((col + 1) % 16 == 0)
printf("%s\n", buf);
else
sprintf(buf + strlen(buf), " ");
}
if (col % 16 != 0)
printf("%s\n", buf);
}
/* Send/Receive an SPI Packet */
void
spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen)
{
int write = 0;
int tx_len = 0;
struct spi_message msg;
struct spi_transfer t[2];
spi_message_init(&msg);
memset(t, 0, 2*sizeof(struct spi_transfer));
if (sd->wordlen == 2)
#if !(defined(SPI_PIO_RW_BIGENDIAN) && defined(SPI_PIO_32BIT_RW))
write = msg_out[2] & 0x80; /* XXX bit 7: read:0, write :1 */
#else
write = msg_out[1] & 0x80; /* XXX bit 7: read:0, write :1 */
#endif /* !(defined(SPI_PIO_RW_BIGENDIAN) && defined(SPI_PIO_32BIT_RW)) */
if (sd->wordlen == 4)
#if !(defined(SPI_PIO_RW_BIGENDIAN) && defined(SPI_PIO_32BIT_RW))
write = msg_out[0] & 0x80; /* XXX bit 7: read:0, write :1 */
#else
write = msg_out[3] & 0x80; /* XXX bit 7: read:0, write :1 */
#endif /* !(defined(SPI_PIO_RW_BIGENDIAN) && defined(SPI_PIO_32BIT_RW)) */
if (bcmgspi_dump) {
hexdump(" OUT: ", msg_out, msglen);
}
tx_len = write ? msglen-4 : 4;
sd_trace(("spi_sendrecv: %s, wordlen %d, cmd : 0x%02x 0x%02x 0x%02x 0x%02x\n",
write ? "WR" : "RD", sd->wordlen,
msg_out[0], msg_out[1], msg_out[2], msg_out[3]));
t[0].tx_buf = (char *)&msg_out[0];
t[0].rx_buf = 0;
t[0].len = tx_len;
spi_message_add_tail(&t[0], &msg);
t[1].rx_buf = (char *)&msg_in[tx_len];
t[1].tx_buf = 0;
t[1].len = msglen-tx_len;
spi_message_add_tail(&t[1], &msg);
spi_sync(gBCMSPI, &msg);
if (bcmgspi_dump) {
hexdump(" IN : ", msg_in, msglen);
}
}
#endif /* !BCMSPI_ANDROID */

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* 'Standard' SDIO HOST CONTROLLER driver
*
* Copyright (C) 1999-2019, Broadcom.
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -18,19 +17,24 @@
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmsdstd.h 768214 2018-06-19 03:53:58Z $
* $Id: bcmsdstd.h 833030 2019-08-02 17:22:42Z jl904071 $
*/
#ifndef _BCM_SD_STD_H
#define _BCM_SD_STD_H
/* global msglevel for debug messages - bitvals come from sdiovar.h */
#ifdef BCMDBG
#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0)
#define sd_trace(x) do { if (sd_msglevel & SDH_TRACE_VAL) printf x; } while (0)
#define sd_info(x) do { if (sd_msglevel & SDH_INFO_VAL) printf x; } while (0)
#define sd_debug(x) do { if (sd_msglevel & SDH_DEBUG_VAL) printf x; } while (0)
#define sd_data(x) do { if (sd_msglevel & SDH_DATA_VAL) printf x; } while (0)
#define sd_ctrl(x) do { if (sd_msglevel & SDH_CTRL_VAL) printf x; } while (0)
#define sd_dma(x) do { if (sd_msglevel & SDH_DMA_VAL) printf x; } while (0)
#else
#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0)
#define sd_trace(x)
#define sd_info(x)
@@ -38,6 +42,7 @@
#define sd_data(x)
#define sd_ctrl(x)
#define sd_dma(x)
#endif /* BCMDBG */
#define sd_sync_dma(sd, read, nbytes)
#define sd_init_dma(sd)
@@ -47,7 +52,11 @@
extern int sdstd_osinit(sdioh_info_t *sd);
extern void sdstd_osfree(sdioh_info_t *sd);
#ifdef BCMPERFSTATS
#define sd_log(x) do { if (sd_msglevel & SDH_LOG_VAL) bcmlog x; } while (0)
#else
#define sd_log(x)
#endif
#define SDIOH_ASSERT(exp) \
do { if (!(exp)) \
@@ -71,19 +80,29 @@ extern void sdstd_osfree(sdioh_info_t *sd);
#define SDIOH_TYPE_ARASAN_HDK 1
#define SDIOH_TYPE_BCM27XX 2
#ifdef BCMINTERNAL
#define SDIOH_TYPE_JINVANI_GOLD 3
#endif
#define SDIOH_TYPE_TI_PCIXX21 4 /* TI PCIxx21 Standard Host Controller */
#define SDIOH_TYPE_RICOH_R5C822 5 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter */
#define SDIOH_TYPE_JMICRON 6 /* JMicron Standard SDIO Host Controller */
/* For linux, allow yielding for dongle */
#if defined(linux) && defined(BCMDONGLEHOST)
#define BCMSDYIELD
#endif
/* Expected card status value for CMD7 */
#define SDIOH_CMD7_EXP_STATUS 0x00001E00
#define RETRIES_LARGE 100000
#ifdef BCMQT
extern void sdstd_os_yield(sdioh_info_t *sd);
#define RETRIES_SMALL 10000
#else
#define sdstd_os_yield(sd) do {} while (0)
#define RETRIES_SMALL 100
#endif
#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */
#define USE_MULTIBLOCK 0x4
@@ -103,10 +122,10 @@ extern void sdstd_osfree(sdioh_info_t *sd);
typedef struct glom_buf {
uint32 count; /* Total number of pkts queued */
void *dma_buf_arr[SDIOH_MAXGLOM_SIZE]; /* Frame address */
ulong dma_phys_arr[SDIOH_MAXGLOM_SIZE]; /* DMA_MAPed address of frames */
dmaaddr_t dma_phys_arr[SDIOH_MAXGLOM_SIZE]; /* DMA_MAPed address of frames */
uint16 nbytes[SDIOH_MAXGLOM_SIZE]; /* Size of each frame */
} glom_buf_t;
#endif // endif
#endif
struct sdioh_info {
uint cfg_bar; /* pci cfg address for bar */
@@ -149,16 +168,16 @@ struct sdioh_info {
uint32 com_cis_ptr;
uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS];
void *dma_buf; /* DMA Buffer virtual address */
ulong dma_phys; /* DMA Buffer physical address */
dmaaddr_t dma_phys; /* DMA Buffer physical address */
void *adma2_dscr_buf; /* ADMA2 Descriptor Buffer virtual address */
ulong adma2_dscr_phys; /* ADMA2 Descriptor Buffer physical address */
dmaaddr_t adma2_dscr_phys; /* ADMA2 Descriptor Buffer physical address */
/* adjustments needed to make the dma align properly */
void *dma_start_buf;
ulong dma_start_phys;
dmaaddr_t dma_start_phys;
uint alloced_dma_size;
void *adma2_dscr_start_buf;
ulong adma2_dscr_start_phys;
dmaaddr_t adma2_dscr_start_phys;
uint alloced_adma2_dscr_size;
int r_cnt; /* rx count */
@@ -182,7 +201,7 @@ struct sdioh_info {
#ifdef BCMSDIOH_TXGLOM
glom_buf_t glom_info; /* pkt information used for glomming */
uint txglom_mode; /* Txglom mode: 0 - copy, 1 - multi-descriptor */
#endif // endif
#endif
};
#define DMA_MODE_NONE 0
@@ -209,7 +228,7 @@ struct sdioh_info {
#ifdef DHD_DEBUG
#define SD_DHD_DISABLE_PERIODIC_TUNING 0x01
#define SD_DHD_ENABLE_PERIODIC_TUNING 0x00
#endif // endif
#endif
/************************************************************
* Internal interfaces: per-port references into bcmsdstd.c
@@ -237,8 +256,8 @@ extern void sdstd_spinbits(sdioh_info_t *sd, uint16 norm, uint16 err);
*/
/* Register mapping routines */
extern uint32 *sdstd_reg_map(osl_t *osh, ulong addr, int size);
extern void sdstd_reg_unmap(osl_t *osh, ulong addr, int size);
extern uint32 *sdstd_reg_map(osl_t *osh, dmaaddr_t addr, int size);
extern void sdstd_reg_unmap(osl_t *osh, dmaaddr_t addr, int size);
/* Interrupt (de)registration routines */
extern int sdstd_register_irq(sdioh_info_t *sd, uint irq);

View File

@@ -0,0 +1,690 @@
/*
* 'Standard' SDIO HOST CONTROLLER driver - linux portion
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id$
*/
#include <linux/sched.h> /* request_irq() */
#include <typedefs.h>
#include <pcicfg.h>
#include <bcmutils.h>
#include <sdio.h> /* SDIO Device and Protocol Specs */
#include <sdioh.h> /* SDIO Host Controller Spec header file */
#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
#include <sdiovar.h> /* to get msglevel bit values */
#include <bcmsdstd.h>
#include <bcmdevs.h>
extern void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type,
uint bus_num, uint slot_num);
extern int bcmsdh_remove(bcmsdh_info_t *bcmsdh);
/* Extern functions for sdio power save */
extern uint8 sdstd_turn_on_clock(sdioh_info_t *sd);
extern uint8 sdstd_turn_off_clock(sdioh_info_t *sd);
/* Extern variable for sdio power save. This is enabled or disabled using the IOCTL call */
extern uint sd_3_power_save;
struct sdos_info {
sdioh_info_t *sd;
spinlock_t lock;
wait_queue_head_t intr_wait_queue;
timer_list_compat_t tuning_timer;
int tuning_timer_exp;
atomic_t timer_enab;
struct tasklet_struct tuning_tasklet;
};
#define SDSTD_WAITBITS_TIMEOUT (5 * HZ) /* seconds * HZ */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
#define BLOCKABLE() (!in_atomic())
#else
#define BLOCKABLE() (!in_interrupt()) /* XXX Doesn't handle CONFIG_PREEMPT? */
#endif
static void
sdstd_3_ostasklet(ulong data);
static void
sdstd_3_tuning_timer(ulong data);
/* Interrupt handler */
static irqreturn_t
sdstd_isr(int irq, void *dev_id
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
, struct pt_regs *ptregs
#endif
)
{
sdioh_info_t *sd;
struct sdos_info *sdos;
bool ours;
unsigned long flags;
sd = (sdioh_info_t *)dev_id;
sdos = (struct sdos_info *)sd->sdos_info;
if (!sd->card_init_done) {
sd_err(("%s: Hey Bogus intr...not even initted: irq %d\n", __FUNCTION__, irq));
return IRQ_RETVAL(FALSE);
} else {
if (sdstd_3_is_retuning_int_set(sd)) {
/* for 3.0 host, retuning request might come in this path */
/* * disable ISR's */
local_irq_save(flags);
if (sdstd_3_check_and_set_retuning(sd))
tasklet_schedule(&sdos->tuning_tasklet);
/* * enable back ISR's */
local_irq_restore(flags);
/* * disable tuning isr signaling */
sdstd_3_disable_retuning_int(sd);
/* * note: check_client_intr() checks for intmask also to
wakeup. so be careful to use sd->intmask to disable
re-tuning ISR.
*/
}
ours = check_client_intr(sd);
/* For local interrupts, wake the waiting process */
if (ours && sd->got_hcint) {
sd_trace(("INTR->WAKE\n"));
/* sdos = (struct sdos_info *)sd->sdos_info; */
wake_up_interruptible(&sdos->intr_wait_queue);
}
return IRQ_RETVAL(ours);
}
}
/* Register with Linux for interrupts */
int
sdstd_register_irq(sdioh_info_t *sd, uint irq)
{
sd_trace(("Entering %s: irq == %d\n", __FUNCTION__, irq));
if (request_irq(irq, sdstd_isr, IRQF_SHARED, "bcmsdstd", sd) < 0) {
sd_err(("%s: request_irq() failed\n", __FUNCTION__));
return ERROR;
}
return SUCCESS;
}
/* Free Linux irq */
void
sdstd_free_irq(uint irq, sdioh_info_t *sd)
{
free_irq(irq, sd);
}
/* Map Host controller registers */
uint32 *
sdstd_reg_map(osl_t *osh, dmaaddr_t addr, int size)
{
return (uint32 *)REG_MAP(addr, size);
}
void
sdstd_reg_unmap(osl_t *osh, dmaaddr_t addr, int size)
{
REG_UNMAP((void*)(uintptr)addr);
}
int
sdstd_osinit(sdioh_info_t *sd)
{
struct sdos_info *sdos;
sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info));
sd->sdos_info = (void*)sdos;
if (sdos == NULL)
return BCME_NOMEM;
sdos->sd = sd;
spin_lock_init(&sdos->lock);
atomic_set(&sdos->timer_enab, FALSE);
init_waitqueue_head(&sdos->intr_wait_queue);
return BCME_OK;
}
/* initilize tuning related OS structures */
void
sdstd_3_osinit_tuning(sdioh_info_t *sd)
{
struct sdos_info *sdos = (struct sdos_info *)sd->sdos_info;
uint8 timer_count = sdstd_3_get_tuning_exp(sdos->sd);
sd_trace(("%s Enter\n", __FUNCTION__));
init_timer_compat(&sdos->tuning_timer, sdstd_3_tuning_timer, sdos);
if (timer_count == CAP3_RETUNING_TC_DISABLED || timer_count > CAP3_RETUNING_TC_1024S) {
sdos->tuning_timer_exp = 0;
} else {
sdos->tuning_timer_exp = 1 << (timer_count - 1);
}
tasklet_init(&sdos->tuning_tasklet, sdstd_3_ostasklet, (ulong)sdos);
if (sdos->tuning_timer_exp) {
timer_expires(&sdos->tuning_timer) = jiffies + sdos->tuning_timer_exp * HZ;
add_timer(&sdos->tuning_timer);
atomic_set(&sdos->timer_enab, TRUE);
}
}
/* finalize tuning related OS structures */
void
sdstd_3_osclean_tuning(sdioh_info_t *sd)
{
struct sdos_info *sdos = (struct sdos_info *)sd->sdos_info;
if (atomic_read(&sdos->timer_enab) == TRUE) {
/* disable timer if it was running */
del_timer_sync(&sdos->tuning_timer);
atomic_set(&sdos->timer_enab, FALSE);
}
tasklet_kill(&sdos->tuning_tasklet);
}
static void
sdstd_3_ostasklet(ulong data)
{
struct sdos_info *sdos = (struct sdos_info *)data;
int tune_state = sdstd_3_get_tune_state(sdos->sd);
int data_state = sdstd_3_get_data_state(sdos->sd);
if ((tune_state == TUNING_START) || (tune_state == TUNING_ONGOING) ||
(tune_state == TUNING_START_AFTER_DAT)) {
return;
}
else if (data_state == DATA_TRANSFER_IDLE)
sdstd_3_set_tune_state(sdos->sd, TUNING_START);
else if (data_state == DATA_TRANSFER_ONGOING)
sdstd_3_set_tune_state(sdos->sd, TUNING_START_AFTER_DAT);
}
static void
sdstd_3_tuning_timer(ulong data)
{
struct sdos_info *sdos = (struct sdos_info *)data;
/* uint8 timeout = 0; */
unsigned long int_flags;
sd_trace(("%s: enter\n", __FUNCTION__));
/* schedule tasklet */
/* * disable ISR's */
local_irq_save(int_flags);
if (sdstd_3_check_and_set_retuning(sdos->sd))
tasklet_schedule(&sdos->tuning_tasklet);
/* * enable back ISR's */
local_irq_restore(int_flags);
}
void sdstd_3_start_tuning(sdioh_info_t *sd)
{
int tune_state;
unsigned long int_flags = 0;
unsigned int timer_enab;
struct sdos_info *sdos = (struct sdos_info *)sd->sdos_info;
sd_trace(("%s: enter\n", __FUNCTION__));
/* * disable ISR's */
local_irq_save(int_flags);
timer_enab = atomic_read(&sdos->timer_enab);
tune_state = sdstd_3_get_tune_state(sd);
if (tune_state == TUNING_ONGOING) {
/* do nothing */
local_irq_restore(int_flags);
goto exit;
}
/* change state */
sdstd_3_set_tune_state(sd, TUNING_ONGOING);
/* * enable ISR's */
local_irq_restore(int_flags);
sdstd_3_clk_tuning(sd, sdstd_3_get_uhsi_clkmode(sd));
#ifdef BCMSDIOH_STD_TUNING_WAR
/*
* Observed intermittent SDIO command error after re-tuning done
* successfully. Re-tuning twice is giving much reliable results.
*/
sdstd_3_clk_tuning(sd, sdstd_3_get_uhsi_clkmode(sd));
#endif /* BCMSDIOH_STD_TUNING_WAR */
/* * disable ISR's */
local_irq_save(int_flags);
sdstd_3_set_tune_state(sd, TUNING_IDLE);
/* * enable ISR's */
local_irq_restore(int_flags);
/* enable retuning intrrupt */
sdstd_3_enable_retuning_int(sd);
/* start retuning timer if enabled */
if ((sdos->tuning_timer_exp) && (timer_enab)) {
if (sd->sd3_tuning_reqd) {
timer_expires(&sdos->tuning_timer) = jiffies + sdos->tuning_timer_exp * HZ;
mod_timer(&sdos->tuning_timer, timer_expires(&sdos->tuning_timer));
}
}
exit:
return;
}
void
sdstd_osfree(sdioh_info_t *sd)
{
struct sdos_info *sdos;
ASSERT(sd && sd->sdos_info);
sdos = (struct sdos_info *)sd->sdos_info;
MFREE(sd->osh, sdos, sizeof(struct sdos_info));
}
/* Interrupt enable/disable */
SDIOH_API_RC
sdioh_interrupt_set(sdioh_info_t *sd, bool enable)
{
ulong flags;
struct sdos_info *sdos;
sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling"));
sdos = (struct sdos_info *)sd->sdos_info;
ASSERT(sdos);
if (!(sd->host_init_done && sd->card_init_done)) {
sd_err(("%s: Card & Host are not initted - bailing\n", __FUNCTION__));
return SDIOH_API_RC_FAIL;
}
if (enable && !(sd->intr_handler && sd->intr_handler_arg)) {
sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__));
return SDIOH_API_RC_FAIL;
}
/* Ensure atomicity for enable/disable calls */
spin_lock_irqsave(&sdos->lock, flags);
sd->client_intr_enabled = enable;
if (enable && !sd->lockcount)
sdstd_devintr_on(sd);
else
sdstd_devintr_off(sd);
spin_unlock_irqrestore(&sdos->lock, flags);
return SDIOH_API_RC_SUCCESS;
}
/* Protect against reentrancy (disable device interrupts while executing) */
void
sdstd_lock(sdioh_info_t *sd)
{
ulong flags;
struct sdos_info *sdos;
int wait_count = 0;
sdos = (struct sdos_info *)sd->sdos_info;
ASSERT(sdos);
sd_trace(("%s: %d\n", __FUNCTION__, sd->lockcount));
spin_lock_irqsave(&sdos->lock, flags);
while (sd->lockcount)
{
spin_unlock_irqrestore(&sdos->lock, flags);
yield();
spin_lock_irqsave(&sdos->lock, flags);
if (++wait_count == 25000) {
if (!(sd->lockcount == 0)) {
sd_err(("%s: ERROR: sd->lockcount == 0\n", __FUNCTION__));
}
}
}
/* PR86684: Add temporary debugging print */
if (wait_count)
printk("sdstd_lock: wait count = %d\n", wait_count);
sdstd_devintr_off(sd);
sd->lockcount++;
spin_unlock_irqrestore(&sdos->lock, flags);
if ((sd->controller_type == SDIOH_TYPE_RICOH_R5C822) && (sd->version == HOST_CONTR_VER_3))
sdstd_turn_on_clock(sd);
}
/* Enable client interrupt */
void
sdstd_unlock(sdioh_info_t *sd)
{
ulong flags;
struct sdos_info *sdos;
sd_trace(("%s: %d, %d\n", __FUNCTION__, sd->lockcount, sd->client_intr_enabled));
ASSERT(sd->lockcount > 0);
sdos = (struct sdos_info *)sd->sdos_info;
ASSERT(sdos);
spin_lock_irqsave(&sdos->lock, flags);
if (--sd->lockcount == 0 && sd->client_intr_enabled) {
sdstd_devintr_on(sd);
}
spin_unlock_irqrestore(&sdos->lock, flags);
if (sd_3_power_save)
{
if ((sd->controller_type == SDIOH_TYPE_RICOH_R5C822) &&
(sd->version == HOST_CONTR_VER_3))
sdstd_turn_off_clock(sd);
}
}
void
sdstd_os_lock_irqsave(sdioh_info_t *sd, ulong* flags)
{
struct sdos_info *sdos = (struct sdos_info *)sd->sdos_info;
spin_lock_irqsave(&sdos->lock, *flags);
}
void
sdstd_os_unlock_irqrestore(sdioh_info_t *sd, ulong* flags)
{
struct sdos_info *sdos = (struct sdos_info *)sd->sdos_info;
spin_unlock_irqrestore(&sdos->lock, *flags);
}
void
sdstd_waitlockfree(sdioh_info_t *sd)
{
if (sd->lockcount) {
printk("wait lock free\n");
while (sd->lockcount)
{
yield();
}
}
}
#ifdef BCMQT
void
sdstd_os_yield(sdioh_info_t *sd)
{
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 29))
/*
* FC4/11 issue on QT if driver hogs > 10s of CPU causing:
* BUG: soft lockup detected on CPU#0!
*
* XXX Hack: For now, interleave yielding of CPU when we're spinning waiting for
* XXX register status
*/
yield();
#endif
}
#endif /* BCMQT */
/* Returns 0 for success, -1 for interrupted, -2 for timeout */
int
sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool local_yield, uint16 *bits)
{
struct sdos_info *sdos;
int rc = 0;
sdos = (struct sdos_info *)sd->sdos_info;
#ifndef BCMSDYIELD
ASSERT(!local_yield);
#endif
sd_trace(("%s: int 0x%02x err 0x%02x yield %d canblock %d\n",
__FUNCTION__, norm, err, local_yield, BLOCKABLE()));
/* Clear the "interrupt happened" flag and last intrstatus */
sd->got_hcint = FALSE;
sd->last_intrstatus = 0;
#ifdef BCMSDYIELD
if (local_yield && BLOCKABLE()) {
/* Enable interrupts, wait for the indication, then disable */
sdstd_intrs_on(sd, norm, err);
rc = wait_event_interruptible_timeout(sdos->intr_wait_queue,
(sd->got_hcint),
SDSTD_WAITBITS_TIMEOUT);
if (rc < 0)
rc = -1; /* interrupted */
else if (rc == 0)
rc = -2; /* timeout */
else
rc = 0; /* success */
sdstd_intrs_off(sd, norm, err);
} else
#endif /* BCMSDYIELD */
{
sdstd_spinbits(sd, norm, err);
}
sd_trace(("%s: last_intrstatus 0x%04x\n", __FUNCTION__, sd->last_intrstatus));
*bits = sd->last_intrstatus;
return rc;
}
#ifdef DHD_DEBUG
void sdstd_enable_disable_periodic_timer(sdioh_info_t *sd, uint val)
{
struct sdos_info *sdos = (struct sdos_info *)sd->sdos_info;
if (val == SD_DHD_ENABLE_PERIODIC_TUNING) {
/* start of tuning timer */
timer_expires(&sdos->tuning_timer) = jiffies + sdos->tuning_timer_exp * HZ;
mod_timer(&sdos->tuning_timer, timer_expires(&sdos->tuning_timer));
}
if (val == SD_DHD_DISABLE_PERIODIC_TUNING) {
/* stop periodic timer */
del_timer_sync(&sdos->tuning_timer);
}
}
#endif /* debugging purpose */
/* forward declarations for PCI probe and remove functions. */
static int __devinit bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev);
/**
* pci id table
*/
static struct pci_device_id bcmsdh_pci_devid[] __devinitdata = {
{ vendor: PCI_ANY_ID,
device: PCI_ANY_ID,
subvendor: PCI_ANY_ID,
subdevice: PCI_ANY_ID,
class: 0,
class_mask: 0,
driver_data: 0,
},
{ 0, 0, 0, 0, 0, 0, 0}
};
MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid);
/**
* SDIO Host Controller pci driver info
*/
static struct pci_driver bcmsdh_pci_driver = {
node: {&(bcmsdh_pci_driver.node), &(bcmsdh_pci_driver.node)},
name: "bcmsdh",
id_table: bcmsdh_pci_devid,
probe: bcmsdh_pci_probe,
remove: bcmsdh_pci_remove,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
save_state: NULL,
#endif
suspend: NULL,
resume: NULL,
};
extern uint sd_pci_slot; /* Force detection to a particular PCI */
/* slot only . Allows for having multiple */
/* WL devices at once in a PC */
/* Only one instance of dhd will be */
/* usable at a time */
/* Upper word is bus number, */
/* lower word is slot number */
/* Default value of 0xffffffff turns this */
/* off */
module_param(sd_pci_slot, uint, 0);
/**
* Detect supported SDIO Host Controller and attach if found.
*
* Determine if the device described by pdev is a supported SDIO Host
* Controller. If so, attach to it and attach to the target device.
*/
static int __devinit
bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
osl_t *osh = NULL;
sdioh_info_t *sdioh = NULL;
int rc;
if (sd_pci_slot != 0xFFFFffff) {
if (pdev->bus->number != (sd_pci_slot>>16) ||
PCI_SLOT(pdev->devfn) != (sd_pci_slot&0xffff)) {
sd_err(("%s: %s: bus %X, slot %X, vend %X, dev %X\n",
__FUNCTION__,
bcmsdh_chipmatch(pdev->vendor, pdev->device)
?"Found compatible SDIOHC"
:"Probing unknown device",
pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor,
pdev->device));
return -ENODEV;
}
sd_err(("%s: %s: bus %X, slot %X, vendor %X, device %X (good PCI location)\n",
__FUNCTION__,
bcmsdh_chipmatch(pdev->vendor, pdev->device)
?"Using compatible SDIOHC"
:"WARNING, forced use of unkown device",
pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor, pdev->device));
}
if ((pdev->vendor == VENDOR_TI) && ((pdev->device == PCIXX21_FLASHMEDIA_ID) ||
(pdev->device == PCIXX21_FLASHMEDIA0_ID))) {
uint32 config_reg;
sd_err(("%s: Disabling TI FlashMedia Controller.\n", __FUNCTION__));
if (!(osh = osl_attach(pdev, SDIO_BUS, TRUE))) {
sd_err(("%s: osl_attach failed\n", __FUNCTION__));
goto err;
}
config_reg = OSL_PCI_READ_CONFIG(osh, 0x4c, 4);
/*
* Set MMC_SD_DIS bit in FlashMedia Controller.
* Disbling the SD/MMC Controller in the FlashMedia Controller
* allows the Standard SD Host Controller to take over control
* of the SD Slot.
*/
config_reg |= 0x02;
OSL_PCI_WRITE_CONFIG(osh, 0x4c, 4, config_reg);
osl_detach(osh);
}
/* match this pci device with what we support */
/* we can't solely rely on this to believe it is our SDIO Host Controller! */
if (!bcmsdh_chipmatch(pdev->vendor, pdev->device)) {
if (pdev->vendor == VENDOR_BROADCOM) {
sd_err(("%s: Unknown Broadcom device (vendor: %#x, device: %#x).\n",
__FUNCTION__, pdev->vendor, pdev->device));
}
return -ENODEV;
}
/* this is a pci device we might support */
sd_err(("%s: Found possible SDIO Host Controller: bus %d slot %d func %d irq %d\n",
__FUNCTION__,
pdev->bus->number, PCI_SLOT(pdev->devfn),
PCI_FUNC(pdev->devfn), pdev->irq));
/* use bcmsdh_query_device() to get the vendor ID of the target device so
* it will eventually appear in the Broadcom string on the console
*/
/* allocate SDIO Host Controller state info */
if (!(osh = osl_attach(pdev, SDIO_BUS, TRUE))) {
sd_err(("%s: osl_attach failed\n", __FUNCTION__));
goto err;
}
/* map to address where host can access */
pci_set_master(pdev);
rc = pci_enable_device(pdev);
if (rc) {
sd_err(("%s: Cannot enable PCI device\n", __FUNCTION__));
goto err;
}
sdioh = sdioh_attach(osh, (void *)(ulong)pci_resource_start(pdev, 0), pdev->irq);
if (sdioh == NULL) {
sd_err(("%s: sdioh_attach failed\n", __FUNCTION__));
goto err;
}
sdioh->bcmsdh = bcmsdh_probe(osh, &pdev->dev, sdioh, NULL, PCI_BUS, -1, -1);
if (sdioh->bcmsdh == NULL) {
sd_err(("%s: bcmsdh_probe failed\n", __FUNCTION__));
goto err;
}
pci_set_drvdata(pdev, sdioh);
return 0;
err:
if (sdioh != NULL)
sdioh_detach(osh, sdioh);
if (osh != NULL)
osl_detach(osh);
return -ENOMEM;
}
/**
* Detach from target devices and SDIO Host Controller
*/
static void __devexit
bcmsdh_pci_remove(struct pci_dev *pdev)
{
sdioh_info_t *sdioh;
osl_t *osh;
sdioh = pci_get_drvdata(pdev);
if (sdioh == NULL) {
sd_err(("%s: error, no sdioh handler found\n", __FUNCTION__));
return;
}
osh = sdioh->osh;
bcmsdh_remove(sdioh->bcmsdh);
sdioh_detach(osh, sdioh);
osl_detach(osh);
}
int bcmsdh_register_client_driver(void)
{
return pci_module_init(&bcmsdh_pci_driver);
}
void bcmsdh_unregister_client_driver(void)
{
pci_unregister_driver(&bcmsdh_pci_driver);
}

View File

@@ -1,14 +1,14 @@
/*
* Broadcom BCMSDH to gSPI Protocol Conversion Layer
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,18 +16,17 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmspibrcm.c 611787 2016-01-12 06:07:27Z $
* $Id$
*/
#ifdef BCMDONGLEHOST
#define HSMODE
#else
#endif /* BCMDONGLEHOST */
#include <typedefs.h>
@@ -45,18 +44,29 @@
#include <sdiovar.h> /* ioctl/iovars */
#include <sdio.h> /* SDIO Device and Protocol Specs */
#if defined(linux)
#include <pcicfg.h>
#endif
/* XXX Quick NDIS hack */
#ifdef NDIS
#define inline __inline
#define PCI_CFG_VID 0
#define PCI_CFG_BAR0 0x10
#endif
#include <bcmspibrcm.h>
#ifdef BCMSPI_ANDROID
extern void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen);
#else
#include <bcmspi.h>
#endif /* BCMSPI_ANDROID */
/* these are for the older cores... for newer cores we have control for each of them */
#define F0_RESPONSE_DELAY 16
#define F1_RESPONSE_DELAY 16
#define F2_RESPONSE_DELAY F0_RESPONSE_DELAY
#define GSPI_F0_RESP_DELAY 0
#define GSPI_F1_RESP_DELAY F1_RESPONSE_DELAY
#define GSPI_F2_RESP_DELAY 0
@@ -65,17 +75,16 @@
#define CMDLEN 4
/* Globals */
#if defined(DHD_DEBUG)
#if defined(BCMDBG) || defined(DHD_DEBUG)
uint sd_msglevel = SDH_ERROR_VAL;
#else
uint sd_msglevel = 0;
#endif
#endif /* BCMDBG || DHD_DEBUG */
uint sd_hiok = FALSE; /* Use hi-speed mode if available? */
uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */
uint sd_f2_blocksize = 64; /* Default blocksize */
uint sd_divisor = 2;
uint sd_power = 1; /* Default to SD Slot powered ON */
uint sd_clock = 1; /* Default to SD Clock turned ON */
@@ -91,10 +100,21 @@ uint8 spi_inbuf[SPI_MAX_PKT_LEN];
#define BUF2_PKT_LEN 128
uint8 spi_outbuf2[BUF2_PKT_LEN];
uint8 spi_inbuf2[BUF2_PKT_LEN];
#ifdef BCMSPI_ANDROID
uint *dhd_spi_lockcount = NULL;
#endif /* BCMSPI_ANDROID */
#if !(defined(SPI_PIO_RW_BIGENDIAN) && defined(SPI_PIO_32BIT_RW))
#define SPISWAP_WD4(x) bcmswap32(x);
#define SPISWAP_WD2(x) (bcmswap16(x & 0xffff)) | \
(bcmswap16((x & 0xffff0000) >> 16) << 16);
#else
/* XXX Some SPI host controller changes endianness when writing/reading
* to/from SPI device TX/RX register in case the bits_per_word is more than 1 byte.
*/
#define SPISWAP_WD4(x) x;
#define SPISWAP_WD2(x) bcmswap32by16(x);
#endif
/* Prototypes */
static bool bcmspi_test_card(sdioh_info_t *sd);
@@ -137,11 +157,15 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq)
return NULL;
}
#ifndef BCMSPI_ANDROID
sd->bar0 = bar0;
#endif /* !BCMSPI_ANDROID */
sd->irq = irq;
#ifndef BCMSPI_ANDROID
sd->intr_handler = NULL;
sd->intr_handler_arg = NULL;
sd->intr_handler_valid = FALSE;
#endif /* !BCMSPI_ANDROID */
/* Set defaults */
sd->use_client_ints = TRUE;
@@ -152,17 +176,24 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq)
*/
sd->wordlen = 2;
#ifdef BCMSPI_ANDROID
dhd_spi_lockcount = &sd->lockcount;
#endif /* BCMSPI_ANDROID */
#ifndef BCMSPI_ANDROID
if (!spi_hw_attach(sd)) {
sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__));
spi_osfree(sd);
MFREE(sd->osh, sd, sizeof(sdioh_info_t));
return (NULL);
}
#endif /* !BCMSPI_ANDROID */
if (bcmspi_driver_init(sd) != SUCCESS) {
sd_err(("%s: bcmspi_driver_init() failed()\n", __FUNCTION__));
#ifndef BCMSPI_ANDROID
spi_hw_detach(sd);
#endif /* !BCMSPI_ANDROID */
spi_osfree(sd);
MFREE(sd->osh, sd, sizeof(sdioh_info_t));
return (NULL);
@@ -170,7 +201,9 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq)
if (spi_register_irq(sd, irq) != SUCCESS) {
sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq));
#ifndef BCMSPI_ANDROID
spi_hw_detach(sd);
#endif /* !BCMSPI_ANDROID */
spi_osfree(sd);
MFREE(sd->osh, sd, sizeof(sdioh_info_t));
return (NULL);
@@ -188,8 +221,13 @@ sdioh_detach(osl_t *osh, sdioh_info_t *sd)
if (sd) {
sd_err(("%s: detaching from hardware\n", __FUNCTION__));
spi_free_irq(sd->irq, sd);
#ifndef BCMSPI_ANDROID
spi_hw_detach(sd);
#endif /* !BCMSPI_ANDROID */
spi_osfree(sd);
#ifdef BCMSPI_ANDROID
dhd_spi_lockcount = NULL;
#endif /* !BCMSPI_ANDROID */
MFREE(sd->osh, sd, sizeof(sdioh_info_t));
}
return SDIOH_API_RC_SUCCESS;
@@ -223,12 +261,14 @@ sdioh_interrupt_deregister(sdioh_info_t *sd)
extern SDIOH_API_RC
sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
{
#ifndef BCMSPI_ANDROID
sd_trace(("%s: Entering\n", __FUNCTION__));
*onoff = sd->client_intr_enabled;
#endif /* !BCMSPI_ANDROID */
return SDIOH_API_RC_SUCCESS;
}
#if defined(DHD_DEBUG)
#if defined(DHD_DEBUG) || defined(BCMDBG)
extern bool
sdioh_interrupt_pending(sdioh_info_t *sd)
{
@@ -279,7 +319,6 @@ sdioh_dwordmode(sdioh_info_t *sd, bool set)
}
}
uint
sdioh_query_iofnum(sdioh_info_t *sd)
{
@@ -321,6 +360,9 @@ const bcm_iovar_t sdioh_iovars[] = {
{"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 },
{"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100},
{"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0},
#ifdef BCMDBG
{"sd_hciregs", IOV_HCIREGS, 0, IOVT_BUFFER, 0 },
#endif
{"spi_errstats", IOV_SPIERRSTATS, 0, IOVT_BUFFER, sizeof(struct spierrstats_t) },
{"spi_respdelay", IOV_RESP_DELAY_ALL, 0, IOVT_BOOL, 0 },
{NULL, 0, 0, 0, 0 }
@@ -328,11 +370,11 @@ const bcm_iovar_t sdioh_iovars[] = {
int
sdioh_iovar_op(sdioh_info_t *si, const char *name,
void *params, int plen, void *arg, int len, bool set)
void *params, int plen, void *arg, uint len, bool set)
{
const bcm_iovar_t *vi = NULL;
int bcmerror = 0;
int val_size;
uint val_size;
int32 int_val = 0;
bool bool_val;
uint32 actionid;
@@ -357,6 +399,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name,
if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0)
goto exit;
/* XXX Copied from dhd, copied from wl; certainly overkill here? */
/* Set up params so get and set can share the convenience variables */
if (params == NULL) {
params = arg;
@@ -417,6 +460,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name,
bcopy(&int_val, arg, val_size);
break;
#ifndef BCMSPI_ANDROID
case IOV_SVAL(IOV_DIVISOR):
sd_divisor = int_val;
if (!spi_start_clock(si, (uint16)sd_divisor)) {
@@ -424,6 +468,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name,
bcmerror = BCME_ERROR;
}
break;
#endif /* !BCMSPI_ANDROID */
case IOV_GVAL(IOV_POWER):
int_val = (uint32)sd_power;
@@ -479,6 +524,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name,
break;
case IOV_GVAL(IOV_DEVREG):
{
/* XXX Should copy for alignment reasons */
sdreg_t *sd_ptr = (sdreg_t *)params;
uint8 data;
@@ -494,6 +540,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name,
case IOV_SVAL(IOV_DEVREG):
{
/* XXX Should copy for alignment reasons */
sdreg_t *sd_ptr = (sdreg_t *)params;
uint8 data = (uint8)sd_ptr->value;
@@ -504,6 +551,21 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name,
break;
}
#ifdef BCMDBG
case IOV_GVAL(IOV_HCIREGS):
{
struct bcmstrbuf b;
bcm_binit(&b, arg, len);
spi_lock(si);
bcm_bprintf(&b, "Unsupported\n");
spi_unlock(si);
if (!b.size)
bcmerror = BCME_BUFTOOSHORT;
break;
}
#endif /* BCMDBG */
case IOV_GVAL(IOV_SPIERRSTATS):
{
@@ -550,6 +612,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name,
}
exit:
/* XXX Remove protective lock after clients all clean... */
return bcmerror;
}
@@ -568,6 +631,9 @@ sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
/* No lock needed since sdioh_request_byte does locking */
SDIOH_API_RC status;
/* WAR for gSPI for PR55208: Read SFC_WF_TERM before write for write to be
* successful on address SBSDIO_FUNC1_FRAMECTRL.
*/
if ((fnc_num == SPI_FUNC_1) && (addr == SBSDIO_FUNC1_FRAMECTRL)) {
uint8 dummy_data;
status = sdioh_cfg_read(sd, fnc_num, addr, &dummy_data);
@@ -588,7 +654,7 @@ sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length)
int offset;
uint32 cis_byte;
uint16 *cis = (uint16 *)cisd;
uint bar0 = SI_ENUM_BASE;
uint bar0 = SI_ENUM_BASE(sd->sih);
int status;
uint8 data;
@@ -752,6 +818,11 @@ bcmspi_card_byterewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 byte)
sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg));
#ifdef BCMDBG
/* Fill up buffers with a value that generates known dutycycle on MOSI/MISO lines. */
memset(spi_outbuf2, 0xee, BUF2_PKT_LEN);
memset(spi_inbuf2, 0xee, BUF2_PKT_LEN);
#endif /* BCMDBG */
/* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen
* according to the wordlen mode(16/32bit) the device is in.
@@ -838,6 +909,11 @@ bcmspi_resync_f1(sdioh_info_t *sd)
{
uint32 cmd_arg = GSPI_RESYNC_PATTERN, data = 0, datalen = 0;
#ifdef BCMDBG
/* Fill up buffers with a value that generates known dutycycle on MOSI/MISO lines. */
memset(spi_outbuf2, 0xee, BUF2_PKT_LEN);
memset(spi_inbuf2, 0xee, BUF2_PKT_LEN);
#endif /* BCMDBG */
/* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen
* according to the wordlen mode(16/32bit) the device is in.
@@ -968,6 +1044,14 @@ sdioh_waitlockfree(sdioh_info_t *sd)
return SUCCESS;
}
#ifdef BCMINTERNAL
extern SDIOH_API_RC
sdioh_test_diag(sdioh_info_t *sd)
{
sd_err(("%s: Implement me\n", __FUNCTION__));
return (0);
}
#endif /* BCMINTERNAL */
/*
* Private/Static work routines
@@ -1022,6 +1106,7 @@ bcmspi_client_init(sdioh_info_t *sd)
uint32 status_en_reg = 0;
sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot));
#ifndef BCMSPI_ANDROID
#ifdef HSMODE
if (!spi_start_clock(sd, (uint16)sd_divisor)) {
sd_err(("spi_start_clock failed\n"));
@@ -1034,6 +1119,7 @@ bcmspi_client_init(sdioh_info_t *sd)
return ERROR;
}
#endif /* HSMODE */
#endif /* !BCMSPI_ANDROID */
if (!bcmspi_host_device_init_adapt(sd)) {
sd_err(("bcmspi_host_device_init_adapt failed\n"));
@@ -1066,11 +1152,13 @@ bcmspi_client_init(sdioh_info_t *sd)
}
#ifndef HSMODE
#ifndef BCMSPI_ANDROID
/* After configuring for High-Speed mode, set the desired clock rate. */
if (!spi_start_clock(sd, 4)) {
sd_err(("spi_start_clock failed\n"));
return ERROR;
}
#endif /* !BCMSPI_ANDROID */
#endif /* HSMODE */
/* check to see if the response delay needs to be programmed properly */
@@ -1117,14 +1205,34 @@ bcmspi_client_init(sdioh_info_t *sd)
}
}
/* XXX:Cleanup after finding a common place in dhd or bcmsdh layer to do this */
#ifndef BCMDONGLEHOST
if ((status = bcmspi_card_regwrite(sd, 1, SBSDIO_FUNC1_SBADDRLOW, 4,
SB_ENUM_BASE >> 8)) != SUCCESS)
return FALSE;
#endif
sd->card_init_done = TRUE;
#ifdef BCMDBG
{
uint8 regbuf[32];
int j;
bzero(regbuf, 32);
/* Read default F0 registers */
sd_trace(("Reading default values of first 32(8bit) F0 spid regs again before"
" quitting init.\n"));
bcmspi_card_regread(sd, 0, SPID_CONFIG, 32, (uint32 *)regbuf);
for (j = 0; j < 32; j++)
sd_trace(("regbuf[%d]=0x%x \n", j, regbuf[j]));
sd_trace(("\n"));
}
#endif /* BCMDBG */
/* get the device rev to program the prop respdelays */
return SUCCESS;
}
/* XXX What is clock rate at high and low speeds ? */
static int
bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode)
{
@@ -1137,7 +1245,6 @@ bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode)
sd_trace(("In %s spih-ctrl = 0x%x \n", __FUNCTION__, regdata));
if (hsmode == TRUE) {
sd_trace(("Attempting to enable High-Speed mode.\n"));
@@ -1167,7 +1274,9 @@ bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode)
return status;
}
}
#ifndef BCMSPI_ANDROID
spi_controller_highspeed_mode(sd, hsmode);
#endif /* !BCMSPI_ANDROID */
return TRUE;
}
@@ -1199,6 +1308,11 @@ bcmspi_host_device_init_adapt(sdioh_info_t *sd)
uint32 wrregdata, regdata = 0;
int status;
int i;
#ifdef BCMDBG
int j;
uint8 regbuf[32];
bzero(regbuf, 32);
#endif /* BCMDBG */
/* Due to a silicon testability issue, the first command from the Host
* to the device will get corrupted (first bit will be lost). So the
@@ -1279,6 +1393,9 @@ bcmspi_host_device_init_adapt(sdioh_info_t *sd)
#if defined(CHANGE_SPI_INTR_POLARITY_ACTIVE_HIGH)
/* Change to host controller intr-polarity of active-high */
/* XXX With intr-polarity active-high, host platform does not go into suspend mode
* since the pin is asserted high.
*/
wrregdata |= INTR_POLARITY;
#else
/* Change to host controller intr-polarity of active-low */
@@ -1307,6 +1424,14 @@ bcmspi_host_device_init_adapt(sdioh_info_t *sd)
}
}
#ifdef BCMDBG
/* Read default F0 registers */
sd_trace(("Reading default values of first 32(8bit) F0 spid regs\n"));
bcmspi_card_regread(sd, 0, SPID_CONFIG, 32, (uint32 *)regbuf);
for (j = 0; j < 32; j++)
sd_trace(("regbuf[%d]=0x%x \n", j, regbuf[j]));
sd_trace(("\n"));
#endif /* BCMDBG */
return TRUE;
}
@@ -1316,6 +1441,10 @@ bcmspi_test_card(sdioh_info_t *sd)
{
uint32 regdata;
int status;
#ifdef BCMDBG
uint8 regbuf[32];
bzero(regbuf, 32);
#endif /* BCMDBG */
if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, &regdata)) != SUCCESS)
return FALSE;
@@ -1327,7 +1456,6 @@ bcmspi_test_card(sdioh_info_t *sd)
return FALSE;
}
#define RW_PATTERN1 0xA0A1A2A3
#define RW_PATTERN2 0x4B5B6B7B
@@ -1519,6 +1647,11 @@ bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg,
uint16 templen, buslen, len, *ptr = NULL;
sd_trace(("spi cmd = 0x%x\n", cmd_arg));
#ifdef BCMDBG
/* Fill up buffer with known pattern */
memset(spi_outbuf, 0xee, SPI_MAX_PKT_LEN);
memset(spi_inbuf, 0xee, SPI_MAX_PKT_LEN);
#endif /* BCMDBG */
/* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen
* according to the wordlen mode(16/32bit) the device is in.
@@ -1589,7 +1722,23 @@ bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg,
/* +4 for cmd and +4 for dstatus */
hostlen = datalen + 8 + resp_delay;
hostlen += dstatus_idx;
#ifdef BCMSPI_ANDROID
if (hostlen%4) {
sd_err(("Unaligned data len %d, hostlen %d\n",
datalen, hostlen));
#endif /* BCMSPI_ANDROID */
hostlen += (4 - (hostlen & 0x3));
#ifdef BCMSPI_ANDROID
}
#endif /* BCMSPI_ANDROID */
#ifdef BCMDBG
if ((GFIELD(cmd_arg, SPI_RW_FLAG) == 1) &&
(sd->dwordmode) &&
(GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) {
sd_trace(("len/~len/spilen/hostlen=0x%x/0x%x/0x%x/0x%x\n",
*ptr, ~*(ptr+1), spilen, hostlen));
}
#endif /* BCMDBG */
spi_sendrecv(sd, spi_outbuf, spi_inbuf, hostlen);
/* for Read, get the data into the input buffer */
@@ -1623,6 +1772,10 @@ bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg,
}
err = bcmspi_update_stats(sd, cmd_arg);
#ifdef BCMDBG
if (err)
prhex("Overflowing frame", (uint8 *)data, datalen);
#endif /* BCMDBG */
return err;
@@ -1651,6 +1804,9 @@ bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo,
/* Frame len check limited by gSPI. */
if ((nbytes > 2000) && write) {
sd_trace((">2KB write: F2 wr of %d bytes\n", nbytes));
#ifdef BCMDBG
prhex("Host for gSPI", (uint8 *)data, 32);
#endif /* BCMDBG */
}
/* ASSERT(nbytes <= 2048); Fix bigger len gspi issue and uncomment. */
/* If F2 fifo on device is not ready to receive data, don't do F2 transfer */
@@ -1711,7 +1867,6 @@ bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo,
__FUNCTION__, write ? "Wd" : "Rd", func, "INCR",
addr, nbytes, sd->r_cnt, sd->t_cnt));
if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, nbytes)) != SUCCESS) {
sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__,
(write ? "write" : "read")));
@@ -1726,6 +1881,9 @@ bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo,
if ((nbytes > 2000) && !write) {
sd_trace((">2KB read: F2 rd of %d bytes\n", nbytes));
#ifdef BCMDBG
prhex("Host for gSPI", (uint8 *)data, 32);
#endif /* BCMDBG */
}
return SUCCESS;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Broadcom Secure Standard Library.
*
* Copyright (C) 1999-2019, Broadcom.
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -18,17 +17,10 @@
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id $
* <<Broadcom-WL-IPTag/Dual:>>
*/
#include <bcm_cfg.h>
#include <typedefs.h>
#include <bcmdefs.h>
#ifdef BCMDRIVER
@@ -41,6 +33,15 @@
#include <bcmstdlib_s.h>
#include <bcmutils.h>
/* Don't use compiler builtins for stdlib APIs within the implementation of the stdlib itself. */
#if defined(BCM_STDLIB_S_BUILTINS_TEST)
#undef memmove_s
#undef memcpy_s
#undef memset_s
#undef strlcpy
#undef strlcat_s
#endif /* BCM_STDLIB_S_BUILTINS_TEST */
/*
* __SIZE_MAX__ value is depending on platform:
* Firmware Dongle: RAMSIZE (Dongle Specific Limit).
@@ -49,14 +50,18 @@
*/
#ifndef SIZE_MAX
#ifndef __SIZE_MAX__
#ifdef DONGLEBUILD
#define __SIZE_MAX__ RAMSIZE
#else
#define __SIZE_MAX__ 0xFFFFFFFFu
#endif /* DONGLEBUILD */
#endif /* __SIZE_MAX__ */
#define SIZE_MAX __SIZE_MAX__
#endif /* SIZE_MAX */
#define RSIZE_MAX (SIZE_MAX >> 1u)
#if !defined(__STDC_WANT_SECURE_LIB__) && !(defined(__STDC_LIB_EXT1__) && \
defined(__STDC_WANT_LIB_EXT1__))
#if !defined(__STDC_WANT_SECURE_LIB__) && \
!(defined(__STDC_LIB_EXT1__) && defined(__STDC_WANT_LIB_EXT1__))
/*
* memmove_s - secure memmove
* dest : pointer to the object to copy to
@@ -110,7 +115,7 @@ exit:
* than RSIZE_MAX, writes destsz zero bytes into the dest object.
*/
int
memcpy_s(void *dest, size_t destsz, const void *src, size_t n)
BCMPOSTTRAPFN(memcpy_s)(void *dest, size_t destsz, const void *src, size_t n)
{
int err = BCME_OK;
char *d = dest;
@@ -161,7 +166,7 @@ exit:
* than RSIZE_MAX, writes destsz bytes with value c into the dest object.
*/
int
memset_s(void *dest, size_t destsz, int c, size_t n)
BCMPOSTTRAPFN(memset_s)(void *dest, size_t destsz, int c, size_t n)
{
int err = BCME_OK;
if ((!dest) || (((char *)dest + destsz) < (char *)dest)) {
@@ -186,13 +191,13 @@ exit:
}
#endif /* !__STDC_WANT_SECURE_LIB__ && !(__STDC_LIB_EXT1__ && __STDC_WANT_LIB_EXT1__) */
#if 0
#if !defined(FREEBSD) && !defined(MACOSX) && !defined(BCM_USE_PLATFORM_STRLCPY)
/**
* strlcpy - Copy a %NUL terminated string into a sized buffer
* @dest: Where to copy the string to
* @src: Where to copy the string from
* @size: size of destination buffer 0 if input parameters are NOK
* return: string leng of src (assume src is NUL terminated)
* return: string leng of src (which is always < size) on success or size on failure
*
* Compatible with *BSD: the result is always a valid
* NUL-terminated string that fits in the buffer (unless,
@@ -201,46 +206,32 @@ exit:
*/
size_t strlcpy(char *dest, const char *src, size_t size)
{
const char *s = src;
size_t n;
size_t i;
if (dest == NULL) {
if (dest == NULL || size == 0) {
return 0;
}
/* terminate dest if src is NULL and return 0 as only NULL was added */
if (s == NULL) {
if (src == NULL) {
*dest = '\0';
return 0;
}
/* allows us to handle size 0 */
if (size == 0) {
n = 0;
} else {
n = size - 1u;
for (i = 0; i < size; i++) {
dest[i] = src[i];
if (dest[i] == '\0') {
/* success - src string copied */
return i;
}
}
/* perform copy */
while (*s && n != 0) {
*dest++ = *s++;
n--;
}
/* NULL terminate since not found in src */
dest[size - 1u] = '\0';
*dest = '\0';
/* count to end of s or compensate for NULL */
if (n == 0) {
while (*s++)
;
} else {
s++;
}
/* return bytes copied not accounting NUL */
return (s - src - 1u);
/* fail - src string truncated */
return size;
}
#endif // endif
#endif /* !defined(FREEBSD) && !defined(MACOSX) && !defined(BCM_USE_PLATFORM_STRLCPY) */
/**
* strlcat_s - Concatenate a %NUL terminated string with a sized buffer

File diff suppressed because it is too large Load Diff

View File

@@ -1,645 +0,0 @@
/*
* Misc utility routines for WL and Apps
* This header file housing the define and function prototype use by
* both the wl driver, tools & Apps.
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmwifi_channels.h 612483 2016-01-14 03:44:27Z $
*/
#ifndef _bcmwifi_channels_h_
#define _bcmwifi_channels_h_
/* A chanspec holds the channel number, band, bandwidth and control sideband */
typedef uint16 chanspec_t;
/* channel defines */
#define CH_UPPER_SB 0x01
#define CH_LOWER_SB 0x02
#define CH_EWA_VALID 0x04
#define CH_80MHZ_APART 16
#define CH_40MHZ_APART 8
#define CH_20MHZ_APART 4
#define CH_10MHZ_APART 2
#define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */
#define CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */
/* maximum # channels the s/w supports */
#define MAXCHANNEL 224 /* max # supported channels. The max channel no is above,
* this is that + 1 rounded up to a multiple of NBBY (8).
* DO NOT MAKE it > 255: channels are uint8's all over
*/
#define MAXCHANNEL_NUM (MAXCHANNEL - 1) /* max channel number */
/* channel bitvec */
typedef struct {
uint8 vec[MAXCHANNEL/8]; /* bitvec of channels */
} chanvec_t;
/* make sure channel num is within valid range */
#define CH_NUM_VALID_RANGE(ch_num) ((ch_num) > 0 && (ch_num) <= MAXCHANNEL_NUM)
#define CHSPEC_CTLOVLP(sp1, sp2, sep) \
(ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < (sep))
/* All builds use the new 11ac ratespec/chanspec */
#undef D11AC_IOTYPES
#define D11AC_IOTYPES
#define WL_CHANSPEC_CHAN_MASK 0x00ff
#define WL_CHANSPEC_CHAN_SHIFT 0
#define WL_CHANSPEC_CHAN1_MASK 0x000f
#define WL_CHANSPEC_CHAN1_SHIFT 0
#define WL_CHANSPEC_CHAN2_MASK 0x00f0
#define WL_CHANSPEC_CHAN2_SHIFT 4
#define WL_CHANSPEC_CTL_SB_MASK 0x0700
#define WL_CHANSPEC_CTL_SB_SHIFT 8
#define WL_CHANSPEC_CTL_SB_LLL 0x0000
#define WL_CHANSPEC_CTL_SB_LLU 0x0100
#define WL_CHANSPEC_CTL_SB_LUL 0x0200
#define WL_CHANSPEC_CTL_SB_LUU 0x0300
#define WL_CHANSPEC_CTL_SB_ULL 0x0400
#define WL_CHANSPEC_CTL_SB_ULU 0x0500
#define WL_CHANSPEC_CTL_SB_UUL 0x0600
#define WL_CHANSPEC_CTL_SB_UUU 0x0700
#define WL_CHANSPEC_CTL_SB_LL WL_CHANSPEC_CTL_SB_LLL
#define WL_CHANSPEC_CTL_SB_LU WL_CHANSPEC_CTL_SB_LLU
#define WL_CHANSPEC_CTL_SB_UL WL_CHANSPEC_CTL_SB_LUL
#define WL_CHANSPEC_CTL_SB_UU WL_CHANSPEC_CTL_SB_LUU
#define WL_CHANSPEC_CTL_SB_L WL_CHANSPEC_CTL_SB_LLL
#define WL_CHANSPEC_CTL_SB_U WL_CHANSPEC_CTL_SB_LLU
#define WL_CHANSPEC_CTL_SB_LOWER WL_CHANSPEC_CTL_SB_LLL
#define WL_CHANSPEC_CTL_SB_UPPER WL_CHANSPEC_CTL_SB_LLU
#define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL
#define WL_CHANSPEC_BW_MASK 0x3800
#define WL_CHANSPEC_BW_SHIFT 11
#define WL_CHANSPEC_BW_5 0x0000
#define WL_CHANSPEC_BW_10 0x0800
#define WL_CHANSPEC_BW_20 0x1000
#define WL_CHANSPEC_BW_40 0x1800
#define WL_CHANSPEC_BW_80 0x2000
#define WL_CHANSPEC_BW_160 0x2800
#define WL_CHANSPEC_BW_8080 0x3000
#define WL_CHANSPEC_BW_2P5 0x3800
#define WL_CHANSPEC_BAND_MASK 0xc000
#define WL_CHANSPEC_BAND_SHIFT 14
#define WL_CHANSPEC_BAND_2G 0x0000
#define WL_CHANSPEC_BAND_3G 0x4000
#define WL_CHANSPEC_BAND_4G 0x8000
#define WL_CHANSPEC_BAND_5G 0xc000
#define INVCHANSPEC 255
#define MAX_CHANSPEC 0xFFFF
#define WL_CHANNEL_BAND(ch) (((ch) <= CH_MAX_2G_CHANNEL) ? \
WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)
/* channel defines */
#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \
((channel) - CH_10MHZ_APART) : 0)
#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \
((channel) + CH_10MHZ_APART) : 0)
#define LL_20_SB(channel) (((channel) > 3 * CH_10MHZ_APART) ? ((channel) - 3 * CH_10MHZ_APART) : 0)
#define UU_20_SB(channel) (((channel) < (MAXCHANNEL - 3 * CH_10MHZ_APART)) ? \
((channel) + 3 * CH_10MHZ_APART) : 0)
#define LU_20_SB(channel) LOWER_20_SB(channel)
#define UL_20_SB(channel) UPPER_20_SB(channel)
#define LOWER_40_SB(channel) ((channel) - CH_20MHZ_APART)
#define UPPER_40_SB(channel) ((channel) + CH_20MHZ_APART)
#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX)
#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \
(((channel) <= CH_MAX_2G_CHANNEL) ? \
WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G))
#define CH2P5MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_2P5 | \
(((channel) <= CH_MAX_2G_CHANNEL) ? \
WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G))
#define CH5MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_5 | \
(((channel) <= CH_MAX_2G_CHANNEL) ? \
WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G))
#define CH10MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_10 | \
(((channel) <= CH_MAX_2G_CHANNEL) ? \
WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G))
#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \
((channel) + CH_20MHZ_APART) : 0)
#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \
((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \
((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \
WL_CHANSPEC_BAND_5G))
#define CH80MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \
((channel) | (ctlsb) | \
WL_CHANSPEC_BW_80 | WL_CHANSPEC_BAND_5G)
#define CH160MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \
((channel) | (ctlsb) | \
WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G)
#define CHBW_CHSPEC(bw, channel) (chanspec_t)((chanspec_t)(channel) | (bw) | \
(((channel) <= CH_MAX_2G_CHANNEL) ? \
WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G))
/* simple MACROs to get different fields of chanspec */
#ifdef WL11AC_80P80
#define CHSPEC_CHANNEL(chspec) wf_chspec_channel(chspec)
#else
#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK))
#endif
#define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT
#define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT
#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK)
#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK)
#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK)
#ifdef WL11N_20MHZONLY
#ifdef WL11ULB
#define CHSPEC_IS2P5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_2P5)
#define CHSPEC_IS5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_5)
#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10)
#else
#define CHSPEC_IS2P5(chspec) 0
#define CHSPEC_IS5(chspec) 0
#define CHSPEC_IS10(chspec) 0
#endif
#define CHSPEC_IS20(chspec) 1
#define CHSPEC_IS20_2G(chspec) ((((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) && \
CHSPEC_IS2G(chspec))
#ifndef CHSPEC_IS40
#define CHSPEC_IS40(chspec) 0
#endif
#ifndef CHSPEC_IS80
#define CHSPEC_IS80(chspec) 0
#endif
#ifndef CHSPEC_IS160
#define CHSPEC_IS160(chspec) 0
#endif
#ifndef CHSPEC_IS8080
#define CHSPEC_IS8080(chspec) 0
#endif
#define BW_LE20(bw) TRUE
#define CHSPEC_ISLE20(chspec) TRUE
#else /* !WL11N_20MHZONLY */
#define CHSPEC_IS2P5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_2P5)
#define CHSPEC_IS5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_5)
#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10)
#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20)
#define CHSPEC_IS20_5G(chspec) ((((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) && \
CHSPEC_IS5G(chspec))
#ifndef CHSPEC_IS40
#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)
#endif
#ifndef CHSPEC_IS80
#define CHSPEC_IS80(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80)
#endif
#ifndef CHSPEC_IS160
#define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160)
#endif
#ifndef CHSPEC_IS8080
#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080)
#endif
#ifdef WL11ULB
#define BW_LT20(bw) (((bw) == WL_CHANSPEC_BW_2P5) || \
((bw) == WL_CHANSPEC_BW_5) || \
((bw) == WL_CHANSPEC_BW_10))
#define CHSPEC_BW_LT20(chspec) (BW_LT20(CHSPEC_BW(chspec)))
/* This MACRO is strictly to avoid abandons in existing code with ULB feature and is in no way
* optimial to use. Should be replaced with CHSPEC_BW_LE() instead
*/
#define BW_LE20(bw) (((bw) == WL_CHANSPEC_BW_2P5) || \
((bw) == WL_CHANSPEC_BW_5) || \
((bw) == WL_CHANSPEC_BW_10) || \
((bw) == WL_CHANSPEC_BW_20))
#define CHSPEC_ISLE20(chspec) (BW_LE20(CHSPEC_BW(chspec)))
#else /* WL11ULB */
#define BW_LE20(bw) ((bw) == WL_CHANSPEC_BW_20)
#define CHSPEC_ISLE20(chspec) (CHSPEC_IS20(chspec))
#endif /* WL11ULB */
#endif /* !WL11N_20MHZONLY */
#define BW_LE40(bw) (BW_LE20(bw) || ((bw) == WL_CHANSPEC_BW_40))
#define BW_LE80(bw) (BW_LE40(bw) || ((bw) == WL_CHANSPEC_BW_80))
#define BW_LE160(bw) (BW_LE80(bw) || ((bw) == WL_CHANSPEC_BW_160))
#define CHSPEC_BW_LE20(chspec) (BW_LE20(CHSPEC_BW(chspec)))
#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G)
#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G)
#define CHSPEC_SB_UPPER(chspec) \
((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) && \
(((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40))
#define CHSPEC_SB_LOWER(chspec) \
((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \
(((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40))
#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G)
/**
* Number of chars needed for wf_chspec_ntoa() destination character buffer.
*/
#define CHANSPEC_STR_LEN 20
#define CHSPEC_IS_BW_160_WIDE(chspec) (CHSPEC_BW(chspec) == WL_CHANSPEC_BW_160 ||\
CHSPEC_BW(chspec) == WL_CHANSPEC_BW_8080)
/* BW inequality comparisons, LE (<=), GE (>=), LT (<), GT (>), comparisons can be made
* as simple numeric comparisons, with the exception that 160 is the same BW as 80+80,
* but have different numeric values; (WL_CHANSPEC_BW_160 < WL_CHANSPEC_BW_8080).
*
* The LT/LE/GT/GE macros check first checks whether both chspec bandwidth and bw are 160 wide.
* If both chspec bandwidth and bw is not 160 wide, then the comparison is made.
*/
#ifdef WL11ULB
#define CHSPEC_BW_GE(chspec, bw) \
(((CHSPEC_IS_BW_160_WIDE(chspec) &&\
((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\
(CHSPEC_BW(chspec) >= (bw))) && \
(!(CHSPEC_BW(chspec) == WL_CHANSPEC_BW_2P5 && (bw) != WL_CHANSPEC_BW_2P5)))
#else /* WL11ULB */
#define CHSPEC_BW_GE(chspec, bw) \
((CHSPEC_IS_BW_160_WIDE(chspec) &&\
((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\
(CHSPEC_BW(chspec) >= (bw)))
#endif /* WL11ULB */
#ifdef WL11ULB
#define CHSPEC_BW_LE(chspec, bw) \
(((CHSPEC_IS_BW_160_WIDE(chspec) &&\
((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\
(CHSPEC_BW(chspec) <= (bw))) || \
(CHSPEC_BW(chspec) == WL_CHANSPEC_BW_2P5))
#else /* WL11ULB */
#define CHSPEC_BW_LE(chspec, bw) \
((CHSPEC_IS_BW_160_WIDE(chspec) &&\
((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\
(CHSPEC_BW(chspec) <= (bw)))
#endif /* WL11ULB */
#ifdef WL11ULB
#define CHSPEC_BW_GT(chspec, bw) \
((!(CHSPEC_IS_BW_160_WIDE(chspec) &&\
((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\
(CHSPEC_BW(chspec) > (bw))) && \
(CHSPEC_BW(chspec) != WL_CHANSPEC_BW_2P5))
#else /* WL11ULB */
#define CHSPEC_BW_GT(chspec, bw) \
(!(CHSPEC_IS_BW_160_WIDE(chspec) &&\
((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\
(CHSPEC_BW(chspec) > (bw)))
#endif /* WL11ULB */
#ifdef WL11ULB
#define CHSPEC_BW_LT(chspec, bw) \
((!(CHSPEC_IS_BW_160_WIDE(chspec) &&\
((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\
(CHSPEC_BW(chspec) < (bw))) || \
((CHSPEC_BW(chspec) == WL_CHANSPEC_BW_2P5 && (bw) != WL_CHANSPEC_BW_2P5)))
#else /* WL11ULB */
#define CHSPEC_BW_LT(chspec, bw) \
(!(CHSPEC_IS_BW_160_WIDE(chspec) &&\
((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\
(CHSPEC_BW(chspec) < (bw)))
#endif /* WL11ULB */
/* Legacy Chanspec defines
* These are the defines for the previous format of the chanspec_t
*/
#define WL_LCHANSPEC_CHAN_MASK 0x00ff
#define WL_LCHANSPEC_CHAN_SHIFT 0
#define WL_LCHANSPEC_CTL_SB_MASK 0x0300
#define WL_LCHANSPEC_CTL_SB_SHIFT 8
#define WL_LCHANSPEC_CTL_SB_LOWER 0x0100
#define WL_LCHANSPEC_CTL_SB_UPPER 0x0200
#define WL_LCHANSPEC_CTL_SB_NONE 0x0300
#define WL_LCHANSPEC_BW_MASK 0x0C00
#define WL_LCHANSPEC_BW_SHIFT 10
#define WL_LCHANSPEC_BW_10 0x0400
#define WL_LCHANSPEC_BW_20 0x0800
#define WL_LCHANSPEC_BW_40 0x0C00
#define WL_LCHANSPEC_BAND_MASK 0xf000
#define WL_LCHANSPEC_BAND_SHIFT 12
#define WL_LCHANSPEC_BAND_5G 0x1000
#define WL_LCHANSPEC_BAND_2G 0x2000
#define LCHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_LCHANSPEC_CHAN_MASK))
#define LCHSPEC_BAND(chspec) ((chspec) & WL_LCHANSPEC_BAND_MASK)
#define LCHSPEC_CTL_SB(chspec) ((chspec) & WL_LCHANSPEC_CTL_SB_MASK)
#define LCHSPEC_BW(chspec) ((chspec) & WL_LCHANSPEC_BW_MASK)
#define LCHSPEC_IS10(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_10)
#define LCHSPEC_IS20(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_20)
#define LCHSPEC_IS40(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)
#define LCHSPEC_IS5G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_5G)
#define LCHSPEC_IS2G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_2G)
#define LCHSPEC_SB_UPPER(chspec) \
((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_UPPER) && \
(((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40))
#define LCHSPEC_SB_LOWER(chspec) \
((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_LOWER) && \
(((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40))
#define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band)))
#define CH20MHZ_LCHSPEC(channel) \
(chanspec_t)((chanspec_t)(channel) | WL_LCHANSPEC_BW_20 | \
WL_LCHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \
WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G))
/*
* WF_CHAN_FACTOR_* constants are used to calculate channel frequency
* given a channel number.
* chan_freq = chan_factor * 500Mhz + chan_number * 5
*/
/**
* Channel Factor for the starting frequence of 2.4 GHz channels.
* The value corresponds to 2407 MHz.
*/
#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */
/**
* Channel Factor for the starting frequence of 5 GHz channels.
* The value corresponds to 5000 MHz.
*/
#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */
/**
* Channel Factor for the starting frequence of 4.9 GHz channels.
* The value corresponds to 4000 MHz.
*/
#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */
#define WLC_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */
/**
* No of sub-band vlaue of the specified Mhz chanspec
*/
#define WF_NUM_SIDEBANDS_40MHZ 2
#define WF_NUM_SIDEBANDS_80MHZ 4
#define WF_NUM_SIDEBANDS_8080MHZ 4
#define WF_NUM_SIDEBANDS_160MHZ 8
/**
* Convert chanspec to ascii string
*
* @param chspec chanspec format
* @param buf ascii string of chanspec
*
* @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes
* Original chanspec in case of error
*
* @see CHANSPEC_STR_LEN
*/
extern char * wf_chspec_ntoa_ex(chanspec_t chspec, char *buf);
/**
* Convert chanspec to ascii string
*
* @param chspec chanspec format
* @param buf ascii string of chanspec
*
* @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes
* NULL in case of error
*
* @see CHANSPEC_STR_LEN
*/
extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf);
/**
* Convert ascii string to chanspec
*
* @param a pointer to input string
*
* @return >= 0 if successful or 0 otherwise
*/
extern chanspec_t wf_chspec_aton(const char *a);
/**
* Verify the chanspec fields are valid.
*
* Verify the chanspec is using a legal set field values, i.e. that the chanspec
* specified a band, bw, ctl_sb and channel and that the combination could be
* legal given some set of circumstances.
*
* @param chanspec input chanspec to verify
*
* @return TRUE if the chanspec is malformed, FALSE if it looks good.
*/
extern bool wf_chspec_malformed(chanspec_t chanspec);
/**
* Verify the chanspec specifies a valid channel according to 802.11.
*
* @param chanspec input chanspec to verify
*
* @return TRUE if the chanspec is a valid 802.11 channel
*/
extern bool wf_chspec_valid(chanspec_t chanspec);
/**
* Return the primary (control) channel.
*
* This function returns the channel number of the primary 20MHz channel. For
* 20MHz channels this is just the channel number. For 40MHz or wider channels
* it is the primary 20MHz channel specified by the chanspec.
*
* @param chspec input chanspec
*
* @return Returns the channel number of the primary 20MHz channel
*/
extern uint8 wf_chspec_ctlchan(chanspec_t chspec);
/*
* Return the bandwidth string.
*
* This function returns the bandwidth string for the passed chanspec.
*
* @param chspec input chanspec
*
* @return Returns the bandwidth string
*/
extern const char *wf_chspec_to_bw_str(chanspec_t chspec);
/**
* Return the primary (control) chanspec.
*
* This function returns the chanspec of the primary 20MHz channel. For 20MHz
* channels this is just the chanspec. For 40MHz or wider channels it is the
* chanspec of the primary 20MHZ channel specified by the chanspec.
*
* @param chspec input chanspec
*
* @return Returns the chanspec of the primary 20MHz channel
*/
extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec);
/**
* Return a channel number corresponding to a frequency.
*
* This function returns the chanspec for the primary 40MHz of an 80MHz channel.
* The control sideband specifies the same 20MHz channel that the 80MHz channel is using
* as the primary 20MHz channel.
*/
extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec);
/*
* Return the channel number for a given frequency and base frequency.
* The returned channel number is relative to the given base frequency.
* If the given base frequency is zero, a base frequency of 5 GHz is assumed for
* frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz.
*
* Frequency is specified in MHz.
* The base frequency is specified as (start_factor * 500 kHz).
* Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for
* 2.4 GHz and 5 GHz bands.
*
* The returned channel will be in the range [1, 14] in the 2.4 GHz band
* and [0, 200] otherwise.
* -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the
* frequency is not a 2.4 GHz channel, or if the frequency is not and even
* multiple of 5 MHz from the base frequency to the base plus 1 GHz.
*
* Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2
*
* @param freq frequency in MHz
* @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz
*
* @return Returns a channel number
*
* @see WF_CHAN_FACTOR_2_4_G
* @see WF_CHAN_FACTOR_5_G
*/
extern int wf_mhz2channel(uint freq, uint start_factor);
/**
* Return the center frequency in MHz of the given channel and base frequency.
*
* Return the center frequency in MHz of the given channel and base frequency.
* The channel number is interpreted relative to the given base frequency.
*
* The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise.
* The base frequency is specified as (start_factor * 500 kHz).
* Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for
* 2.4 GHz and 5 GHz bands.
* The channel range of [1, 14] is only checked for a start_factor of
* WF_CHAN_FACTOR_2_4_G (4814).
* Odd start_factors produce channels on .5 MHz boundaries, in which case
* the answer is rounded down to an integral MHz.
* -1 is returned for an out of range channel.
*
* Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2
*
* @param channel input channel number
* @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz
*
* @return Returns a frequency in MHz
*
* @see WF_CHAN_FACTOR_2_4_G
* @see WF_CHAN_FACTOR_5_G
*/
extern int wf_channel2mhz(uint channel, uint start_factor);
/**
* Returns the chanspec 80Mhz channel corresponding to the following input
* parameters
*
* primary_channel - primary 20Mhz channel
* center_channel - center frequecny of the 80Mhz channel
*
* The center_channel can be one of {42, 58, 106, 122, 138, 155}
*
* returns INVCHANSPEC in case of error
*/
extern chanspec_t wf_chspec_80(uint8 center_channel, uint8 primary_channel);
/**
* Convert ctl chan and bw to chanspec
*
* @param ctl_ch channel
* @param bw bandwidth
*
* @return > 0 if successful or 0 otherwise
*
*/
extern uint16 wf_channel2chspec(uint ctl_ch, uint bw);
extern uint wf_channel2freq(uint channel);
extern uint wf_freq2channel(uint freq);
/*
* Returns the 80+80 MHz chanspec corresponding to the following input parameters
*
* primary_20mhz - Primary 20 MHz channel
* chan0_80MHz - center channel number of one frequency segment
* chan1_80MHz - center channel number of the other frequency segment
*
* Parameters chan0_80MHz and chan1_80MHz are channel numbers in {42, 58, 106, 122, 138, 155}.
* The primary channel must be contained in one of the 80MHz channels. This routine
* will determine which frequency segment is the primary 80 MHz segment.
*
* Returns INVCHANSPEC in case of error.
*
* Refer to IEEE802.11ac section 22.3.14 "Channelization".
*/
extern chanspec_t wf_chspec_get8080_chspec(uint8 primary_20mhz,
uint8 chan0_80Mhz, uint8 chan1_80Mhz);
/*
* Returns the primary 80 Mhz channel for the provided chanspec
*
* chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved
*
* returns -1 in case the provided channel is 20/40 Mhz chanspec
*/
extern uint8 wf_chspec_primary80_channel(chanspec_t chanspec);
/*
* Returns the secondary 80 Mhz channel for the provided chanspec
*
* chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved
*
* returns -1 in case the provided channel is 20/40 Mhz chanspec
*/
extern uint8 wf_chspec_secondary80_channel(chanspec_t chanspec);
/*
* This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel.
*/
extern chanspec_t wf_chspec_primary80_chspec(chanspec_t chspec);
#ifdef WL11AC_80P80
/*
* This function returns the centre chanel for the given chanspec.
* In case of 80+80 chanspec it returns the primary 80 Mhz centre channel
*/
extern uint8 wf_chspec_channel(chanspec_t chspec);
#endif
extern chanspec_t wf_channel_create_chspec_frm_opclass(uint8 opclass, uint8 channel);
extern int wf_channel_create_opclass_frm_chspec(chanspec_t chspec);
#endif /* _bcmwifi_channels_h_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,607 @@
/*
* Common [OS-independent] rate management
* 802.11 Networking Adapter Device Driver.
*
* Broadcom Proprietary and Confidential. Copyright (C) 2020,
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
* the contents of this file may not be disclosed to third parties,
* copied or duplicated in any form, in whole or in part, without
* the prior written permission of Broadcom.
*
*
* <<Broadcom-WL-IPTag/Proprietary:>>
*/
#include <typedefs.h>
#ifdef BCMDRIVER
#include <osl.h>
#else
#include <assert.h>
#ifndef ASSERT
#define ASSERT(e) assert(e)
#endif
#ifndef ASSERT_FP
#define ASSERT_FP(e) assert(e)
#endif
#endif /* BCMDRIVER */
#include <802.11.h>
#include <802.11ax.h>
#include <bcmutils.h>
#include <bcmwifi_rspec.h>
#include <bcmwifi_rates.h>
/* TODO: Consolidate rate utility functions from wlc_rate.c and bcmwifi_monitor.c
* into here if they're shared by non wl layer as well...
*/
/* ============================================ */
/* Moved from wlc_rate.c */
/* ============================================ */
/* HE mcs info */
struct ieee_80211_mcs_rate_info {
uint8 constellation_bits;
uint8 coding_q;
uint8 coding_d;
uint8 dcm_capable; /* 1 if dcm capable */
};
static const struct ieee_80211_mcs_rate_info wlc_mcs_info[] = {
{ 1, 1, 2, 1 }, /* MCS 0: MOD: BPSK, CR 1/2, dcm capable */
{ 2, 1, 2, 1 }, /* MCS 1: MOD: QPSK, CR 1/2, dcm capable */
{ 2, 3, 4, 0 }, /* MCS 2: MOD: QPSK, CR 3/4, NOT dcm capable */
{ 4, 1, 2, 1 }, /* MCS 3: MOD: 16QAM, CR 1/2, dcm capable */
{ 4, 3, 4, 1 }, /* MCS 4: MOD: 16QAM, CR 3/4, dcm capable */
{ 6, 2, 3, 0 }, /* MCS 5: MOD: 64QAM, CR 2/3, NOT dcm capable */
{ 6, 3, 4, 0 }, /* MCS 6: MOD: 64QAM, CR 3/4, NOT dcm capable */
{ 6, 5, 6, 0 }, /* MCS 7: MOD: 64QAM, CR 5/6, NOT dcm capable */
{ 8, 3, 4, 0 }, /* MCS 8: MOD: 256QAM, CR 3/4, NOT dcm capable */
{ 8, 5, 6, 0 }, /* MCS 9: MOD: 256QAM, CR 5/6, NOT dcm capable */
{ 10, 3, 4, 0 }, /* MCS 10: MOD: 1024QAM, CR 3/4, NOT dcm capable */
{ 10, 5, 6, 0 }, /* MCS 11: MOD: 1024QAM, CR 5/6, NOT dcm capable */
#ifdef WL11BE
/* TODO: for now EHT shares this table with HE,
* create a new table if needed once we know more
* about EHT rate calculation...
*/
{ 12, 3, 4, 0 }, /* MCS 12: MOD: 4096QAM, CR 3/4, NOT dcm capable */
{ 12, 5, 6, 0 }, /* MCS 13: MOD: 4096QAM, CR 5/6, NOT dcm capable */
#endif
};
/* Nsd values Draft0.4 Table 26.63 onwards */
static const uint wlc_he_nsd[] = {
234, /* BW20 */
468, /* BW40 */
980, /* BW80 */
1960, /* BW160 */
#ifdef WL11BE
/* TODO: for now EHT shares this table with HE,
* create a new table if needed once we know more
* about EHT rate calculation...
*/
2940, /* BW240 */
3920 /* BW320 */
#endif
};
/* Nsd values Draft3.3 Table 28-15 */
static const uint wlc_he_ru_nsd[] = {
24, /* 26T */
48, /* 52T */
102, /* 106T */
234, /* 242T/BW20 */
468, /* 484T/BW40 */
980, /* 996T/BW80 */
1960, /* 2*996T/BW160 */
#ifdef WL11BE
/* TODO: for now EHT shares this table with HE,
* create a new table if needed once we know more
* about EHT rate calculation...
*/
2940, /* 3*996T/BW240 */
3920 /* 4*996T/BW320 */
#endif
};
#define HE_RU_TO_NSD(ru_idx) \
(ru_idx < ARRAYSIZE(wlc_he_ru_nsd)) ? \
wlc_he_ru_nsd[ru_idx] : 0
/* sym_len = 12.8 us. For calculation purpose, *10 */
#define HE_SYM_LEN_FACTOR (128)
/* GI values = 0.8 , 1.6 or 3.2 us. For calculation purpose, *10 */
#define HE_GI_800us_FACTOR (8)
#define HE_GI_1600us_FACTOR (16)
#define HE_GI_3200us_FACTOR (32)
/* To avoid ROM invalidation use the old macro as is... */
#ifdef WL11BE
#define HE_BW_TO_NSD(bwi) \
((bwi) > 0u && (bwi) <= ARRAYSIZE(wlc_he_nsd)) ? \
wlc_he_nsd[(bwi) - 1u] : 0u
#else
#define HE_BW_TO_NSD(bwi) \
((bwi) > 0 && ((bwi) << WL_RSPEC_BW_SHIFT) <= WL_RSPEC_BW_160MHZ) ? \
wlc_he_nsd[(bwi)-1] : 0
#endif /* WL11BE */
#define ksps 250 /* kilo symbols per sec, 4 us sym */
#ifdef WL11BE
/* Table "wlc_nsd" is derived from HT and VHT #defines below, but extended for HE
* for rate calculation purpose at a given NSS and bandwidth combination.
*
* It should and can only be used in where it wants to know the relative rate in kbps
* for a different NSS and bandwidth combination at a given mcs e.g. in fallback rate
* search. It shouldn not and can not be used in where it calculates the absolute rate
* i.e. the result doesn't agree with what the spec says otherwise.
*
* See Std 802.11-2016 "Table 21-61 VHT-MCSs for optional 160 MHz and 80+80 MHz, NSS = 8"
* for VHT, and P802.11ax/D6.0 "Table 27-111 HE-MCSs for 2x996-tone RU, NSS = 8" for HE,
* for 160Mhz bandwidth for resulting rate comparison.
*
* It's again extended for EHT 240/320Mhz bandwidth, for the same purpose.
*/
static const uint16 wlc_nsd[] = {
52, /* 20MHz */
108, /* 40MHz */
234, /* 80Mhz */
468, /* 160MHz */
702, /* 240MHz */
936, /* 320MHz */
};
#define BW_TO_NSD(bwi) \
((bwi) > 0u && (bwi) <= ARRAYSIZE(wlc_nsd)) ? \
wlc_nsd[(bwi) - 1u] : 0u
static uint
wf_nsd2ndbps(uint mcs, uint nss, uint nsd, bool dcm)
{
uint Ndbps;
/* multiply number of spatial streams,
* bits per number from the constellation,
* and coding quotient
*/
Ndbps = nsd * nss *
wlc_mcs_info[mcs].coding_q * wlc_mcs_info[mcs].constellation_bits;
/* adjust for the coding rate divisor */
Ndbps = Ndbps / wlc_mcs_info[mcs].coding_d;
/* take care of dcm: dcm divides R by 2. If not dcm mcs, ignore */
if (dcm) {
if (wlc_mcs_info[mcs].dcm_capable) {
Ndbps >>= 1u;
}
}
return Ndbps;
}
#else
/* for HT and VHT? */
#define Nsd_20MHz 52
#define Nsd_40MHz 108
#define Nsd_80MHz 234
#define Nsd_160MHz 468
#endif /* WL11BE */
uint
wf_he_mcs_to_Ndbps(uint mcs, uint nss, uint bw, bool dcm)
{
uint Nsd;
uint Ndbps;
/* find the number of complex numbers per symbol */
Nsd = HE_BW_TO_NSD(bw >> WL_RSPEC_BW_SHIFT);
#ifdef WL11BE
Ndbps = wf_nsd2ndbps(mcs, nss, Nsd, dcm);
#else
/* multiply number of spatial streams,
* bits per number from the constellation,
* and coding quotient
*/
Ndbps = Nsd * nss *
wlc_mcs_info[mcs].coding_q * wlc_mcs_info[mcs].constellation_bits;
/* adjust for the coding rate divisor */
Ndbps = Ndbps / wlc_mcs_info[mcs].coding_d;
/* take care of dcm: dcm divides R by 2. If not dcm mcs, ignore */
if (dcm) {
if (wlc_mcs_info[mcs].dcm_capable) {
Ndbps >>= 1;
}
}
#endif /* WL11BE */
return Ndbps;
}
uint32
wf_he_mcs_ru_to_ndbps(uint8 mcs, uint8 nss, bool dcm, uint8 ru_index)
{
uint32 nsd;
uint32 ndbps;
/* find the number of complex numbers per symbol */
nsd = HE_RU_TO_NSD(ru_index);
#ifdef WL11BE
ndbps = wf_nsd2ndbps(mcs, nss, nsd, dcm);
#else
/* multiply number of spatial streams,
* bits per number from the constellation,
* and coding quotient
* Ndbps = Nss x Nsd x (Nbpscs x R) x (DCM/2)
*/
ndbps = nsd * nss *
wlc_mcs_info[mcs].coding_q * wlc_mcs_info[mcs].constellation_bits;
/* adjust for the coding rate divisor */
ndbps = ndbps / wlc_mcs_info[mcs].coding_d;
/* take care of dcm: dcm divides R by 2. If not dcm mcs, ignore */
if (dcm && wlc_mcs_info[mcs].dcm_capable) {
ndbps >>= 1;
}
#endif /* WL11BE */
return ndbps;
}
/**
* Returns the rate in [Kbps] units for a caller supplied MCS/bandwidth/Nss/Sgi/dcm combination.
* 'mcs' : a *single* spatial stream MCS (11ax)
* formula as per http:
* WLAN&preview=/323036249/344457953/11ax_rate_table.xlsx
* Symbol length = 12.8 usec [given as sym_len/10 below]
* GI value = 0.8 or 1.6 or 3.2 usec [given as GI_value/10 below]
* rate (Kbps) = (Nsd * Nbpscs * nss * (coding_q/coding_d) * 1000) / ((sym_len/10) + (GI_value/10))
* Note that, for calculation purpose, following is used. [to be careful with overflows]
* rate (Kbps) = (Nsd * Nbpscs * nss * (coding_q/coding_d) * 1000) / ((sym_len + GI_value) / 10)
* rate (Kbps) = (Nsd * Nbpscs * nss * (coding_q/coding_d) * 1000) / (sym_len + GI_value) * 10
*/
uint
wf_he_mcs_to_rate(uint mcs, uint nss, uint bw, uint gi, bool dcm)
{
uint rate;
uint rate_deno;
rate = HE_BW_TO_NSD(bw >> WL_RSPEC_BW_SHIFT);
#ifdef WL11BE
rate = wf_nsd2ndbps(mcs, nss, rate, dcm);
#else
/* Nbpscs: multiply by bits per number from the constellation in use */
rate = rate * wlc_mcs_info[mcs].constellation_bits;
/* Nss: adjust for the number of spatial streams */
rate = rate * nss;
/* R: adjust for the coding rate given as a quotient and divisor */
rate = (rate * wlc_mcs_info[mcs].coding_q) / wlc_mcs_info[mcs].coding_d;
/* take care of dcm: dcm divides R by 2. If not dcm mcs, ignore */
if (dcm) {
if (wlc_mcs_info[mcs].dcm_capable) {
rate >>= 1;
}
}
#endif /* WL11BE */
/* add sym len factor */
rate_deno = HE_SYM_LEN_FACTOR;
/* get GI for denominator */
if (HE_IS_GI_3_2us(gi)) {
rate_deno += HE_GI_3200us_FACTOR;
} else if (HE_IS_GI_1_6us(gi)) {
rate_deno += HE_GI_1600us_FACTOR;
} else {
/* assuming HE_GI_0_8us */
rate_deno += HE_GI_800us_FACTOR;
}
/* as per above formula */
rate *= 1000; /* factor of 10. *100 to accommodate 2 places */
rate /= rate_deno;
rate *= 10; /* *100 was already done above. Splitting is done to avoid overflow. */
return rate;
}
uint
wf_mcs_to_Ndbps(uint mcs, uint nss, uint bw)
{
uint Nsd;
uint Ndbps;
/* This calculation works for 11n HT and 11ac VHT if the HT mcs values
* are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8.
* That is, HT MCS 23 is a base MCS = 7, Nss = 3
*/
/* find the number of complex numbers per symbol */
#ifdef WL11BE
Nsd = BW_TO_NSD(bw >> WL_RSPEC_BW_SHIFT);
Ndbps = wf_nsd2ndbps(mcs, nss, Nsd, FALSE);
#else
if (bw == WL_RSPEC_BW_20MHZ) {
Nsd = Nsd_20MHz;
} else if (bw == WL_RSPEC_BW_40MHZ) {
Nsd = Nsd_40MHz;
} else if (bw == WL_RSPEC_BW_80MHZ) {
Nsd = Nsd_80MHz;
} else if (bw == WL_RSPEC_BW_160MHZ) {
Nsd = Nsd_160MHz;
} else {
Nsd = 0;
}
/* multiply number of spatial streams,
* bits per number from the constellation,
* and coding quotient
*/
Ndbps = Nsd * nss *
wlc_mcs_info[mcs].coding_q * wlc_mcs_info[mcs].constellation_bits;
/* adjust for the coding rate divisor */
Ndbps = Ndbps / wlc_mcs_info[mcs].coding_d;
#endif /* WL11BE */
return Ndbps;
}
/**
* Returns the rate in [Kbps] units for a caller supplied MCS/bandwidth/Nss/Sgi combination.
* 'mcs' : a *single* spatial stream MCS (11n or 11ac)
*/
uint
wf_mcs_to_rate(uint mcs, uint nss, uint bw, int sgi)
{
uint rate;
if (mcs == 32) {
/* just return fixed values for mcs32 instead of trying to parametrize */
rate = (sgi == 0) ? 6000 : 6778;
} else {
/* This calculation works for 11n HT, 11ac VHT and 11ax HE if the HT mcs values
* are decomposed into a base MCS = MCS % 8, and Nss = 1 + MCS / 8.
* That is, HT MCS 23 is a base MCS = 7, Nss = 3
*/
#if defined(WLPROPRIETARY_11N_RATES)
switch (mcs) {
case 87:
mcs = 8; /* MCS 8: MOD: 256QAM, CR 3/4 */
break;
case 88:
mcs = 9; /* MCS 9: MOD: 256QAM, CR 5/6 */
break;
default:
break;
}
#endif /* WLPROPRIETARY_11N_RATES */
#ifdef WL11BE
rate = wf_mcs_to_Ndbps(mcs, nss, bw);
#else
/* find the number of complex numbers per symbol */
if (RSPEC_IS20MHZ(bw)) {
/* 4360 TODO: eliminate Phy const in rspec bw, then just compare
* as in 80 and 160 case below instead of RSPEC_IS20MHZ(bw)
*/
rate = Nsd_20MHz;
} else if (RSPEC_IS40MHZ(bw)) {
/* 4360 TODO: eliminate Phy const in rspec bw, then just compare
* as in 80 and 160 case below instead of RSPEC_IS40MHZ(bw)
*/
rate = Nsd_40MHz;
} else if (bw == WL_RSPEC_BW_80MHZ) {
rate = Nsd_80MHz;
} else if (bw == WL_RSPEC_BW_160MHZ) {
rate = Nsd_160MHz;
} else {
rate = 0;
}
/* multiply by bits per number from the constellation in use */
rate = rate * wlc_mcs_info[mcs].constellation_bits;
/* adjust for the number of spatial streams */
rate = rate * nss;
/* adjust for the coding rate given as a quotient and divisor */
rate = (rate * wlc_mcs_info[mcs].coding_q) / wlc_mcs_info[mcs].coding_d;
#endif /* WL11BE */
/* multiply by Kilo symbols per sec to get Kbps */
rate = rate * ksps;
/* adjust the symbols per sec for SGI
* symbol duration is 4 us without SGI, and 3.6 us with SGI,
* so ratio is 10 / 9
*/
if (sgi) {
/* add 4 for rounding of division by 9 */
rate = ((rate * 10) + 4) / 9;
}
}
return rate;
} /* wf_mcs_to_rate */
/* This function needs update to handle MU frame PLCP as well (MCS is conveyed via VHT-SIGB
* field in case of MU frames). Currently this support needs to be added in uCode to communicate
* MCS information for an MU frame
*
* For VHT frame:
* bit 0-3 mcs index
* bit 6-4 nsts for VHT
* bit 7: 1 for VHT
* Note: bit 7 is used to indicate to the rate sel the mcs is a non HT mcs!
*
* Essentially it's the NSS:MCS portions of the rspec
*/
uint8
wf_vht_plcp_to_rate(uint8 *plcp)
{
uint8 rate, gid;
uint nss;
uint32 plcp0 = plcp[0] + (plcp[1] << 8); /* don't need plcp[2] */
gid = (plcp0 & VHT_SIGA1_GID_MASK) >> VHT_SIGA1_GID_SHIFT;
if (gid > VHT_SIGA1_GID_TO_AP && gid < VHT_SIGA1_GID_NOT_TO_AP) {
/* for MU packet we hacked Signal Tail field in VHT-SIG-A2 to save nss and mcs,
* copy from murate in d11 rx header.
* nss = bit 18:19 (for 11ac 2 bits to indicate maximum 4 nss)
* mcs = 20:23
*/
rate = (plcp[5] & 0xF0) >> 4;
nss = ((plcp[5] & 0x0C) >> 2) + 1;
} else {
rate = (plcp[3] >> VHT_SIGA2_MCS_SHIFT);
nss = ((plcp0 & VHT_SIGA1_NSTS_SHIFT_MASK_USER0) >>
VHT_SIGA1_NSTS_SHIFT) + 1;
if (plcp0 & VHT_SIGA1_STBC)
nss = nss >> 1;
}
rate |= ((nss << WL_RSPEC_VHT_NSS_SHIFT) | WF_NON_HT_MCS);
return rate;
}
/**
* Function for computing NSS:MCS from HE SU PLCP or
* MCS:LTF-GI from HE MU PLCP
*
* based on rev3.10 :
* https://docs.google.com/spreadsheets/d/
* 1eP6ZCRrtnF924ds1R-XmbcH0IdQ0WNJpS1-FHmWeb9g/edit#gid=1492656555
*
* For HE SU frame:
* bit 0-3 mcs index
* bit 6-4 nsts for HE
* bit 7: 1 for HE
* Note: bit 7 is used to indicate to the rate sel the mcs is a non HT mcs!
* Essentially it's the NSS:MCS portions of the rspec
*
* For HE MU frame:
* bit 0-3 mcs index
* bit 4-5 LTF-GI value
* bit 6 STBC
* Essentially it's the MCS and LTF-GI portion of the rspec
*/
/* Macros to be used for calculating rate from PLCP */
#define HE_SU_PLCP2RATE_MCS_MASK 0x0F
#define HE_SU_PLCP2RATE_MCS_SHIFT 0
#define HE_SU_PLCP2RATE_NSS_MASK 0x70
#define HE_SU_PLCP2RATE_NSS_SHIFT 4
#define HE_MU_PLCP2RATE_LTF_GI_MASK 0x30
#define HE_MU_PLCP2RATE_LTF_GI_SHIFT 4
#define HE_MU_PLCP2RATE_STBC_MASK 0x40
#define HE_MU_PLCP2RATE_STBC_SHIFT 6
uint8
wf_he_plcp_to_rate(uint8 *plcp, bool is_mu)
{
uint8 rate = 0;
uint8 nss = 0;
uint32 plcp0 = 0;
uint32 plcp1 = 0;
uint8 he_ltf_gi;
uint8 stbc;
ASSERT(plcp);
BCM_REFERENCE(nss);
BCM_REFERENCE(he_ltf_gi);
plcp0 = ((plcp[3] << 24) | (plcp[2] << 16) | (plcp[1] << 8) | plcp[0]);
plcp1 = ((plcp[5] << 8) | plcp[4]);
if (!is_mu) {
/* For SU frames return rate in MCS:NSS format */
rate = ((plcp0 & HE_SU_RE_SIGA_MCS_MASK) >> HE_SU_RE_SIGA_MCS_SHIFT);
nss = ((plcp0 & HE_SU_RE_SIGA_NSTS_MASK) >> HE_SU_RE_SIGA_NSTS_SHIFT) + 1;
rate |= ((nss << HE_SU_PLCP2RATE_NSS_SHIFT) | WF_NON_HT_MCS);
} else {
/* For MU frames return rate in MCS:LTF-GI format */
rate = (plcp0 & HE_MU_SIGA_SIGB_MCS_MASK) >> HE_MU_SIGA_SIGB_MCS_SHIFT;
he_ltf_gi = (plcp0 & HE_MU_SIGA_GI_LTF_MASK) >> HE_MU_SIGA_GI_LTF_SHIFT;
stbc = (plcp1 & HE_MU_SIGA_STBC_MASK) >> HE_MU_SIGA_STBC_SHIFT;
/* LTF-GI shall take the same position as NSS */
rate |= (he_ltf_gi << HE_MU_PLCP2RATE_LTF_GI_SHIFT);
/* STBC needs to be filled in bit 6 */
rate |= (stbc << HE_MU_PLCP2RATE_STBC_SHIFT);
}
return rate;
}
/**
* Function for computing NSS:MCS from EHT SU PLCP or
* MCS:LTF-GI from EHT MU PLCP
*
* TODO: add link to the HW spec.
* FIXME: do we really need to support mu?
*/
uint8
wf_eht_plcp_to_rate(uint8 *plcp, bool is_mu)
{
BCM_REFERENCE(plcp);
BCM_REFERENCE(is_mu);
ASSERT(!"wf_eht_plcp_to_rate: not implemented!");
return 0;
}
/* ============================================ */
/* Moved from wlc_rate_def.c */
/* ============================================ */
/**
* Some functions require a single stream MCS as an input parameter. Given an MCS, this function
* returns the single spatial stream MCS equivalent.
*/
uint8
wf_get_single_stream_mcs(uint mcs)
{
if (mcs < 32) {
return mcs % 8;
}
switch (mcs) {
case 32:
return 32;
case 87:
case 99:
case 101:
return 87; /* MCS 87: SS 1, MOD: 256QAM, CR 3/4 */
default:
return 88; /* MCS 88: SS 1, MOD: 256QAM, CR 5/6 */
}
}
/* ============================================ */
/* Moved from wlc_phy_iovar.c */
/* ============================================ */
const uint8 plcp_ofdm_rate_tbl[] = {
DOT11_RATE_48M, /* 8: 48Mbps */
DOT11_RATE_24M, /* 9: 24Mbps */
DOT11_RATE_12M, /* A: 12Mbps */
DOT11_RATE_6M, /* B: 6Mbps */
DOT11_RATE_54M, /* C: 54Mbps */
DOT11_RATE_36M, /* D: 36Mbps */
DOT11_RATE_18M, /* E: 18Mbps */
DOT11_RATE_9M /* F: 9Mbps */
};

View File

@@ -1,793 +0,0 @@
/*
* Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmwifi_rates.h 612483 2016-01-14 03:44:27Z $
*/
#ifndef _bcmwifi_rates_h_
#define _bcmwifi_rates_h_
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define WL_RATESET_SZ_DSSS 4
#define WL_RATESET_SZ_OFDM 8
#define WL_RATESET_SZ_VHT_MCS 10
#define WL_RATESET_SZ_VHT_MCS_P 12
#if defined(WLPROPRIETARY_11N_RATES)
#define WL_RATESET_SZ_HT_MCS WL_RATESET_SZ_VHT_MCS
#else
#define WL_RATESET_SZ_HT_MCS 8
#endif
#define WL_RATESET_SZ_HT_IOCTL 8 /* MAC histogram, compatibility with wl utility */
#define WL_TX_CHAINS_MAX 4
#define WL_RATE_DISABLED (-128) /* Power value corresponding to unsupported rate */
/* Transmit channel bandwidths */
typedef enum wl_tx_bw {
WL_TX_BW_20,
WL_TX_BW_40,
WL_TX_BW_80,
WL_TX_BW_20IN40,
WL_TX_BW_20IN80,
WL_TX_BW_40IN80,
WL_TX_BW_160,
WL_TX_BW_20IN160,
WL_TX_BW_40IN160,
WL_TX_BW_80IN160,
WL_TX_BW_ALL,
WL_TX_BW_8080,
WL_TX_BW_8080CHAN2,
WL_TX_BW_20IN8080,
WL_TX_BW_40IN8080,
WL_TX_BW_80IN8080,
WL_TX_BW_2P5,
WL_TX_BW_5,
WL_TX_BW_10
} wl_tx_bw_t;
/*
* Transmit modes.
* Not all modes are listed here, only those required for disambiguation. e.g. SPEXP is not listed
*/
typedef enum wl_tx_mode {
WL_TX_MODE_NONE,
WL_TX_MODE_STBC,
WL_TX_MODE_CDD,
WL_TX_MODE_TXBF,
WL_NUM_TX_MODES
} wl_tx_mode_t;
/* Number of transmit chains */
typedef enum wl_tx_chains {
WL_TX_CHAINS_1 = 1,
WL_TX_CHAINS_2,
WL_TX_CHAINS_3,
WL_TX_CHAINS_4
} wl_tx_chains_t;
/* Number of transmit streams */
typedef enum wl_tx_nss {
WL_TX_NSS_1 = 1,
WL_TX_NSS_2,
WL_TX_NSS_3,
WL_TX_NSS_4
} wl_tx_nss_t;
/* This enum maps each rate to a CLM index */
typedef enum clm_rates {
/************
* 1 chain *
************
*/
/* 1 Stream */
WL_RATE_1X1_DSSS_1 = 0,
WL_RATE_1X1_DSSS_2 = 1,
WL_RATE_1X1_DSSS_5_5 = 2,
WL_RATE_1X1_DSSS_11 = 3,
WL_RATE_1X1_OFDM_6 = 4,
WL_RATE_1X1_OFDM_9 = 5,
WL_RATE_1X1_OFDM_12 = 6,
WL_RATE_1X1_OFDM_18 = 7,
WL_RATE_1X1_OFDM_24 = 8,
WL_RATE_1X1_OFDM_36 = 9,
WL_RATE_1X1_OFDM_48 = 10,
WL_RATE_1X1_OFDM_54 = 11,
WL_RATE_1X1_MCS0 = 12,
WL_RATE_1X1_MCS1 = 13,
WL_RATE_1X1_MCS2 = 14,
WL_RATE_1X1_MCS3 = 15,
WL_RATE_1X1_MCS4 = 16,
WL_RATE_1X1_MCS5 = 17,
WL_RATE_1X1_MCS6 = 18,
WL_RATE_1X1_MCS7 = 19,
WL_RATE_P_1X1_MCS87 = 20,
WL_RATE_P_1X1_MCS88 = 21,
WL_RATE_1X1_VHT0SS1 = 12,
WL_RATE_1X1_VHT1SS1 = 13,
WL_RATE_1X1_VHT2SS1 = 14,
WL_RATE_1X1_VHT3SS1 = 15,
WL_RATE_1X1_VHT4SS1 = 16,
WL_RATE_1X1_VHT5SS1 = 17,
WL_RATE_1X1_VHT6SS1 = 18,
WL_RATE_1X1_VHT7SS1 = 19,
WL_RATE_1X1_VHT8SS1 = 20,
WL_RATE_1X1_VHT9SS1 = 21,
WL_RATE_P_1X1_VHT10SS1 = 22,
WL_RATE_P_1X1_VHT11SS1 = 23,
/************
* 2 chains *
************
*/
/* 1 Stream expanded + 1 */
WL_RATE_1X2_DSSS_1 = 24,
WL_RATE_1X2_DSSS_2 = 25,
WL_RATE_1X2_DSSS_5_5 = 26,
WL_RATE_1X2_DSSS_11 = 27,
WL_RATE_1X2_CDD_OFDM_6 = 28,
WL_RATE_1X2_CDD_OFDM_9 = 29,
WL_RATE_1X2_CDD_OFDM_12 = 30,
WL_RATE_1X2_CDD_OFDM_18 = 31,
WL_RATE_1X2_CDD_OFDM_24 = 32,
WL_RATE_1X2_CDD_OFDM_36 = 33,
WL_RATE_1X2_CDD_OFDM_48 = 34,
WL_RATE_1X2_CDD_OFDM_54 = 35,
WL_RATE_1X2_CDD_MCS0 = 36,
WL_RATE_1X2_CDD_MCS1 = 37,
WL_RATE_1X2_CDD_MCS2 = 38,
WL_RATE_1X2_CDD_MCS3 = 39,
WL_RATE_1X2_CDD_MCS4 = 40,
WL_RATE_1X2_CDD_MCS5 = 41,
WL_RATE_1X2_CDD_MCS6 = 42,
WL_RATE_1X2_CDD_MCS7 = 43,
WL_RATE_P_1X2_CDD_MCS87 = 44,
WL_RATE_P_1X2_CDD_MCS88 = 45,
WL_RATE_1X2_VHT0SS1 = 36,
WL_RATE_1X2_VHT1SS1 = 37,
WL_RATE_1X2_VHT2SS1 = 38,
WL_RATE_1X2_VHT3SS1 = 39,
WL_RATE_1X2_VHT4SS1 = 40,
WL_RATE_1X2_VHT5SS1 = 41,
WL_RATE_1X2_VHT6SS1 = 42,
WL_RATE_1X2_VHT7SS1 = 43,
WL_RATE_1X2_VHT8SS1 = 44,
WL_RATE_1X2_VHT9SS1 = 45,
WL_RATE_P_1X2_VHT10SS1 = 46,
WL_RATE_P_1X2_VHT11SS1 = 47,
/* 2 Streams */
WL_RATE_2X2_STBC_MCS0 = 48,
WL_RATE_2X2_STBC_MCS1 = 49,
WL_RATE_2X2_STBC_MCS2 = 50,
WL_RATE_2X2_STBC_MCS3 = 51,
WL_RATE_2X2_STBC_MCS4 = 52,
WL_RATE_2X2_STBC_MCS5 = 53,
WL_RATE_2X2_STBC_MCS6 = 54,
WL_RATE_2X2_STBC_MCS7 = 55,
WL_RATE_P_2X2_STBC_MCS87 = 56,
WL_RATE_P_2X2_STBC_MCS88 = 57,
WL_RATE_2X2_STBC_VHT0SS1 = 48,
WL_RATE_2X2_STBC_VHT1SS1 = 49,
WL_RATE_2X2_STBC_VHT2SS1 = 50,
WL_RATE_2X2_STBC_VHT3SS1 = 51,
WL_RATE_2X2_STBC_VHT4SS1 = 52,
WL_RATE_2X2_STBC_VHT5SS1 = 53,
WL_RATE_2X2_STBC_VHT6SS1 = 54,
WL_RATE_2X2_STBC_VHT7SS1 = 55,
WL_RATE_2X2_STBC_VHT8SS1 = 56,
WL_RATE_2X2_STBC_VHT9SS1 = 57,
WL_RATE_P_2X2_STBC_VHT10SS1 = 58,
WL_RATE_P_2X2_STBC_VHT11SS1 = 59,
WL_RATE_2X2_SDM_MCS8 = 60,
WL_RATE_2X2_SDM_MCS9 = 61,
WL_RATE_2X2_SDM_MCS10 = 62,
WL_RATE_2X2_SDM_MCS11 = 63,
WL_RATE_2X2_SDM_MCS12 = 64,
WL_RATE_2X2_SDM_MCS13 = 65,
WL_RATE_2X2_SDM_MCS14 = 66,
WL_RATE_2X2_SDM_MCS15 = 67,
WL_RATE_P_2X2_SDM_MCS99 = 68,
WL_RATE_P_2X2_SDM_MCS100 = 69,
WL_RATE_2X2_VHT0SS2 = 60,
WL_RATE_2X2_VHT1SS2 = 61,
WL_RATE_2X2_VHT2SS2 = 62,
WL_RATE_2X2_VHT3SS2 = 63,
WL_RATE_2X2_VHT4SS2 = 64,
WL_RATE_2X2_VHT5SS2 = 65,
WL_RATE_2X2_VHT6SS2 = 66,
WL_RATE_2X2_VHT7SS2 = 67,
WL_RATE_2X2_VHT8SS2 = 68,
WL_RATE_2X2_VHT9SS2 = 69,
WL_RATE_P_2X2_VHT10SS2 = 70,
WL_RATE_P_2X2_VHT11SS2 = 71,
/****************************
* TX Beamforming, 2 chains *
****************************
*/
/* 1 Stream expanded + 1 */
WL_RATE_1X2_TXBF_OFDM_6 = 72,
WL_RATE_1X2_TXBF_OFDM_9 = 73,
WL_RATE_1X2_TXBF_OFDM_12 = 74,
WL_RATE_1X2_TXBF_OFDM_18 = 75,
WL_RATE_1X2_TXBF_OFDM_24 = 76,
WL_RATE_1X2_TXBF_OFDM_36 = 77,
WL_RATE_1X2_TXBF_OFDM_48 = 78,
WL_RATE_1X2_TXBF_OFDM_54 = 79,
WL_RATE_1X2_TXBF_MCS0 = 80,
WL_RATE_1X2_TXBF_MCS1 = 81,
WL_RATE_1X2_TXBF_MCS2 = 82,
WL_RATE_1X2_TXBF_MCS3 = 83,
WL_RATE_1X2_TXBF_MCS4 = 84,
WL_RATE_1X2_TXBF_MCS5 = 85,
WL_RATE_1X2_TXBF_MCS6 = 86,
WL_RATE_1X2_TXBF_MCS7 = 87,
WL_RATE_P_1X2_TXBF_MCS87 = 88,
WL_RATE_P_1X2_TXBF_MCS88 = 89,
WL_RATE_1X2_TXBF_VHT0SS1 = 80,
WL_RATE_1X2_TXBF_VHT1SS1 = 81,
WL_RATE_1X2_TXBF_VHT2SS1 = 82,
WL_RATE_1X2_TXBF_VHT3SS1 = 83,
WL_RATE_1X2_TXBF_VHT4SS1 = 84,
WL_RATE_1X2_TXBF_VHT5SS1 = 85,
WL_RATE_1X2_TXBF_VHT6SS1 = 86,
WL_RATE_1X2_TXBF_VHT7SS1 = 87,
WL_RATE_1X2_TXBF_VHT8SS1 = 88,
WL_RATE_1X2_TXBF_VHT9SS1 = 89,
WL_RATE_P_1X2_TXBF_VHT10SS1 = 90,
WL_RATE_P_1X2_TXBF_VHT11SS1 = 91,
/* 2 Streams */
WL_RATE_2X2_TXBF_SDM_MCS8 = 92,
WL_RATE_2X2_TXBF_SDM_MCS9 = 93,
WL_RATE_2X2_TXBF_SDM_MCS10 = 94,
WL_RATE_2X2_TXBF_SDM_MCS11 = 95,
WL_RATE_2X2_TXBF_SDM_MCS12 = 96,
WL_RATE_2X2_TXBF_SDM_MCS13 = 97,
WL_RATE_2X2_TXBF_SDM_MCS14 = 98,
WL_RATE_2X2_TXBF_SDM_MCS15 = 99,
WL_RATE_P_2X2_TXBF_SDM_MCS99 = 100,
WL_RATE_P_2X2_TXBF_SDM_MCS100 = 101,
WL_RATE_2X2_TXBF_VHT0SS2 = 92,
WL_RATE_2X2_TXBF_VHT1SS2 = 93,
WL_RATE_2X2_TXBF_VHT2SS2 = 94,
WL_RATE_2X2_TXBF_VHT3SS2 = 95,
WL_RATE_2X2_TXBF_VHT4SS2 = 96,
WL_RATE_2X2_TXBF_VHT5SS2 = 97,
WL_RATE_2X2_TXBF_VHT6SS2 = 98,
WL_RATE_2X2_TXBF_VHT7SS2 = 99,
WL_RATE_2X2_TXBF_VHT8SS2 = 100,
WL_RATE_2X2_TXBF_VHT9SS2 = 101,
WL_RATE_P_2X2_TXBF_VHT10SS2 = 102,
WL_RATE_P_2X2_TXBF_VHT11SS2 = 103,
/************
* 3 chains *
************
*/
/* 1 Stream expanded + 2 */
WL_RATE_1X3_DSSS_1 = 104,
WL_RATE_1X3_DSSS_2 = 105,
WL_RATE_1X3_DSSS_5_5 = 106,
WL_RATE_1X3_DSSS_11 = 107,
WL_RATE_1X3_CDD_OFDM_6 = 108,
WL_RATE_1X3_CDD_OFDM_9 = 109,
WL_RATE_1X3_CDD_OFDM_12 = 110,
WL_RATE_1X3_CDD_OFDM_18 = 111,
WL_RATE_1X3_CDD_OFDM_24 = 112,
WL_RATE_1X3_CDD_OFDM_36 = 113,
WL_RATE_1X3_CDD_OFDM_48 = 114,
WL_RATE_1X3_CDD_OFDM_54 = 115,
WL_RATE_1X3_CDD_MCS0 = 116,
WL_RATE_1X3_CDD_MCS1 = 117,
WL_RATE_1X3_CDD_MCS2 = 118,
WL_RATE_1X3_CDD_MCS3 = 119,
WL_RATE_1X3_CDD_MCS4 = 120,
WL_RATE_1X3_CDD_MCS5 = 121,
WL_RATE_1X3_CDD_MCS6 = 122,
WL_RATE_1X3_CDD_MCS7 = 123,
WL_RATE_P_1X3_CDD_MCS87 = 124,
WL_RATE_P_1X3_CDD_MCS88 = 125,
WL_RATE_1X3_VHT0SS1 = 116,
WL_RATE_1X3_VHT1SS1 = 117,
WL_RATE_1X3_VHT2SS1 = 118,
WL_RATE_1X3_VHT3SS1 = 119,
WL_RATE_1X3_VHT4SS1 = 120,
WL_RATE_1X3_VHT5SS1 = 121,
WL_RATE_1X3_VHT6SS1 = 122,
WL_RATE_1X3_VHT7SS1 = 123,
WL_RATE_1X3_VHT8SS1 = 124,
WL_RATE_1X3_VHT9SS1 = 125,
WL_RATE_P_1X3_VHT10SS1 = 126,
WL_RATE_P_1X3_VHT11SS1 = 127,
/* 2 Streams expanded + 1 */
WL_RATE_2X3_STBC_MCS0 = 128,
WL_RATE_2X3_STBC_MCS1 = 129,
WL_RATE_2X3_STBC_MCS2 = 130,
WL_RATE_2X3_STBC_MCS3 = 131,
WL_RATE_2X3_STBC_MCS4 = 132,
WL_RATE_2X3_STBC_MCS5 = 133,
WL_RATE_2X3_STBC_MCS6 = 134,
WL_RATE_2X3_STBC_MCS7 = 135,
WL_RATE_P_2X3_STBC_MCS87 = 136,
WL_RATE_P_2X3_STBC_MCS88 = 137,
WL_RATE_2X3_STBC_VHT0SS1 = 128,
WL_RATE_2X3_STBC_VHT1SS1 = 129,
WL_RATE_2X3_STBC_VHT2SS1 = 130,
WL_RATE_2X3_STBC_VHT3SS1 = 131,
WL_RATE_2X3_STBC_VHT4SS1 = 132,
WL_RATE_2X3_STBC_VHT5SS1 = 133,
WL_RATE_2X3_STBC_VHT6SS1 = 134,
WL_RATE_2X3_STBC_VHT7SS1 = 135,
WL_RATE_2X3_STBC_VHT8SS1 = 136,
WL_RATE_2X3_STBC_VHT9SS1 = 137,
WL_RATE_P_2X3_STBC_VHT10SS1 = 138,
WL_RATE_P_2X3_STBC_VHT11SS1 = 139,
WL_RATE_2X3_SDM_MCS8 = 140,
WL_RATE_2X3_SDM_MCS9 = 141,
WL_RATE_2X3_SDM_MCS10 = 142,
WL_RATE_2X3_SDM_MCS11 = 143,
WL_RATE_2X3_SDM_MCS12 = 144,
WL_RATE_2X3_SDM_MCS13 = 145,
WL_RATE_2X3_SDM_MCS14 = 146,
WL_RATE_2X3_SDM_MCS15 = 147,
WL_RATE_P_2X3_SDM_MCS99 = 148,
WL_RATE_P_2X3_SDM_MCS100 = 149,
WL_RATE_2X3_VHT0SS2 = 140,
WL_RATE_2X3_VHT1SS2 = 141,
WL_RATE_2X3_VHT2SS2 = 142,
WL_RATE_2X3_VHT3SS2 = 143,
WL_RATE_2X3_VHT4SS2 = 144,
WL_RATE_2X3_VHT5SS2 = 145,
WL_RATE_2X3_VHT6SS2 = 146,
WL_RATE_2X3_VHT7SS2 = 147,
WL_RATE_2X3_VHT8SS2 = 148,
WL_RATE_2X3_VHT9SS2 = 149,
WL_RATE_P_2X3_VHT10SS2 = 150,
WL_RATE_P_2X3_VHT11SS2 = 151,
/* 3 Streams */
WL_RATE_3X3_SDM_MCS16 = 152,
WL_RATE_3X3_SDM_MCS17 = 153,
WL_RATE_3X3_SDM_MCS18 = 154,
WL_RATE_3X3_SDM_MCS19 = 155,
WL_RATE_3X3_SDM_MCS20 = 156,
WL_RATE_3X3_SDM_MCS21 = 157,
WL_RATE_3X3_SDM_MCS22 = 158,
WL_RATE_3X3_SDM_MCS23 = 159,
WL_RATE_P_3X3_SDM_MCS101 = 160,
WL_RATE_P_3X3_SDM_MCS102 = 161,
WL_RATE_3X3_VHT0SS3 = 152,
WL_RATE_3X3_VHT1SS3 = 153,
WL_RATE_3X3_VHT2SS3 = 154,
WL_RATE_3X3_VHT3SS3 = 155,
WL_RATE_3X3_VHT4SS3 = 156,
WL_RATE_3X3_VHT5SS3 = 157,
WL_RATE_3X3_VHT6SS3 = 158,
WL_RATE_3X3_VHT7SS3 = 159,
WL_RATE_3X3_VHT8SS3 = 160,
WL_RATE_3X3_VHT9SS3 = 161,
WL_RATE_P_3X3_VHT10SS3 = 162,
WL_RATE_P_3X3_VHT11SS3 = 163,
/****************************
* TX Beamforming, 3 chains *
****************************
*/
/* 1 Stream expanded + 2 */
WL_RATE_1X3_TXBF_OFDM_6 = 164,
WL_RATE_1X3_TXBF_OFDM_9 = 165,
WL_RATE_1X3_TXBF_OFDM_12 = 166,
WL_RATE_1X3_TXBF_OFDM_18 = 167,
WL_RATE_1X3_TXBF_OFDM_24 = 168,
WL_RATE_1X3_TXBF_OFDM_36 = 169,
WL_RATE_1X3_TXBF_OFDM_48 = 170,
WL_RATE_1X3_TXBF_OFDM_54 = 171,
WL_RATE_1X3_TXBF_MCS0 = 172,
WL_RATE_1X3_TXBF_MCS1 = 173,
WL_RATE_1X3_TXBF_MCS2 = 174,
WL_RATE_1X3_TXBF_MCS3 = 175,
WL_RATE_1X3_TXBF_MCS4 = 176,
WL_RATE_1X3_TXBF_MCS5 = 177,
WL_RATE_1X3_TXBF_MCS6 = 178,
WL_RATE_1X3_TXBF_MCS7 = 179,
WL_RATE_P_1X3_TXBF_MCS87 = 180,
WL_RATE_P_1X3_TXBF_MCS88 = 181,
WL_RATE_1X3_TXBF_VHT0SS1 = 172,
WL_RATE_1X3_TXBF_VHT1SS1 = 173,
WL_RATE_1X3_TXBF_VHT2SS1 = 174,
WL_RATE_1X3_TXBF_VHT3SS1 = 175,
WL_RATE_1X3_TXBF_VHT4SS1 = 176,
WL_RATE_1X3_TXBF_VHT5SS1 = 177,
WL_RATE_1X3_TXBF_VHT6SS1 = 178,
WL_RATE_1X3_TXBF_VHT7SS1 = 179,
WL_RATE_1X3_TXBF_VHT8SS1 = 180,
WL_RATE_1X3_TXBF_VHT9SS1 = 181,
WL_RATE_P_1X3_TXBF_VHT10SS1 = 182,
WL_RATE_P_1X3_TXBF_VHT11SS1 = 183,
/* 2 Streams expanded + 1 */
WL_RATE_2X3_TXBF_SDM_MCS8 = 184,
WL_RATE_2X3_TXBF_SDM_MCS9 = 185,
WL_RATE_2X3_TXBF_SDM_MCS10 = 186,
WL_RATE_2X3_TXBF_SDM_MCS11 = 187,
WL_RATE_2X3_TXBF_SDM_MCS12 = 188,
WL_RATE_2X3_TXBF_SDM_MCS13 = 189,
WL_RATE_2X3_TXBF_SDM_MCS14 = 190,
WL_RATE_2X3_TXBF_SDM_MCS15 = 191,
WL_RATE_P_2X3_TXBF_SDM_MCS99 = 192,
WL_RATE_P_2X3_TXBF_SDM_MCS100 = 193,
WL_RATE_2X3_TXBF_VHT0SS2 = 184,
WL_RATE_2X3_TXBF_VHT1SS2 = 185,
WL_RATE_2X3_TXBF_VHT2SS2 = 186,
WL_RATE_2X3_TXBF_VHT3SS2 = 187,
WL_RATE_2X3_TXBF_VHT4SS2 = 188,
WL_RATE_2X3_TXBF_VHT5SS2 = 189,
WL_RATE_2X3_TXBF_VHT6SS2 = 190,
WL_RATE_2X3_TXBF_VHT7SS2 = 191,
WL_RATE_2X3_TXBF_VHT8SS2 = 192,
WL_RATE_2X3_TXBF_VHT9SS2 = 193,
WL_RATE_P_2X3_TXBF_VHT10SS2 = 194,
WL_RATE_P_2X3_TXBF_VHT11SS2 = 195,
/* 3 Streams */
WL_RATE_3X3_TXBF_SDM_MCS16 = 196,
WL_RATE_3X3_TXBF_SDM_MCS17 = 197,
WL_RATE_3X3_TXBF_SDM_MCS18 = 198,
WL_RATE_3X3_TXBF_SDM_MCS19 = 199,
WL_RATE_3X3_TXBF_SDM_MCS20 = 200,
WL_RATE_3X3_TXBF_SDM_MCS21 = 201,
WL_RATE_3X3_TXBF_SDM_MCS22 = 202,
WL_RATE_3X3_TXBF_SDM_MCS23 = 203,
WL_RATE_P_3X3_TXBF_SDM_MCS101 = 204,
WL_RATE_P_3X3_TXBF_SDM_MCS102 = 205,
WL_RATE_3X3_TXBF_VHT0SS3 = 196,
WL_RATE_3X3_TXBF_VHT1SS3 = 197,
WL_RATE_3X3_TXBF_VHT2SS3 = 198,
WL_RATE_3X3_TXBF_VHT3SS3 = 199,
WL_RATE_3X3_TXBF_VHT4SS3 = 200,
WL_RATE_3X3_TXBF_VHT5SS3 = 201,
WL_RATE_3X3_TXBF_VHT6SS3 = 202,
WL_RATE_3X3_TXBF_VHT7SS3 = 203,
WL_RATE_3X3_TXBF_VHT8SS3 = 204,
WL_RATE_3X3_TXBF_VHT9SS3 = 205,
WL_RATE_P_3X3_TXBF_VHT10SS3 = 206,
WL_RATE_P_3X3_TXBF_VHT11SS3 = 207,
/************
* 4 chains *
************
*/
/* 1 Stream expanded + 3 */
WL_RATE_1X4_DSSS_1 = 208,
WL_RATE_1X4_DSSS_2 = 209,
WL_RATE_1X4_DSSS_5_5 = 210,
WL_RATE_1X4_DSSS_11 = 211,
WL_RATE_1X4_CDD_OFDM_6 = 212,
WL_RATE_1X4_CDD_OFDM_9 = 213,
WL_RATE_1X4_CDD_OFDM_12 = 214,
WL_RATE_1X4_CDD_OFDM_18 = 215,
WL_RATE_1X4_CDD_OFDM_24 = 216,
WL_RATE_1X4_CDD_OFDM_36 = 217,
WL_RATE_1X4_CDD_OFDM_48 = 218,
WL_RATE_1X4_CDD_OFDM_54 = 219,
WL_RATE_1X4_CDD_MCS0 = 220,
WL_RATE_1X4_CDD_MCS1 = 221,
WL_RATE_1X4_CDD_MCS2 = 222,
WL_RATE_1X4_CDD_MCS3 = 223,
WL_RATE_1X4_CDD_MCS4 = 224,
WL_RATE_1X4_CDD_MCS5 = 225,
WL_RATE_1X4_CDD_MCS6 = 226,
WL_RATE_1X4_CDD_MCS7 = 227,
WL_RATE_P_1X4_CDD_MCS87 = 228,
WL_RATE_P_1X4_CDD_MCS88 = 229,
WL_RATE_1X4_VHT0SS1 = 220,
WL_RATE_1X4_VHT1SS1 = 221,
WL_RATE_1X4_VHT2SS1 = 222,
WL_RATE_1X4_VHT3SS1 = 223,
WL_RATE_1X4_VHT4SS1 = 224,
WL_RATE_1X4_VHT5SS1 = 225,
WL_RATE_1X4_VHT6SS1 = 226,
WL_RATE_1X4_VHT7SS1 = 227,
WL_RATE_1X4_VHT8SS1 = 228,
WL_RATE_1X4_VHT9SS1 = 229,
WL_RATE_P_1X4_VHT10SS1 = 230,
WL_RATE_P_1X4_VHT11SS1 = 231,
/* 2 Streams expanded + 2 */
WL_RATE_2X4_STBC_MCS0 = 232,
WL_RATE_2X4_STBC_MCS1 = 233,
WL_RATE_2X4_STBC_MCS2 = 234,
WL_RATE_2X4_STBC_MCS3 = 235,
WL_RATE_2X4_STBC_MCS4 = 236,
WL_RATE_2X4_STBC_MCS5 = 237,
WL_RATE_2X4_STBC_MCS6 = 238,
WL_RATE_2X4_STBC_MCS7 = 239,
WL_RATE_P_2X4_STBC_MCS87 = 240,
WL_RATE_P_2X4_STBC_MCS88 = 241,
WL_RATE_2X4_STBC_VHT0SS1 = 232,
WL_RATE_2X4_STBC_VHT1SS1 = 233,
WL_RATE_2X4_STBC_VHT2SS1 = 234,
WL_RATE_2X4_STBC_VHT3SS1 = 235,
WL_RATE_2X4_STBC_VHT4SS1 = 236,
WL_RATE_2X4_STBC_VHT5SS1 = 237,
WL_RATE_2X4_STBC_VHT6SS1 = 238,
WL_RATE_2X4_STBC_VHT7SS1 = 239,
WL_RATE_2X4_STBC_VHT8SS1 = 240,
WL_RATE_2X4_STBC_VHT9SS1 = 241,
WL_RATE_P_2X4_STBC_VHT10SS1 = 242,
WL_RATE_P_2X4_STBC_VHT11SS1 = 243,
WL_RATE_2X4_SDM_MCS8 = 244,
WL_RATE_2X4_SDM_MCS9 = 245,
WL_RATE_2X4_SDM_MCS10 = 246,
WL_RATE_2X4_SDM_MCS11 = 247,
WL_RATE_2X4_SDM_MCS12 = 248,
WL_RATE_2X4_SDM_MCS13 = 249,
WL_RATE_2X4_SDM_MCS14 = 250,
WL_RATE_2X4_SDM_MCS15 = 251,
WL_RATE_P_2X4_SDM_MCS99 = 252,
WL_RATE_P_2X4_SDM_MCS100 = 253,
WL_RATE_2X4_VHT0SS2 = 244,
WL_RATE_2X4_VHT1SS2 = 245,
WL_RATE_2X4_VHT2SS2 = 246,
WL_RATE_2X4_VHT3SS2 = 247,
WL_RATE_2X4_VHT4SS2 = 248,
WL_RATE_2X4_VHT5SS2 = 249,
WL_RATE_2X4_VHT6SS2 = 250,
WL_RATE_2X4_VHT7SS2 = 251,
WL_RATE_2X4_VHT8SS2 = 252,
WL_RATE_2X4_VHT9SS2 = 253,
WL_RATE_P_2X4_VHT10SS2 = 254,
WL_RATE_P_2X4_VHT11SS2 = 255,
/* 3 Streams expanded + 1 */
WL_RATE_3X4_SDM_MCS16 = 256,
WL_RATE_3X4_SDM_MCS17 = 257,
WL_RATE_3X4_SDM_MCS18 = 258,
WL_RATE_3X4_SDM_MCS19 = 259,
WL_RATE_3X4_SDM_MCS20 = 260,
WL_RATE_3X4_SDM_MCS21 = 261,
WL_RATE_3X4_SDM_MCS22 = 262,
WL_RATE_3X4_SDM_MCS23 = 263,
WL_RATE_P_3X4_SDM_MCS101 = 264,
WL_RATE_P_3X4_SDM_MCS102 = 265,
WL_RATE_3X4_VHT0SS3 = 256,
WL_RATE_3X4_VHT1SS3 = 257,
WL_RATE_3X4_VHT2SS3 = 258,
WL_RATE_3X4_VHT3SS3 = 259,
WL_RATE_3X4_VHT4SS3 = 260,
WL_RATE_3X4_VHT5SS3 = 261,
WL_RATE_3X4_VHT6SS3 = 262,
WL_RATE_3X4_VHT7SS3 = 263,
WL_RATE_3X4_VHT8SS3 = 264,
WL_RATE_3X4_VHT9SS3 = 265,
WL_RATE_P_3X4_VHT10SS3 = 266,
WL_RATE_P_3X4_VHT11SS3 = 267,
/* 4 Streams */
WL_RATE_4X4_SDM_MCS24 = 268,
WL_RATE_4X4_SDM_MCS25 = 269,
WL_RATE_4X4_SDM_MCS26 = 270,
WL_RATE_4X4_SDM_MCS27 = 271,
WL_RATE_4X4_SDM_MCS28 = 272,
WL_RATE_4X4_SDM_MCS29 = 273,
WL_RATE_4X4_SDM_MCS30 = 274,
WL_RATE_4X4_SDM_MCS31 = 275,
WL_RATE_P_4X4_SDM_MCS103 = 276,
WL_RATE_P_4X4_SDM_MCS104 = 277,
WL_RATE_4X4_VHT0SS4 = 268,
WL_RATE_4X4_VHT1SS4 = 269,
WL_RATE_4X4_VHT2SS4 = 270,
WL_RATE_4X4_VHT3SS4 = 271,
WL_RATE_4X4_VHT4SS4 = 272,
WL_RATE_4X4_VHT5SS4 = 273,
WL_RATE_4X4_VHT6SS4 = 274,
WL_RATE_4X4_VHT7SS4 = 275,
WL_RATE_4X4_VHT8SS4 = 276,
WL_RATE_4X4_VHT9SS4 = 277,
WL_RATE_P_4X4_VHT10SS4 = 278,
WL_RATE_P_4X4_VHT11SS4 = 279,
/****************************
* TX Beamforming, 4 chains *
****************************
*/
/* 1 Stream expanded + 3 */
WL_RATE_1X4_TXBF_OFDM_6 = 280,
WL_RATE_1X4_TXBF_OFDM_9 = 281,
WL_RATE_1X4_TXBF_OFDM_12 = 282,
WL_RATE_1X4_TXBF_OFDM_18 = 283,
WL_RATE_1X4_TXBF_OFDM_24 = 284,
WL_RATE_1X4_TXBF_OFDM_36 = 285,
WL_RATE_1X4_TXBF_OFDM_48 = 286,
WL_RATE_1X4_TXBF_OFDM_54 = 287,
WL_RATE_1X4_TXBF_MCS0 = 288,
WL_RATE_1X4_TXBF_MCS1 = 289,
WL_RATE_1X4_TXBF_MCS2 = 290,
WL_RATE_1X4_TXBF_MCS3 = 291,
WL_RATE_1X4_TXBF_MCS4 = 292,
WL_RATE_1X4_TXBF_MCS5 = 293,
WL_RATE_1X4_TXBF_MCS6 = 294,
WL_RATE_1X4_TXBF_MCS7 = 295,
WL_RATE_P_1X4_TXBF_MCS87 = 296,
WL_RATE_P_1X4_TXBF_MCS88 = 297,
WL_RATE_1X4_TXBF_VHT0SS1 = 288,
WL_RATE_1X4_TXBF_VHT1SS1 = 289,
WL_RATE_1X4_TXBF_VHT2SS1 = 290,
WL_RATE_1X4_TXBF_VHT3SS1 = 291,
WL_RATE_1X4_TXBF_VHT4SS1 = 292,
WL_RATE_1X4_TXBF_VHT5SS1 = 293,
WL_RATE_1X4_TXBF_VHT6SS1 = 294,
WL_RATE_1X4_TXBF_VHT7SS1 = 295,
WL_RATE_1X4_TXBF_VHT8SS1 = 296,
WL_RATE_1X4_TXBF_VHT9SS1 = 297,
WL_RATE_P_1X4_TXBF_VHT10SS1 = 298,
WL_RATE_P_1X4_TXBF_VHT11SS1 = 299,
/* 2 Streams expanded + 2 */
WL_RATE_2X4_TXBF_SDM_MCS8 = 300,
WL_RATE_2X4_TXBF_SDM_MCS9 = 301,
WL_RATE_2X4_TXBF_SDM_MCS10 = 302,
WL_RATE_2X4_TXBF_SDM_MCS11 = 303,
WL_RATE_2X4_TXBF_SDM_MCS12 = 304,
WL_RATE_2X4_TXBF_SDM_MCS13 = 305,
WL_RATE_2X4_TXBF_SDM_MCS14 = 306,
WL_RATE_2X4_TXBF_SDM_MCS15 = 307,
WL_RATE_P_2X4_TXBF_SDM_MCS99 = 308,
WL_RATE_P_2X4_TXBF_SDM_MCS100 = 309,
WL_RATE_2X4_TXBF_VHT0SS2 = 300,
WL_RATE_2X4_TXBF_VHT1SS2 = 301,
WL_RATE_2X4_TXBF_VHT2SS2 = 302,
WL_RATE_2X4_TXBF_VHT3SS2 = 303,
WL_RATE_2X4_TXBF_VHT4SS2 = 304,
WL_RATE_2X4_TXBF_VHT5SS2 = 305,
WL_RATE_2X4_TXBF_VHT6SS2 = 306,
WL_RATE_2X4_TXBF_VHT7SS2 = 307,
WL_RATE_2X4_TXBF_VHT8SS2 = 308,
WL_RATE_2X4_TXBF_VHT9SS2 = 309,
WL_RATE_P_2X4_TXBF_VHT10SS2 = 310,
WL_RATE_P_2X4_TXBF_VHT11SS2 = 311,
/* 3 Streams expanded + 1 */
WL_RATE_3X4_TXBF_SDM_MCS16 = 312,
WL_RATE_3X4_TXBF_SDM_MCS17 = 313,
WL_RATE_3X4_TXBF_SDM_MCS18 = 314,
WL_RATE_3X4_TXBF_SDM_MCS19 = 315,
WL_RATE_3X4_TXBF_SDM_MCS20 = 316,
WL_RATE_3X4_TXBF_SDM_MCS21 = 317,
WL_RATE_3X4_TXBF_SDM_MCS22 = 318,
WL_RATE_3X4_TXBF_SDM_MCS23 = 319,
WL_RATE_P_3X4_TXBF_SDM_MCS101 = 320,
WL_RATE_P_3X4_TXBF_SDM_MCS102 = 321,
WL_RATE_3X4_TXBF_VHT0SS3 = 312,
WL_RATE_3X4_TXBF_VHT1SS3 = 313,
WL_RATE_3X4_TXBF_VHT2SS3 = 314,
WL_RATE_3X4_TXBF_VHT3SS3 = 315,
WL_RATE_3X4_TXBF_VHT4SS3 = 316,
WL_RATE_3X4_TXBF_VHT5SS3 = 317,
WL_RATE_3X4_TXBF_VHT6SS3 = 318,
WL_RATE_3X4_TXBF_VHT7SS3 = 319,
WL_RATE_P_3X4_TXBF_VHT8SS3 = 320,
WL_RATE_P_3X4_TXBF_VHT9SS3 = 321,
WL_RATE_P_3X4_TXBF_VHT10SS3 = 322,
WL_RATE_P_3X4_TXBF_VHT11SS3 = 323,
/* 4 Streams */
WL_RATE_4X4_TXBF_SDM_MCS24 = 324,
WL_RATE_4X4_TXBF_SDM_MCS25 = 325,
WL_RATE_4X4_TXBF_SDM_MCS26 = 326,
WL_RATE_4X4_TXBF_SDM_MCS27 = 327,
WL_RATE_4X4_TXBF_SDM_MCS28 = 328,
WL_RATE_4X4_TXBF_SDM_MCS29 = 329,
WL_RATE_4X4_TXBF_SDM_MCS30 = 330,
WL_RATE_4X4_TXBF_SDM_MCS31 = 331,
WL_RATE_P_4X4_TXBF_SDM_MCS103 = 332,
WL_RATE_P_4X4_TXBF_SDM_MCS104 = 333,
WL_RATE_4X4_TXBF_VHT0SS4 = 324,
WL_RATE_4X4_TXBF_VHT1SS4 = 325,
WL_RATE_4X4_TXBF_VHT2SS4 = 326,
WL_RATE_4X4_TXBF_VHT3SS4 = 327,
WL_RATE_4X4_TXBF_VHT4SS4 = 328,
WL_RATE_4X4_TXBF_VHT5SS4 = 329,
WL_RATE_4X4_TXBF_VHT6SS4 = 330,
WL_RATE_4X4_TXBF_VHT7SS4 = 331,
WL_RATE_P_4X4_TXBF_VHT8SS4 = 332,
WL_RATE_P_4X4_TXBF_VHT9SS4 = 333,
WL_RATE_P_4X4_TXBF_VHT10SS4 = 334,
WL_RATE_P_4X4_TXBF_VHT11SS4 = 335
} clm_rates_t;
/* Number of rate codes */
#define WL_NUMRATES 336
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _bcmwifi_rates_h_ */

View File

@@ -0,0 +1,274 @@
/*
* Common [OS-independent] rate management
* 802.11 Networking Adapter Device Driver.
*
* Broadcom Proprietary and Confidential. Copyright (C) 2020,
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
* the contents of this file may not be disclosed to third parties,
* copied or duplicated in any form, in whole or in part, without
* the prior written permission of Broadcom.
*
*
* <<Broadcom-WL-IPTag/Proprietary:>>
*/
#include <typedefs.h>
#include <osl.h>
#include <d11.h>
#include <802.11ax.h>
#include <bcmwifi_rspec.h>
#include <bcmwifi_rates.h>
/* TODO: Consolidate rspec utility functions from wlc_rate.c and bcmwifi_monitor.c
* into here if they're shared by non wl layer as well...
*/
/* ============================================ */
/* Moved from wlc_rate.c */
/* ============================================ */
/**
* Returns the rate in [Kbps] units.
*/
static uint
wf_he_rspec_to_rate(ratespec_t rspec, uint max_mcs, uint max_nss)
{
uint mcs = (rspec & WL_RSPEC_HE_MCS_MASK);
uint nss = (rspec & WL_RSPEC_HE_NSS_MASK) >> WL_RSPEC_HE_NSS_SHIFT;
bool dcm = (rspec & WL_RSPEC_DCM) != 0;
uint bw = RSPEC_BW(rspec);
uint gi = RSPEC_HE_LTF_GI(rspec);
ASSERT(mcs <= max_mcs);
ASSERT(nss <= max_nss);
if (mcs > max_mcs) {
return 0;
}
BCM_REFERENCE(max_nss);
return wf_he_mcs_to_rate(mcs, nss, bw, gi, dcm);
} /* wf_he_rspec_to_rate */
/* take a well formed ratespec_t arg and return phy rate in [Kbps] units.
* 'rsel' indicates if the call comes from rate selection.
*/
static uint
_wf_rspec_to_rate(ratespec_t rspec, bool rsel)
{
uint rate = (uint)(-1);
if (RSPEC_ISLEGACY(rspec)) {
rate = 500 * RSPEC2RATE(rspec);
} else if (RSPEC_ISHT(rspec)) {
uint mcs = (rspec & WL_RSPEC_HT_MCS_MASK);
ASSERT_FP(mcs <= 32 || IS_PROPRIETARY_11N_MCS(mcs));
if (mcs == 32) {
rate = wf_mcs_to_rate(mcs, 1, WL_RSPEC_BW_40MHZ, RSPEC_ISSGI(rspec));
} else {
#if defined(WLPROPRIETARY_11N_RATES)
uint nss = GET_11N_MCS_NSS(mcs);
mcs = wf_get_single_stream_mcs(mcs);
#else /* this ifdef prevents ROM abandons */
uint nss = 1 + (mcs / 8);
mcs = mcs % 8;
#endif /* WLPROPRIETARY_11N_RATES */
rate = wf_mcs_to_rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec));
}
} else if (RSPEC_ISVHT(rspec)) {
uint mcs = (rspec & WL_RSPEC_VHT_MCS_MASK);
uint nss = (rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT;
if (rsel) {
rate = wf_mcs_to_rate(mcs, nss, RSPEC_BW(rspec), 0);
} else {
ASSERT_FP(mcs <= WLC_MAX_VHT_MCS);
ASSERT_FP(nss <= 8);
rate = wf_mcs_to_rate(mcs, nss, RSPEC_BW(rspec), RSPEC_ISSGI(rspec));
}
} else if (RSPEC_ISHE(rspec)) {
rate = wf_he_rspec_to_rate(rspec, WLC_MAX_HE_MCS, 8);
} else if (RSPEC_ISEHT(rspec)) {
rate = wf_he_rspec_to_rate(rspec, WLC_MAX_EHT_MCS, 16);
} else {
ASSERT(0);
}
return (rate == 0) ? (uint)(-1) : rate;
}
/* take a well formed ratespec_t 'rspec' and return phy rate in [Kbps] units */
uint
wf_rspec_to_rate(ratespec_t rspec)
{
return _wf_rspec_to_rate(rspec, FALSE);
}
/* take a well formed ratespec_t 'rspec' and return phy rate in [Kbps] units,
* FOR RATE SELECTION ONLY, WHICH USES LEGACY, HT, AND VHT RATES, AND VHT MCS
* COULD BE BIGGER THAN WLC_MAX_VHT_MCS!
*/
uint
wf_rspec_to_rate_rsel(ratespec_t rspec)
{
return _wf_rspec_to_rate(rspec, TRUE);
}
#ifdef BCMDBG
/* Return the rate in 500Kbps units if the rspec is legacy rate, assert otherwise */
uint
wf_rspec_to_rate_legacy(ratespec_t rspec)
{
ASSERT(RSPEC_ISLEGACY(rspec));
return rspec & WL_RSPEC_LEGACY_RATE_MASK;
}
#endif
/**
* Function for computing RSPEC from EHT PLCP
*
* TODO: add link to the HW spec.
*/
ratespec_t
wf_eht_plcp_to_rspec(uint8 *plcp)
{
ASSERT(!"wf_eht_plcp_to_rspec: not implemented!");
return 0;
}
/**
* Function for computing RSPEC from HE PLCP
*
* based on rev3.10 :
* https://docs.google.com/spreadsheets/d/
* 1eP6ZCRrtnF924ds1R-XmbcH0IdQ0WNJpS1-FHmWeb9g/edit#gid=1492656555
*/
ratespec_t
wf_he_plcp_to_rspec(uint8 *plcp)
{
uint8 rate;
uint8 nss;
uint8 bw;
uint8 gi;
ratespec_t rspec;
/* HE plcp - 6 B */
uint32 plcp0;
uint16 plcp1;
ASSERT(plcp);
plcp0 = ((plcp[3] << 24) | (plcp[2] << 16) | (plcp[1] << 8) | plcp[0]);
plcp1 = ((plcp[5] << 8) | plcp[4]);
/* TBD: only SU supported now */
rate = (plcp0 & HE_SU_RE_SIGA_MCS_MASK) >> HE_SU_RE_SIGA_MCS_SHIFT;
/* PLCP contains (NSTS - 1) while RSPEC stores NSTS */
nss = ((plcp0 & HE_SU_RE_SIGA_NSTS_MASK) >> HE_SU_RE_SIGA_NSTS_SHIFT) + 1;
rspec = HE_RSPEC(rate, nss);
/* GI info comes from CP/LTF */
gi = (plcp0 & HE_SU_RE_SIGA_GI_LTF_MASK) >> HE_SU_RE_SIGA_GI_LTF_SHIFT;
rspec |= HE_GI_TO_RSPEC(gi);
/* b19-b20 of plcp indicate bandwidth in the format (2-bit):
* 0 for 20M, 1 for 40M, 2 for 80M, and 3 for 80p80/160M
* SW store this BW in rspec format (3-bit):
* 1 for 20M, 2 for 40M, 3 for 80M, and 4 for 80p80/160M
*/
bw = ((plcp0 & HE_SU_SIGA_BW_MASK) >> HE_SU_SIGA_BW_SHIFT) + 1;
rspec |= (bw << WL_RSPEC_BW_SHIFT);
if (plcp1 & HE_SU_RE_SIGA_BEAMFORM_MASK)
rspec |= WL_RSPEC_TXBF;
if (plcp1 & HE_SU_RE_SIGA_CODING_MASK)
rspec |= WL_RSPEC_LDPC;
if (plcp1 & HE_SU_RE_SIGA_STBC_MASK)
rspec |= WL_RSPEC_STBC;
if (plcp0 & HE_SU_RE_SIGA_DCM_MASK)
rspec |= WL_RSPEC_DCM;
return rspec;
}
ratespec_t
wf_vht_plcp_to_rspec(uint8 *plcp)
{
uint8 rate;
uint vht_sig_a1, vht_sig_a2;
ratespec_t rspec;
ASSERT(plcp);
rate = wf_vht_plcp_to_rate(plcp) & ~WF_NON_HT_MCS;
vht_sig_a1 = plcp[0] | (plcp[1] << 8);
vht_sig_a2 = plcp[3] | (plcp[4] << 8);
rspec = VHT_RSPEC((rate & WL_RSPEC_VHT_MCS_MASK),
(rate >> WL_RSPEC_VHT_NSS_SHIFT));
#if ((((VHT_SIGA1_20MHZ_VAL + 1) << WL_RSPEC_BW_SHIFT) != WL_RSPEC_BW_20MHZ) || \
(((VHT_SIGA1_40MHZ_VAL + 1) << WL_RSPEC_BW_SHIFT) != WL_RSPEC_BW_40MHZ) || \
(((VHT_SIGA1_80MHZ_VAL + 1) << WL_RSPEC_BW_SHIFT) != WL_RSPEC_BW_80MHZ) || \
(((VHT_SIGA1_160MHZ_VAL + 1) << WL_RSPEC_BW_SHIFT) != WL_RSPEC_BW_160MHZ))
#error "VHT SIGA BW mapping to RSPEC BW needs correction"
#endif
rspec |= ((vht_sig_a1 & VHT_SIGA1_160MHZ_VAL) + 1) << WL_RSPEC_BW_SHIFT;
if (vht_sig_a1 & VHT_SIGA1_STBC)
rspec |= WL_RSPEC_STBC;
if (vht_sig_a2 & VHT_SIGA2_GI_SHORT)
rspec |= WL_RSPEC_SGI;
if (vht_sig_a2 & VHT_SIGA2_CODING_LDPC)
rspec |= WL_RSPEC_LDPC;
return rspec;
}
ratespec_t
wf_ht_plcp_to_rspec(uint8 *plcp)
{
return HT_RSPEC(plcp[0] & MIMO_PLCP_MCS_MASK);
}
/* ============================================ */
/* Moved from wlc_rate_def.c */
/* ============================================ */
/**
* Rate info per rate: tells for *pre* 802.11n rates whether a given rate is OFDM or not and its
* phy_rate value. Table index is a rate in [500Kbps] units, from 0 to 54Mbps.
* Contents of a table element:
* d[7] : 1=OFDM rate, 0=DSSS/CCK rate
* d[3:0] if DSSS/CCK rate:
* index into the 'M_RATE_TABLE_B' table maintained by ucode in shm
* d[3:0] if OFDM rate: encode rate per 802.11a-1999 sec 17.3.4.1, with lsb transmitted first.
* index into the 'M_RATE_TABLE_A' table maintained by ucode in shm
*/
/* Note: make this table 128 elements so the result of (rspec & 0x7f) can be safely
* used as the index into this table...
*/
const uint8 rate_info[128] = {
/* 0 1 2 3 4 5 6 7 8 9 */
/* 0 */ 0x00, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 10 */ 0x00, 0x37, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x00,
/* 20 */ 0x00, 0x00, 0x6e, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00,
/* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00,
/* 50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 70 */ 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
/* 100 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c,
/* ------------- guard ------------ */ 0x00,
/* 110 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 120 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,14 @@
/*
* Driver O/S-independent utility routines
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,19 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmxtlv.c 628611 2016-03-31 17:53:25Z $
* <<Broadcom-WL-IPTag/Dual:>>
*/
#include <bcm_cfg.h>
#include <typedefs.h>
#include <bcmdefs.h>
@@ -37,40 +29,133 @@
#ifdef BCMDRIVER
#include <osl.h>
#else /* !BCMDRIVER */
#include <stdlib.h> /* AS!!! */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifndef ASSERT
#define ASSERT(exp)
#endif
INLINE void* MALLOCZ(void *o, size_t s) { BCM_REFERENCE(o); return calloc(1, s); }
INLINE void MFREE(void *o, void *p, size_t s) { BCM_REFERENCE(o); BCM_REFERENCE(s); free(p); }
#endif /* !BCMDRIVER */
#include <bcmtlv.h>
#include <bcmendian.h>
#include <bcmutils.h>
static INLINE int bcm_xtlv_size_for_data(int dlen, bcm_xtlv_opts_t opts)
int
BCMPOSTTRAPFN(bcm_xtlv_hdr_size)(bcm_xtlv_opts_t opts)
{
return ((opts & BCM_XTLV_OPTION_ALIGN32) ? ALIGN_SIZE(dlen + BCM_XTLV_HDR_SIZE, 4)
: (dlen + BCM_XTLV_HDR_SIZE));
int len = (int)OFFSETOF(bcm_xtlv_t, data); /* nominal */
if (opts & BCM_XTLV_OPTION_LENU8) --len;
if (opts & BCM_XTLV_OPTION_IDU8) --len;
return len;
}
bool
bcm_valid_xtlv(const bcm_xtlv_t *elt, int buf_len, bcm_xtlv_opts_t opts)
{
return elt != NULL &&
buf_len >= bcm_xtlv_hdr_size(opts) &&
buf_len >= bcm_xtlv_size(elt, opts);
}
int
BCMPOSTTRAPFN(bcm_xtlv_size_for_data)(int dlen, bcm_xtlv_opts_t opts)
{
int hsz;
hsz = bcm_xtlv_hdr_size(opts);
return ((opts & BCM_XTLV_OPTION_ALIGN32) ? ALIGN_SIZE(dlen + hsz, 4)
: (dlen + hsz));
}
int
bcm_xtlv_size(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts)
{
int size; /* size including header, data, and any pad */
int len; /* length wthout padding */
len = BCM_XTLV_LEN_EX(elt, opts);
size = bcm_xtlv_size_for_data(len, opts);
return size;
}
int
bcm_xtlv_len(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts)
{
const uint8 *lenp;
int len;
lenp = (const uint8 *)elt + OFFSETOF(bcm_xtlv_t, len); /* nominal */
if (opts & BCM_XTLV_OPTION_IDU8) {
--lenp;
}
if (opts & BCM_XTLV_OPTION_LENU8) {
len = *lenp;
} else if (opts & BCM_XTLV_OPTION_LENBE) {
len = (uint32)hton16(elt->len);
} else {
len = ltoh16_ua(lenp);
}
return len;
}
int
bcm_xtlv_id(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts)
{
int id = 0;
if (opts & BCM_XTLV_OPTION_IDU8) {
id = *(const uint8 *)elt;
} else if (opts & BCM_XTLV_OPTION_IDBE) {
id = (uint32)hton16(elt->id);
} else {
id = ltoh16_ua((const uint8 *)elt);
}
return id;
}
bcm_xtlv_t *
bcm_next_xtlv(bcm_xtlv_t *elt, int *buflen, bcm_xtlv_opts_t opts)
bcm_next_xtlv(const bcm_xtlv_t *elt, int *buflen, bcm_xtlv_opts_t opts)
{
int sz;
uint sz;
COV_TAINTED_DATA_SINK(buflen);
COV_NEG_SINK(buflen);
/* validate current elt */
if (!bcm_valid_xtlv(elt, *buflen, opts))
return NULL;
/* advance to next elt */
sz = BCM_XTLV_SIZE(elt, opts);
elt = (bcm_xtlv_t*)((uint8 *)elt + sz);
sz = BCM_XTLV_SIZE_EX(elt, opts);
elt = (const bcm_xtlv_t*)((const uint8 *)elt + sz);
#if defined(__COVERITY__)
/* The 'sz' value is tainted in Coverity because it is read from the tainted data pointed
* to by 'elt'. However, bcm_valid_xtlv() verifies that the elt pointer is a valid element,
* so its size, sz = BCM_XTLV_SIZE_EX(elt, opts), is in the bounds of the buffer.
* Clearing the tainted attribute of 'sz' for Coverity.
*/
__coverity_tainted_data_sanitize__(sz);
if (sz > *buflen) {
return NULL;
}
#endif /* __COVERITY__ */
*buflen -= sz;
/* validate next elt */
if (!bcm_valid_xtlv(elt, *buflen, opts))
return NULL;
return elt;
COV_TAINTED_DATA_ARG(elt);
GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST()
return (bcm_xtlv_t *)(elt);
GCC_DIAGNOSTIC_POP()
}
int
@@ -89,99 +174,190 @@ bcm_xtlv_buf_init(bcm_xtlvbuf_t *tlv_buf, uint8 *buf, uint16 len, bcm_xtlv_opts_
uint16
bcm_xtlv_buf_len(bcm_xtlvbuf_t *tbuf)
{
if (tbuf == NULL) return 0;
return (uint16)(tbuf->buf - tbuf->head);
uint16 len;
if (tbuf)
len = (uint16)(tbuf->buf - tbuf->head);
else
len = 0;
return len;
}
uint16
bcm_xtlv_buf_rlen(bcm_xtlvbuf_t *tbuf)
{
if (tbuf == NULL) return 0;
return tbuf->size - bcm_xtlv_buf_len(tbuf);
uint16 rlen;
if (tbuf)
rlen = tbuf->size - bcm_xtlv_buf_len(tbuf);
else
rlen = 0;
return rlen;
}
uint8 *
bcm_xtlv_buf(bcm_xtlvbuf_t *tbuf)
{
if (tbuf == NULL) return NULL;
return tbuf->buf;
return tbuf ? tbuf->buf : NULL;
}
uint8 *
bcm_xtlv_head(bcm_xtlvbuf_t *tbuf)
{
if (tbuf == NULL) return NULL;
return tbuf->head;
return tbuf ? tbuf->head : NULL;
}
void
BCMPOSTTRAPFN(bcm_xtlv_pack_xtlv)(bcm_xtlv_t *xtlv, uint16 type, uint16 len, const uint8 *data,
bcm_xtlv_opts_t opts)
{
uint8 *data_buf;
bcm_xtlv_opts_t mask = BCM_XTLV_OPTION_IDU8 | BCM_XTLV_OPTION_LENU8;
if (!(opts & mask)) { /* default */
uint8 *idp = (uint8 *)xtlv;
uint8 *lenp = idp + sizeof(xtlv->id);
htol16_ua_store(type, idp);
htol16_ua_store(len, lenp);
data_buf = lenp + sizeof(uint16);
} else if ((opts & mask) == mask) { /* u8 id and u8 len */
uint8 *idp = (uint8 *)xtlv;
uint8 *lenp = idp + 1;
*idp = (uint8)type;
*lenp = (uint8)len;
data_buf = lenp + sizeof(uint8);
} else if (opts & BCM_XTLV_OPTION_IDU8) { /* u8 id, u16 len */
uint8 *idp = (uint8 *)xtlv;
uint8 *lenp = idp + 1;
*idp = (uint8)type;
htol16_ua_store(len, lenp);
data_buf = lenp + sizeof(uint16);
} else if (opts & BCM_XTLV_OPTION_LENU8) { /* u16 id, u8 len */
uint8 *idp = (uint8 *)xtlv;
uint8 *lenp = idp + sizeof(uint16);
htol16_ua_store(type, idp);
*lenp = (uint8)len;
data_buf = lenp + sizeof(uint8);
} else {
ASSERT(!"Unexpected xtlv option");
return;
}
if (opts & BCM_XTLV_OPTION_LENU8) {
ASSERT(len <= 0x00ff);
len &= 0xff;
}
if (data != NULL) {
memcpy(data_buf, data, len);
}
}
/* xtlv header is always packed in LE order */
void
bcm_xtlv_unpack_xtlv(const bcm_xtlv_t *xtlv, uint16 *type, uint16 *len,
const uint8 **data, bcm_xtlv_opts_t opts)
{
if (type)
*type = (uint16)bcm_xtlv_id(xtlv, opts);
if (len)
*len = (uint16)bcm_xtlv_len(xtlv, opts);
if (data)
*data = (const uint8 *)xtlv + BCM_XTLV_HDR_SIZE_EX(opts);
}
int
bcm_xtlv_put_data(bcm_xtlvbuf_t *tbuf, uint16 type, const void *data, uint16 dlen)
bcm_xtlv_put_data(bcm_xtlvbuf_t *tbuf, uint16 type, const uint8 *data, int n)
{
bcm_xtlv_t *xtlv;
int size;
if (tbuf == NULL)
return BCME_BADARG;
size = bcm_xtlv_size_for_data(dlen, tbuf->opts);
size = bcm_xtlv_size_for_data(n, tbuf->opts);
if (bcm_xtlv_buf_rlen(tbuf) < size)
return BCME_NOMEM;
xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf);
xtlv->id = htol16(type);
xtlv->len = htol16(dlen);
memcpy(xtlv->data, data, dlen);
tbuf->buf += size;
bcm_xtlv_pack_xtlv(xtlv, type, (uint16)n, data, tbuf->opts);
tbuf->buf += size; /* note: data may be NULL, reserves space */
return BCME_OK;
}
int
bcm_xtlv_put_8(bcm_xtlvbuf_t *tbuf, uint16 type, const int8 data)
static int
bcm_xtlv_put_int(bcm_xtlvbuf_t *tbuf, uint16 type, const uint8 *data, int n, int int_sz)
{
bcm_xtlv_t *xtlv;
int size;
int xtlv_len;
uint8 *xtlv_data;
int err = BCME_OK;
if (tbuf == NULL) {
err = BCME_BADARG;
goto done;
}
if (tbuf == NULL)
return BCME_BADARG;
size = bcm_xtlv_size_for_data(1, tbuf->opts);
if (bcm_xtlv_buf_rlen(tbuf) < size)
return BCME_NOMEM;
xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf);
xtlv->id = htol16(type);
xtlv->len = htol16(sizeof(data));
xtlv->data[0] = data;
tbuf->buf += size;
return BCME_OK;
/* put type and length in xtlv and reserve data space */
xtlv_len = n * int_sz;
err = bcm_xtlv_put_data(tbuf, type, NULL, xtlv_len);
if (err != BCME_OK)
goto done;
xtlv_data = (uint8 *)xtlv + bcm_xtlv_hdr_size(tbuf->opts);
/* write data w/ little-endianness into buffer - single loop, aligned access */
for (; n != 0; --n, xtlv_data += int_sz, data += int_sz) {
switch (int_sz) {
case sizeof(uint8):
break;
case sizeof(uint16):
{
uint16 v = load16_ua(data);
htol16_ua_store(v, xtlv_data);
break;
}
case sizeof(uint32):
{
uint32 v = load32_ua(data);
htol32_ua_store(v, xtlv_data);
break;
}
case sizeof(uint64):
{
uint64 v = load64_ua(data);
htol64_ua_store(v, xtlv_data);
break;
}
default:
err = BCME_UNSUPPORTED;
goto done;
}
}
done:
return err;
}
int
bcm_xtlv_put_16(bcm_xtlvbuf_t *tbuf, uint16 type, const int16 data)
bcm_xtlv_put16(bcm_xtlvbuf_t *tbuf, uint16 type, const uint16 *data, int n)
{
bcm_xtlv_t *xtlv;
int size;
if (tbuf == NULL)
return BCME_BADARG;
size = bcm_xtlv_size_for_data(2, tbuf->opts);
if (bcm_xtlv_buf_rlen(tbuf) < size)
return BCME_NOMEM;
xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf);
xtlv->id = htol16(type);
xtlv->len = htol16(sizeof(data));
htol16_ua_store(data, xtlv->data);
tbuf->buf += size;
return BCME_OK;
return bcm_xtlv_put_int(tbuf, type, (const uint8 *)data, n, sizeof(uint16));
}
int
bcm_xtlv_put_32(bcm_xtlvbuf_t *tbuf, uint16 type, const int32 data)
{
bcm_xtlv_t *xtlv;
int size;
if (tbuf == NULL)
return BCME_BADARG;
size = bcm_xtlv_size_for_data(4, tbuf->opts);
if (bcm_xtlv_buf_rlen(tbuf) < size)
return BCME_NOMEM;
xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf);
xtlv->id = htol16(type);
xtlv->len = htol16(sizeof(data));
htol32_ua_store(data, xtlv->data);
tbuf->buf += size;
return BCME_OK;
int
bcm_xtlv_put32(bcm_xtlvbuf_t *tbuf, uint16 type, const uint32 *data, int n)
{
return bcm_xtlv_put_int(tbuf, type, (const uint8 *)data, n, sizeof(uint32));
}
int
bcm_xtlv_put64(bcm_xtlvbuf_t *tbuf, uint16 type, const uint64 *data, int n)
{
return bcm_xtlv_put_int(tbuf, type, (const uint8 *)data, n, sizeof(uint64));
}
/*
@@ -191,62 +367,49 @@ bcm_xtlv_put_32(bcm_xtlvbuf_t *tbuf, uint16 type, const int32 data)
* caller's resposible for dst space check
*/
int
bcm_unpack_xtlv_entry(uint8 **tlv_buf, uint16 xpct_type, uint16 xpct_len, void *dst,
bcm_xtlv_opts_t opts)
bcm_unpack_xtlv_entry(const uint8 **tlv_buf, uint16 xpct_type, uint16 xpct_len,
uint8 *dst_data, bcm_xtlv_opts_t opts)
{
bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf;
const bcm_xtlv_t *ptlv = (const bcm_xtlv_t *)*tlv_buf;
uint16 len;
uint16 type;
const uint8 *data;
ASSERT(ptlv);
/* tlv headr is always packed in LE order */
len = ltoh16(ptlv->len);
type = ltoh16(ptlv->id);
if (len == 0) {
/* z-len tlv headers: allow, but don't process */
printf("z-len, skip unpack\n");
} else {
if ((type != xpct_type) ||
(len > xpct_len)) {
printf("xtlv_unpack Error: found[type:%d,len:%d] != xpct[type:%d,len:%d]\n",
type, len, xpct_type, xpct_len);
bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts);
if (len) {
if ((type != xpct_type) || (len > xpct_len))
return BCME_BADARG;
}
/* copy tlv record to caller's buffer */
memcpy(dst, ptlv->data, ptlv->len);
if (dst_data && data)
memcpy(dst_data, data, len); /* copy data to dst */
}
*tlv_buf = (uint8*)(*tlv_buf) + BCM_XTLV_SIZE(ptlv, opts);
*tlv_buf += BCM_XTLV_SIZE_EX(ptlv, opts);
return BCME_OK;
}
/*
* packs user data into tlv record
* advances tlv pointer to next xtlv slot
* packs user data into tlv record and advances tlv pointer to next xtlv slot
* buflen is used for tlv_buf space check
*/
int
bcm_pack_xtlv_entry(uint8 **tlv_buf, uint16 *buflen, uint16 type, uint16 len, void *src,
bcm_xtlv_opts_t opts)
bcm_pack_xtlv_entry(uint8 **tlv_buf, uint16 *buflen, uint16 type, uint16 len,
const uint8 *src_data, bcm_xtlv_opts_t opts)
{
bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf;
int size;
ASSERT(ptlv);
ASSERT(src);
size = bcm_xtlv_size_for_data(len, opts);
/* copy data from tlv buffer to dst provided by user */
if (size > *buflen) {
printf("bcm_pack_xtlv_entry: no space tlv_buf: requested:%d, available:%d\n",
size, *buflen);
return BCME_BADLEN;
}
ptlv->id = htol16(type);
ptlv->len = htol16(len);
/* copy callers data */
memcpy(ptlv->data, src, len);
bcm_xtlv_pack_xtlv(ptlv, type, len, src_data, opts);
/* advance callers pointer to tlv buff */
*tlv_buf = (uint8*)(*tlv_buf) + size;
@@ -260,42 +423,45 @@ bcm_pack_xtlv_entry(uint8 **tlv_buf, uint16 *buflen, uint16 type, uint16 len, vo
* to set function one call per found tlv record
*/
int
bcm_unpack_xtlv_buf(void *ctx, uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts,
bcm_unpack_xtlv_buf(void *ctx, const uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts,
bcm_xtlv_unpack_cbfn_t *cbfn)
{
uint16 len;
uint16 type;
int res = BCME_OK;
int size;
bcm_xtlv_t *ptlv;
const bcm_xtlv_t *ptlv;
int sbuflen = buflen;
const uint8 *data;
int hdr_size;
ASSERT(!buflen || tlv_buf);
ASSERT(!buflen || cbfn);
while (sbuflen >= (int)BCM_XTLV_HDR_SIZE) {
ptlv = (bcm_xtlv_t *)tlv_buf;
/* tlv header is always packed in LE order */
len = ltoh16(ptlv->len);
type = ltoh16(ptlv->id);
hdr_size = BCM_XTLV_HDR_SIZE_EX(opts);
while (sbuflen >= hdr_size) {
ptlv = (const bcm_xtlv_t *)tlv_buf;
bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts);
size = bcm_xtlv_size_for_data(len, opts);
sbuflen -= size;
/* check for possible buffer overrun */
if (sbuflen < 0)
break;
if ((res = cbfn(ctx, ptlv->data, type, len)) != BCME_OK)
/* check for buffer overrun */
if (sbuflen < 0) {
break;
tlv_buf = (uint8*)tlv_buf + size;
}
if ((res = cbfn(ctx, data, type, len)) != BCME_OK) {
break;
}
tlv_buf += size;
}
return res;
}
int
bcm_pack_xtlv_buf(void *ctx, void *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts,
bcm_pack_xtlv_buf(void *ctx, uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts,
bcm_pack_xtlv_next_info_cbfn_t get_next, bcm_pack_xtlv_pack_next_cbfn_t pack_next,
int *outlen)
{
@@ -307,13 +473,16 @@ bcm_pack_xtlv_buf(void *ctx, void *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts,
uint8 *buf;
bool more;
int size;
int hdr_size;
ASSERT(get_next && pack_next);
buf = (uint8 *)tlv_buf;
buf = tlv_buf;
startp = buf;
endp = (uint8 *)buf + buflen;
more = TRUE;
hdr_size = BCM_XTLV_HDR_SIZE_EX(opts);
while (more && (buf < endp)) {
more = get_next(ctx, &tlv_id, &tlv_len);
size = bcm_xtlv_size_for_data(tlv_len, opts);
@@ -322,9 +491,8 @@ bcm_pack_xtlv_buf(void *ctx, void *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts,
goto done;
}
htol16_ua_store(tlv_id, buf);
htol16_ua_store(tlv_len, buf + sizeof(tlv_id));
pack_next(ctx, tlv_id, tlv_len, buf + BCM_XTLV_HDR_SIZE);
bcm_xtlv_pack_xtlv((bcm_xtlv_t *)buf, tlv_id, tlv_len, NULL, opts);
pack_next(ctx, tlv_id, tlv_len, buf + hdr_size);
buf += size;
}
@@ -342,20 +510,22 @@ done:
* pack xtlv buffer from memory according to xtlv_desc_t
*/
int
bcm_pack_xtlv_buf_from_mem(void **tlv_buf, uint16 *buflen, xtlv_desc_t *items,
bcm_pack_xtlv_buf_from_mem(uint8 **tlv_buf, uint16 *buflen, const xtlv_desc_t *items,
bcm_xtlv_opts_t opts)
{
int res = BCME_OK;
uint8 *ptlv = (uint8 *)*tlv_buf;
uint8 *ptlv = *tlv_buf;
while (items->type != 0) {
if ((items->len > 0) && (res = bcm_pack_xtlv_entry(&ptlv,
buflen, items->type,
items->len, items->ptr, opts) != BCME_OK)) {
break;
if (items->len && items->ptr) {
res = bcm_pack_xtlv_entry(&ptlv, buflen, items->type,
items->len, items->ptr, opts);
if (res != BCME_OK)
break;
}
items++;
}
*tlv_buf = ptlv; /* update the external pointer */
return res;
}
@@ -365,12 +535,14 @@ bcm_pack_xtlv_buf_from_mem(void **tlv_buf, uint16 *buflen, xtlv_desc_t *items,
*
*/
int
bcm_unpack_xtlv_buf_to_mem(void *tlv_buf, int *buflen, xtlv_desc_t *items, bcm_xtlv_opts_t opts)
bcm_unpack_xtlv_buf_to_mem(const uint8 *tlv_buf, int *buflen, xtlv_desc_t *items,
bcm_xtlv_opts_t opts)
{
int res = BCME_OK;
bcm_xtlv_t *elt;
const bcm_xtlv_t *elt;
elt = bcm_valid_xtlv((bcm_xtlv_t *)tlv_buf, *buflen, opts) ? (bcm_xtlv_t *)tlv_buf : NULL;
elt = bcm_valid_xtlv((const bcm_xtlv_t *)tlv_buf, *buflen, opts) ?
(const bcm_xtlv_t *)tlv_buf : NULL;
if (!elt || !items) {
res = BCME_BADARG;
return res;
@@ -379,14 +551,16 @@ bcm_unpack_xtlv_buf_to_mem(void *tlv_buf, int *buflen, xtlv_desc_t *items, bcm_x
for (; elt != NULL && res == BCME_OK; elt = bcm_next_xtlv(elt, buflen, opts)) {
/* find matches in desc_t items */
xtlv_desc_t *dst_desc = items;
uint16 len = ltoh16(elt->len);
uint16 len, type;
const uint8 *data;
bcm_xtlv_unpack_xtlv(elt, &type, &len, &data, opts);
while (dst_desc->type != 0) {
if (ltoh16(elt->id) == dst_desc->type) {
if (type == dst_desc->type) {
if (len != dst_desc->len) {
res = BCME_BADLEN;
} else {
memcpy(dst_desc->ptr, elt->data, len);
memcpy(dst_desc->ptr, data, len);
}
break;
}
@@ -394,7 +568,7 @@ bcm_unpack_xtlv_buf_to_mem(void *tlv_buf, int *buflen, xtlv_desc_t *items, bcm_x
}
}
if (res == BCME_OK && *buflen != 0)
if (res == BCME_OK && *buflen != 0) /* this does not look right */
res = BCME_BUFTOOSHORT;
return res;
@@ -402,56 +576,72 @@ bcm_unpack_xtlv_buf_to_mem(void *tlv_buf, int *buflen, xtlv_desc_t *items, bcm_x
/*
* return data pointer of a given ID from xtlv buffer.
* If the specified xTLV ID is found, on return *data_len_out will contain
* If the specified xTLV ID is found, on return *datalen will contain
* the the data length of the xTLV ID.
*/
void *
bcm_get_data_from_xtlv_buf(uint8 *tlv_buf, uint16 buflen, uint16 id,
uint16 *datalen_out, bcm_xtlv_opts_t opts)
const uint8*
bcm_get_data_from_xtlv_buf(const uint8 *tlv_buf, uint16 buflen, uint16 id,
uint16 *datalen, bcm_xtlv_opts_t opts)
{
void *retptr = NULL;
const uint8 *retptr = NULL;
uint16 type, len;
int size;
bcm_xtlv_t *ptlv;
const bcm_xtlv_t *ptlv;
int sbuflen = buflen;
const uint8 *data;
int hdr_size;
while (sbuflen >= (int)BCM_XTLV_HDR_SIZE) {
ptlv = (bcm_xtlv_t *)tlv_buf;
COV_TAINTED_DATA_SINK(buflen);
COV_NEG_SINK(buflen);
hdr_size = BCM_XTLV_HDR_SIZE_EX(opts);
/* Init the datalength */
if (datalen) {
*datalen = 0;
}
while (sbuflen >= hdr_size) {
ptlv = (const bcm_xtlv_t *)tlv_buf;
bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts);
/* tlv header is always packed in LE order */
type = ltoh16(ptlv->id);
len = ltoh16(ptlv->len);
size = bcm_xtlv_size_for_data(len, opts);
sbuflen -= size;
/* check for possible buffer overrun */
if (sbuflen < 0) {
printf("%s %d: Invalid sbuflen %d\n",
__FUNCTION__, __LINE__, sbuflen);
if (sbuflen < 0) /* buffer overrun? */
break;
}
if (id == type) {
retptr = ptlv->data;
if (datalen_out) {
*datalen_out = len;
}
retptr = data;
if (datalen)
*datalen = len;
break;
}
tlv_buf += size;
}
COV_TAINTED_DATA_ARG(retptr);
return retptr;
}
int bcm_xtlv_size(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts)
bcm_xtlv_t*
bcm_xtlv_bcopy(const bcm_xtlv_t *src, bcm_xtlv_t *dst,
int src_buf_len, int dst_buf_len, bcm_xtlv_opts_t opts)
{
int size; /* entire size of the XTLV including header, data, and optional padding */
int len; /* XTLV's value real length wthout padding */
bcm_xtlv_t *dst_next = NULL;
src = (src && bcm_valid_xtlv(src, src_buf_len, opts)) ? src : NULL;
if (src && dst) {
uint16 type;
uint16 len;
const uint8 *data;
int size;
bcm_xtlv_unpack_xtlv(src, &type, &len, &data, opts);
size = bcm_xtlv_size_for_data(len, opts);
if (size <= dst_buf_len) {
bcm_xtlv_pack_xtlv(dst, type, len, data, opts);
dst_next = (bcm_xtlv_t *)((uint8 *)dst + size);
}
}
len = BCM_XTLV_LEN(elt);
size = bcm_xtlv_size_for_data(len, opts);
return size;
return dst_next;
}

26
drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus.c Normal file → Executable file
View File

@@ -621,7 +621,7 @@ dbus_get_fw_nvram(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path)
/* For Get nvram */
file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
if (file_exists) {
nv_image = dhd_os_open_image(pnv_path);
nv_image = dhd_os_open_image1(dhd_bus->dhd, pnv_path);
if (nv_image == NULL) {
printf("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path);
goto err;
@@ -646,14 +646,14 @@ dbus_get_fw_nvram(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path)
goto err;
}
if (nv_image) {
dhd_os_close_image(nv_image);
dhd_os_close_image1(dhd_bus->dhd, nv_image);
nv_image = NULL;
}
/* For Get first block of fw to calculate total_len */
file_exists = ((pfw_path != NULL) && (pfw_path[0] != '\0'));
if (file_exists) {
fw_image = dhd_os_open_image(pfw_path);
fw_image = dhd_os_open_image1(dhd_bus->dhd, pfw_path);
if (fw_image == NULL) {
printf("%s: Open fw file failed %s\n", __FUNCTION__, pfw_path);
goto err;
@@ -730,11 +730,11 @@ err:
if (fw_memblock)
MFREE(dhd_bus->pub.osh, fw_memblock, MAX_NVRAMBUF_SIZE);
if (fw_image)
dhd_os_close_image(fw_image);
dhd_os_close_image1(dhd_bus->dhd, fw_image);
if (nv_memblock)
MFREE(dhd_bus->pub.osh, nv_memblock, MAX_NVRAMBUF_SIZE);
if (nv_image)
dhd_os_close_image(nv_image);
dhd_os_close_image1(dhd_bus->dhd, nv_image);
return bcmerror;
}
@@ -1055,7 +1055,7 @@ dbus_if_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb)
* When lower DBUS level signals that a send IRB completed, either successful or not, the higher
* level (e.g. dhd_linux.c) has to be notified, and transmit flow control has to be evaluated.
*/
static void BCMFASTPATH
static void
dbus_if_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status)
{
dhd_bus_t *dhd_bus = (dhd_bus_t *) handle;
@@ -1126,7 +1126,7 @@ dbus_if_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status)
* level (e.g. dhd_linux.c) has to be notified, and fresh free receive IRBs may have to be given
* to lower levels.
*/
static void BCMFASTPATH
static void
dbus_if_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status)
{
dhd_bus_t *dhd_bus = (dhd_bus_t *) handle;
@@ -2682,9 +2682,6 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
}
}
#ifdef PKT_STATICS
memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t));
#endif
return bcmerror;
}
@@ -2704,7 +2701,7 @@ dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path,
bus->dhd->clm_path = pclm_path;
bus->dhd->conf_path = pconf_path;
dhd_conf_set_path_params(bus->dhd, NULL, bus->fw_path, bus->nv_path);
dhd_conf_set_path_params(bus->dhd, bus->fw_path, bus->nv_path);
}
@@ -2781,9 +2778,10 @@ dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype,
}
if (!g_pub) {
/* Ok, finish the attach to the OS network interface */
if (dhd_register_if(pub, 0, TRUE) != 0) {
DBUSERR(("%s: dhd_register_if failed\n", __FUNCTION__));
/* Ok, have the per-port tell the stack we're open for business */
if (dhd_attach_net(bus->dhd, TRUE) != 0)
{
DBUSERR(("%s: Net attach failed!!\n", __FUNCTION__));
goto fail;
}
pub->hang_report = TRUE;

View File

@@ -39,6 +39,7 @@
#include <bcmutils.h>
#include <dbus.h>
#include <usbrdl.h>
#include <bcmdevs_legacy.h>
#include <bcmdevs.h>
#include <bcmendian.h>

View File

@@ -75,10 +75,11 @@
#include <linux/random.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/uaccess.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
#include <dbus.h>
#include <bcmutils.h>
#include <bcmdevs_legacy.h>
#include <bcmdevs.h>
#include <linux/usb.h>
#include <usbrdl.h>
@@ -603,7 +604,7 @@ int matches_loopback_pkt(void *buf);
* multiple code paths in this file dequeue a URB request, this function makes sure that it happens
* in a concurrency save manner. Don't call this from a sleepable process context.
*/
static urb_req_t * BCMFASTPATH
static urb_req_t *
dbus_usbos_qdeq(struct list_head *urbreq_q, spinlock_t *lock)
{
unsigned long flags;
@@ -634,7 +635,7 @@ dbus_usbos_qdeq(struct list_head *urbreq_q, spinlock_t *lock)
return req;
}
static void BCMFASTPATH
static void
dbus_usbos_qenq(struct list_head *urbreq_q, urb_req_t *req, spinlock_t *lock)
{
unsigned long flags;
@@ -845,7 +846,7 @@ dbus_usbos_send_complete(CALLBACK_ARGS)
* In order to receive USB traffic from the dongle, we need to supply the Linux kernel with a free
* URB that is going to contain received data.
*/
static int BCMFASTPATH
static int
dbus_usbos_recv_urb_submit(usbos_info_t *usbos_info, dbus_irb_rx_t *rxirb, uint32 ep_idx)
{
urb_req_t *req;
@@ -929,7 +930,7 @@ fail:
* Called by worked thread when a 'receive URB' completed or Linux kernel when it returns a URB to
* this driver.
*/
static void BCMFASTPATH
static void
dbus_usbos_recv_complete_handle(urb_req_t *req, int len, int status)
{
dbus_irb_rx_t *rxirb = req->arg;

2882
drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd.h Normal file → Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,228 @@
/*
* Bit packing and Base64 utils for EWP
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id$
*/
#include <dhd_bitpack.h>
#define BIT_PACK_OVERFLOW 0xFFFFFFFFu
const char* base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
#define BASE64_MAX_VALUE 63u
#define BASE64_UNIT_LEN 6u
#define BASE64_OFFSET0 0u
#define BASE64_OFFSET1 6u
#define BASE64_OFFSET2 12u
#define MASK_UPPER_6BIT 0xfc
#define MASK_LOWER_6BIT 0x3f
#define MASK_UPPER_4BIT 0xf0
#define MASK_LOWER_4BIT 0x0f
#define MASK_UPPER_2BIT 0xc0
#define MASK_LOWER_2BIT 0x03
#define SHIFT_2BIT 2u
#define SHIFT_4BIT 4u
#define SHIFT_6BIT 6u
#define BASE64_PADDING_MARGIN 4u
/*
* Function: dhd_bit_pack
*
* Purpose: bit data packing to given buffer
*
* Input Parameters:
* buf buffer to pack bit data
* buf_len total buffer length
* bit_offset offset in buffer (bitwise)
* data data to pack (max 32 bit)
* bit_length bit length to pack
*
* Output:
* Updated bit offset in buf
*/
int32
dhd_bit_pack(char *buf, int buf_len, int bit_offset, uint32 data, int32 bit_length)
{
int32 byte_shift = (bit_offset / 8);
int32 local_bit_offset = bit_offset % 8;
int32 available_bit = 8 - local_bit_offset;
int32 remain_bit = bit_length;
uint32 cropped_data;
int32 idx;
int32 total_byte = BYTE_SIZE(local_bit_offset + bit_length);
if (bit_length > 32) {
/* exceeded max bit length, do nothing */
return bit_offset;
}
if (BYTE_SIZE(bit_offset + bit_length) > buf_len) {
/* can't pack more bits if expected offset is
* exceeded then buffer size
*/
return bit_offset;
}
if (bit_length < 32 && data >= 1<<bit_length) {
cropped_data = BIT_PACK_OVERFLOW << (32 - bit_length);
cropped_data = cropped_data >> (32 - bit_length);
} else {
cropped_data = data << (32 - bit_length);
cropped_data = cropped_data >> (32 - bit_length);
}
buf += byte_shift;
remain_bit = bit_length;
if (total_byte > 10) {
return bit_offset;
}
for (idx = 0; idx < total_byte; idx++) {
char temp_byte = 0x00;
if (idx == 0) {
local_bit_offset = bit_offset % 8;
} else {
local_bit_offset = 0;
}
available_bit = 8 - local_bit_offset;
remain_bit -= available_bit;
if (remain_bit >= 0) {
temp_byte = cropped_data >> remain_bit;
} else {
temp_byte = cropped_data << (-1*remain_bit);
}
*buf = *buf | temp_byte;
buf ++;
}
bit_offset += bit_length;
return bit_offset;
}
static char
dhd_base64_get_code(char input)
{
if (input > BASE64_MAX_VALUE) {
return '=';
}
return base64_table[(int)input];
}
/*
* Function: dhd_base64_encode
*
* Purpose: base64 encoding module which converts from 8 bits to
* 6 bit based, base64 format using base64_table
* eg: input: hex-123456
* bin-0001|0010|0011|0100|0101|0110
* encode every 6 bit :
* bin-000100|100011|010001|010110
* base64 code :
* base64-EjRW
*
* Input Parameters:
* in_buf input buffer
* in_buf_len length of input buffer
* out_buf output buffer
* out_buf_len length_ of output buffer
*
* Output:
* length of encoded base64 string
*/
int32
dhd_base64_encode(char* in_buf, int32 in_buf_len, char* out_buf, int32 out_buf_len)
{
char* input_pos;
char* input_end;
char* base64_out;
char* base64_out_pos;
char* base64_output_end;
char current_byte = 0;
char masked_byte = 0;
int32 estimated_out_len = 0;
int32 offset = 0;
if (!in_buf || !out_buf || in_buf_len == 0 || out_buf_len == 0) {
/* wrong input parameters */
return 0;
}
input_pos = in_buf;
input_end = in_buf + in_buf_len;
base64_out = out_buf;
base64_out_pos = base64_out;
base64_output_end = out_buf + out_buf_len - BASE64_PADDING_MARGIN;
estimated_out_len = in_buf_len / 3 * 4;
if (estimated_out_len > out_buf_len) {
/* estimated output length is
* larger than output buffer size
*/
return 0;
}
while (input_pos != input_end) {
if (base64_out_pos > base64_output_end) {
/* outbuf buffer size exceeded, finish encoding */
break;
}
if (offset == BASE64_OFFSET0) {
current_byte = *input_pos++;
masked_byte = (current_byte & MASK_UPPER_6BIT) >> SHIFT_2BIT;
*base64_out_pos++ = dhd_base64_get_code(masked_byte);
masked_byte = (current_byte & MASK_LOWER_2BIT) << SHIFT_4BIT;
offset += BASE64_UNIT_LEN;
} else if (offset == BASE64_OFFSET1) {
current_byte = *input_pos++;
masked_byte |= (current_byte & MASK_UPPER_4BIT) >> SHIFT_4BIT;
*base64_out_pos++ = dhd_base64_get_code(masked_byte);
masked_byte = (current_byte & MASK_LOWER_4BIT) << SHIFT_2BIT;
offset += BASE64_UNIT_LEN;
} else if (offset == BASE64_OFFSET2) {
current_byte = *input_pos++;
masked_byte |= (current_byte & MASK_UPPER_2BIT) >> SHIFT_6BIT;
*base64_out_pos++ = dhd_base64_get_code(masked_byte);
offset += BASE64_UNIT_LEN;
masked_byte = (current_byte & MASK_LOWER_6BIT);
*base64_out_pos++ = dhd_base64_get_code(masked_byte);
offset = BASE64_OFFSET0;
}
}
if (offset == BASE64_OFFSET1) {
*base64_out_pos++ = dhd_base64_get_code(masked_byte);
*base64_out_pos++ = '=';
*base64_out_pos++ = '=';
} else if (offset == BASE64_OFFSET2) {
*base64_out_pos++ = dhd_base64_get_code(masked_byte);
*base64_out_pos++ = '=';
}
return base64_out_pos - base64_out;
}

View File

@@ -1,14 +1,14 @@
/*
* BCM common config options
* Bit packing and Base64 utils for EWP
*
* Copyright (C) 2020, Broadcom.
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,17 +16,18 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcm_cfg.h 514727 2014-11-12 03:02:48Z $
* $Id$
*/
#ifndef _bcm_cfg_h_
#define _bcm_cfg_h_
#endif /* _bcm_cfg_h_ */
#ifndef __BITPACK_H_
#define __BITPACK_H_
#define BYTE_SIZE(a) ((a + 7)/8)
extern int32 dhd_bit_pack(char *buf, int32 buf_len, int bit_offset, uint32 data, int32 bit_length);
extern int32 dhd_base64_encode(char* in_buf, int32 in_buf_len, char* out_buf, int32 out_buf_len);
#endif /* __BITPACK_H */

View File

@@ -4,14 +4,14 @@
* Provides type definitions and function prototypes used to link the
* DHD OS, bus, and protocol modules.
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -19,15 +19,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_bus.h 698895 2017-05-11 02:55:17Z $
* $Id$
*/
#ifndef _dhd_bus_h_
@@ -41,6 +37,9 @@ extern int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len);
* Exported from dhd bus module (dhd_usb, dhd_sdio)
*/
/* global variable for the bus */
extern struct dhd_bus *g_dhd_bus;
/* Indicate (dis)interest in finding dongles. */
extern int dhd_bus_register(void);
extern void dhd_bus_unregister(void);
@@ -64,11 +63,6 @@ extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int *idletime);
/* Set the Bus Idle Time */
extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time);
/* Size of Extended Trap data Buffer */
#ifdef BCMPCIE
#define BCMPCIE_EXT_TRAP_DATA_MAXLEN 4096
#endif
/* Send a data frame to the dongle. Callee disposes of txp. */
#ifdef BCMPCIE
extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx);
@@ -76,7 +70,12 @@ extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx);
extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp);
#endif
extern struct device * dhd_bus_to_dev(struct dhd_bus *bus);
#ifdef BCMPCIE
extern uint16 dhd_prot_get_rxbufpost_sz(dhd_pub_t *dhd);
extern uint16 dhd_prot_get_h2d_rx_post_active(dhd_pub_t *dhd);
extern uint16 dhd_prot_get_d2h_rx_cpln_active(dhd_pub_t *dhd);
extern void dhdpcie_cto_recovery_handler(dhd_pub_t *dhd);
#endif /* BCMPCIE */
/* Send/receive a control message to/from the dongle.
* Expects caller to enforce a single outstanding transaction.
@@ -90,21 +89,24 @@ extern bool dhd_bus_watchdog(dhd_pub_t *dhd);
extern int dhd_bus_oob_intr_register(dhd_pub_t *dhdp);
extern void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp);
extern void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable);
extern int dhd_bus_get_oob_irq_num(dhd_pub_t *dhdp);
extern void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub);
extern void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub);
extern bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub);
/* Device console input function */
extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen);
#ifdef CONSOLE_DPC
extern int dhd_bus_txcons(dhd_pub_t *dhd, uchar *msg, uint msglen);
#endif
/* Deferred processing for the bus, return TRUE requests reschedule */
extern bool dhd_bus_dpc(struct dhd_bus *bus);
extern void dhd_bus_isr(bool * InterruptRecognized, bool * QueueMiniportHandleInterrupt, void *arg);
/* Check for and handle local prot-specific iovar commands */
extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
void *params, int plen, void *arg, int len, bool set);
void *params, uint plen, void *arg, uint len, bool set);
/* Add bus dump output to a buffer */
extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
@@ -112,6 +114,11 @@ extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
/* Clear any bus counters */
extern void dhd_bus_clearcounts(dhd_pub_t *dhdp);
#if defined(BCMSDIO) && defined(PKT_STATICS)
extern void dhd_bus_dump_txpktstatics(struct dhd_bus *bus);
extern void dhd_bus_clear_txpktstatics(struct dhd_bus *bus);
#endif
/* return the dongle chipid */
extern uint dhd_bus_chip(struct dhd_bus *bus);
@@ -123,7 +130,7 @@ extern void dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_par
extern void *dhd_bus_pub(struct dhd_bus *bus);
extern void *dhd_bus_txq(struct dhd_bus *bus);
extern const void *dhd_bus_sih(struct dhd_bus *bus);
extern void *dhd_bus_sih(struct dhd_bus *bus);
extern uint dhd_bus_hdrlen(struct dhd_bus *bus);
#ifdef BCMSDIO
extern void dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val);
@@ -146,8 +153,10 @@ extern int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_nu
#if defined(DHD_FW_COREDUMP) && (defined(BCMPCIE) || defined(BCMSDIO))
extern int dhd_bus_mem_dump(dhd_pub_t *dhd);
extern int dhd_bus_get_mem_dump(dhd_pub_t *dhdp);
#else
#define dhd_bus_mem_dump(x)
#define dhd_bus_get_mem_dump(x)
#endif /* DHD_FW_COREDUMP && (BCMPCIE || BCMSDIO) */
#ifdef BCMPCIE
@@ -188,10 +197,11 @@ enum {
TOTAL_LFRAG_PACKET_CNT,
MAX_HOST_RXBUFS,
HOST_API_VERSION,
#ifdef D2H_MINIDUMP
DNGL_TO_HOST_TRAP_ADDR_LEN,
#endif /* D2H_MINIDUMP */
DNGL_TO_HOST_TRAP_ADDR,
#ifdef HOFFLOAD_MODULES
WRT_HOST_MODULE_ADDR
#endif
HOST_SCB_ADDR, /* update host scb base address to dongle */
};
typedef void (*dhd_mb_ring_t) (struct dhd_bus *, uint32);
@@ -220,15 +230,19 @@ extern int dhd_bus_flow_ring_flush_request(struct dhd_bus *bus, void *flow_ring_
extern void dhd_bus_flow_ring_flush_response(struct dhd_bus *bus, uint16 flowid, uint32 status);
extern uint32 dhd_bus_max_h2d_queues(struct dhd_bus *bus);
extern int dhd_bus_schedule_queue(struct dhd_bus *bus, uint16 flow_id, bool txs);
extern void dhd_bus_set_linkdown(dhd_pub_t *dhdp, bool val);
#ifdef IDLE_TX_FLOW_MGMT
extern void dhd_bus_flow_ring_resume_response(struct dhd_bus *bus, uint16 flowid, int32 status);
#endif /* IDLE_TX_FLOW_MGMT */
#ifdef BCMDBG
extern void
dhd_bus_flow_ring_cnt_update(struct dhd_bus *bus, uint16 flowid, uint32 txstatus);
#endif
extern int dhdpcie_bus_clock_start(struct dhd_bus *bus);
extern int dhdpcie_bus_clock_stop(struct dhd_bus *bus);
#if defined(LINUX) || defined(linux)
extern int dhdpcie_bus_start_host_dev(struct dhd_bus *bus);
extern int dhdpcie_bus_stop_host_dev(struct dhd_bus *bus);
extern int dhdpcie_bus_enable_device(struct dhd_bus *bus);
extern int dhdpcie_bus_disable_device(struct dhd_bus *bus);
extern int dhdpcie_bus_alloc_resource(struct dhd_bus *bus);
@@ -237,12 +251,19 @@ extern bool dhdpcie_bus_dongle_attach(struct dhd_bus *bus);
extern int dhd_bus_release_dongle(struct dhd_bus *bus);
extern int dhd_bus_request_irq(struct dhd_bus *bus);
extern int dhdpcie_get_pcieirq(struct dhd_bus *bus, unsigned int *irq);
extern void dhd_bus_aer_config(struct dhd_bus *bus);
#else
static INLINE void dhd_bus_aer_config(struct dhd_bus *bus) { }
#endif /* LINUX || linux */
extern void dhdpcie_cto_init(struct dhd_bus *bus, bool enable);
extern struct device * dhd_bus_to_dev(struct dhd_bus *bus);
extern int dhdpcie_cto_init(struct dhd_bus *bus, bool enable);
extern int dhdpcie_cto_cfg_init(struct dhd_bus *bus, bool enable);
extern void dhdpcie_ssreset_dis_enum_rst(struct dhd_bus *bus);
#ifdef DHD_FW_COREDUMP
extern struct dhd_bus *g_dhd_bus;
extern int dhd_dongle_mem_dump(void);
#endif /* DHD_FW_COREDUMP */
@@ -254,6 +275,13 @@ extern void dhd_bus_handle_mb_data(struct dhd_bus *bus, uint32 d2h_mb_data);
/* dump the device trap informtation */
extern void dhd_bus_dump_trap_info(struct dhd_bus *bus, struct bcmstrbuf *b);
extern void dhd_bus_copy_trap_sig(struct dhd_bus *bus, trap_t *tr);
#ifdef WL_CFGVENDOR_SEND_HANG_EVENT
extern void dhd_dump_pcie_rc_regs_for_linkdown(dhd_pub_t *dhd, int *bytes_written);
void copy_hang_info_linkdown(dhd_pub_t *dhd);
void copy_ext_trap_sig(dhd_pub_t *dhd, trap_t *tr);
void copy_hang_info_trap(dhd_pub_t *dhd);
#endif /* WL_CFGVENDOR_SEND_HANG_EVENT */
/* Function to set default min res mask */
extern bool dhd_bus_set_default_min_res_mask(struct dhd_bus *bus);
@@ -261,11 +289,52 @@ extern bool dhd_bus_set_default_min_res_mask(struct dhd_bus *bus);
/* Function to reset PMU registers */
extern void dhd_bus_pmu_reg_reset(dhd_pub_t *dhdp);
#ifdef DHD_ULP
extern void dhd_bus_ulp_disable_console(dhd_pub_t *dhdp);
extern void dhd_bus_ucode_download(struct dhd_bus *bus);
#endif /* DHD_ULP */
extern int dhd_bus_readwrite_bp_addr(dhd_pub_t *dhdp, uint addr, uint size, uint* data, bool read);
extern int dhd_get_idletime(dhd_pub_t *dhd);
extern bool dhd_get_rpm_state(dhd_pub_t *dhd);
extern void dhd_set_rpm_state(dhd_pub_t *dhd, bool state);
#ifdef BCMPCIE
extern void dhd_bus_dump_console_buffer(struct dhd_bus *bus);
extern void dhd_bus_intr_count_dump(dhd_pub_t *dhdp);
extern bool dhd_bus_query_dpc_sched_errors(dhd_pub_t *dhdp);
extern int dhd_bus_dmaxfer_lpbk(dhd_pub_t *dhdp, uint32 type);
extern bool dhd_bus_check_driver_up(void);
extern int dhd_bus_get_cto(dhd_pub_t *dhdp);
extern void dhd_bus_set_linkdown(dhd_pub_t *dhdp, bool val);
extern int dhd_bus_get_linkdown(dhd_pub_t *dhdp);
#ifdef CONFIG_ARCH_MSM
extern void dhd_bus_inform_ep_loaded_to_rc(dhd_pub_t *dhdp, bool up);
#endif /* CONFIG_ARCH_MSM */
extern int dhd_bus_checkdied(struct dhd_bus *bus, char *data, uint size);
#else
#define dhd_bus_dump_console_buffer(x)
static INLINE void dhd_bus_intr_count_dump(dhd_pub_t *dhdp) { UNUSED_PARAMETER(dhdp); }
static INLINE bool dhd_bus_query_dpc_sched_errors(dhd_pub_t *dhdp) { return 0; }
static INLINE int dhd_bus_dmaxfer_lpbk(dhd_pub_t *dhdp, uint32 type) { return 0; }
static INLINE bool dhd_bus_check_driver_up(void) { return FALSE; }
extern INLINE void dhd_bus_set_linkdown(dhd_pub_t *dhdp, bool val) { }
extern INLINE int dhd_bus_get_linkdown(dhd_pub_t *dhdp) { return 0; }
static INLINE int dhd_bus_get_cto(dhd_pub_t *dhdp) { return 0; }
extern INLINE int dhd_bus_checkdied(struct dhd_bus *bus, char *data, uint size) { return 0; }
#endif /* BCMPCIE */
#if defined(BCMPCIE) && defined(EWP_ETD_PRSRV_LOGS)
void dhdpcie_get_etd_preserve_logs(dhd_pub_t *dhd, uint8 *ext_trap_data,
void *event_decode_data);
#endif
extern uint16 dhd_get_chipid(struct dhd_bus *bus);
#ifdef BTLOG
extern void dhd_bus_rx_bt_log(struct dhd_bus *bus, void* pkt);
#endif /* BTLOG */
#ifdef DHD_WAKE_STATUS
extern wake_counts_t* dhd_bus_get_wakecount(dhd_pub_t *dhd);
extern int dhd_bus_get_bus_wake(dhd_pub_t * dhd);
#endif /* DHD_WAKE_STATUS */
#ifdef BT_OVER_SDIO
/*
@@ -278,18 +347,83 @@ int __dhdsdio_clk_enable(struct dhd_bus *bus, bus_owner_t owner, int can_wait);
int __dhdsdio_clk_disable(struct dhd_bus *bus, bus_owner_t owner, int can_wait);
void dhdsdio_reset_bt_use_count(struct dhd_bus *bus);
#endif /* BT_OVER_SDIO */
int dhd_bus_perform_flr(struct dhd_bus *bus, bool force_fail);
extern bool dhd_bus_get_flr_force_fail(struct dhd_bus *bus);
extern bool dhd_bus_aspm_enable_rc_ep(struct dhd_bus *bus, bool enable);
extern void dhd_bus_l1ss_enable_rc_ep(struct dhd_bus *bus, bool enable);
bool dhd_bus_is_multibp_capable(struct dhd_bus *bus);
#ifdef BT_OVER_PCIE
int dhd_bus_pwr_off(dhd_pub_t *dhdp, int reason);
int dhd_bus_pwr_on(dhd_pub_t *dhdp, int reason);
int dhd_bus_pwr_toggle(dhd_pub_t *dhdp, int reason);
bool dhdpcie_is_btop_chip(struct dhd_bus *bus);
bool dhdpcie_is_bt_loaded(struct dhd_bus *bus);
int dhdpcie_redownload_fw(dhd_pub_t *dhdp);
extern void dhd_bus_pcie_pwr_req_reload_war(struct dhd_bus *bus);
int dhd_bus_perform_flr_with_quiesce(dhd_pub_t *dhdp, struct dhd_bus *bus,
bool init_deinit_path);
#endif /* BT_OVER_PCIE */
#ifdef BCMPCIE
extern void dhd_bus_dump_console_buffer(struct dhd_bus *bus);
#else
#define dhd_bus_dump_console_buffer(x)
extern void dhdpcie_advertise_bus_cleanup(dhd_pub_t *dhdp);
extern void dhd_msgbuf_iovar_timeout_dump(dhd_pub_t *dhd);
extern void dhdpcie_induce_cbp_hang(dhd_pub_t *dhd);
#endif /* BCMPCIE */
extern uint16 dhd_get_chipid(dhd_pub_t *dhd);
extern bool dhd_bus_force_bt_quiesce_enabled(struct dhd_bus *bus);
extern void dhd_bwm_bt_quiesce(struct dhd_bus *bus);
extern void dhd_bwm_bt_resume(struct dhd_bus *bus);
extern int dhd_get_idletime(dhd_pub_t *dhd);
#ifdef DHD_SSSR_DUMP
extern int dhd_bus_fis_trigger(dhd_pub_t *dhd);
extern int dhd_bus_fis_dump(dhd_pub_t *dhd);
#endif /* DHD_SSSR_DUMP */
#ifdef DHD_WAKE_STATUS
extern wake_counts_t* dhd_bus_get_wakecount(dhd_pub_t *dhd);
extern int dhd_bus_get_bus_wake(dhd_pub_t * dhd);
#endif /* DHD_WAKE_STATUS */
#ifdef PCIE_FULL_DONGLE
extern int dhdpcie_set_dma_ring_indices(dhd_pub_t *dhd, int32 int_val);
#endif /* PCIE_FULL_DONGLE */
#ifdef D2H_MINIDUMP
#ifndef DHD_FW_COREDUMP
/* Minidump depends on DHD_FW_COREDUMP to dump minidup
* This dependency is intentional to avoid multiple work queue
* to dump the SOCRAM, minidum ..etc.
*/
#error "Minidump doesnot work as DHD_FW_COREDUMP is not defined"
#endif /* DHD_FW_COREDUMP */
#ifdef BCM_BUZZZ
/*
* In pciedev_shared_t buzz_dbg_ptr and device_trap_debug_buffer_len
* are overloaded. So when BCM_BUZZZ is defined MINIDUMP should not be defined or
* vice versa.
*/
#error "Minidump doesnot work as BCM_BUZZZ is defined"
#endif /* BCM_BUZZZ */
extern bool dhd_bus_is_minidump_enabled(dhd_pub_t *dhdp);
dhd_dma_buf_t* dhd_prot_get_minidump_buf(dhd_pub_t *dhd);
#endif /* D2H_MINIDUMP */
#ifdef DHD_CFG80211_SUSPEND_RESUME
extern void dhd_cfg80211_suspend(dhd_pub_t *dhdp);
extern void dhd_cfg80211_resume(dhd_pub_t *dhdp);
#endif /* DHD_CFG80211_SUSPEND_RESUME */
#ifdef DHD_SDTC_ETB_DUMP
extern int dhd_bus_get_etb_info(dhd_pub_t *dhd, uint32 etb_info_addr, etb_info_t *etb_info);
extern int dhd_bus_get_sdtc_etb(dhd_pub_t *dhd, uint8 *sdtc_etb_mempool,
uint addr, uint read_bytes);
#endif /* DHD_SDTC_ETB_DUMP */
extern int dhd_socram_dump(struct dhd_bus *bus);
extern int dhdpcie_get_max_eventbufpost(struct dhd_bus *bus);
#ifdef DHD_FLOW_RING_STATUS_TRACE
extern void dhd_bus_flow_ring_status_isr_trace(dhd_pub_t *dhd);
extern void dhd_bus_flow_ring_status_dpc_trace(dhd_pub_t *dhd);
#endif /* DHD_FLOW_RING_STATUS_TRACE */
#endif /* _dhd_bus_h_ */

View File

@@ -1,16 +1,15 @@
#ifndef _DHD_BUZZZ_H_INCLUDED_
#define _DHD_BUZZZ_H_INCLUDED_
/*
* Broadcom logging system - Empty implementaiton
* Copyright (C) 1999-2017, Broadcom Corporation
*
*/
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -18,10 +17,6 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
@@ -29,9 +24,201 @@
* $Id$
*/
#if defined(DHD_BUZZZ_LOG_ENABLED)
/*
* Broadcom proprietary logging system. Deleted performance counters.
*/
void dhd_buzzz_attach(void);
void dhd_buzzz_detach(void);
void dhd_buzzz_panic(uint32 crash);
void dhd_buzzz_dump(void);
void dhd_buzzz_log_disable(void);
void dhd_buzzz_crash(void);
void dhd_buzzz_log0(uint32 evt_id);
void dhd_buzzz_log1(uint32 evt_id, uint32 arg1);
void dhd_buzzz_log2(uint32 evt_id, uint32 arg1, uintptr arg2);
void dhd_buzzz_fmt_reg(uint32 id, char * fmt);
extern void* dhd_os_create_buzzz_thread(void);
extern void dhd_os_destroy_buzzz_thread(void *thr_hdl);
extern void dhd_os_sched_buzzz_thread(void *thr_hdl);
#undef BUZZZ_EVT
#define BUZZZ_EVT(ID) BUZZZ_EVT__## ID,
#undef BUZZZ_FMT
#define BUZZZ_FMT(ID, format) \
dhd_buzzz_fmt_reg(BUZZZ_EVT__## ID, "\t" format);
typedef enum buzzz_evt_id
{
BUZZZ_EVT__DHD = 100, /* BUZZZ_EVT(DHD) */
BUZZZ_EVT(GENERAL_LOCK)
BUZZZ_EVT(GENERAL_UNLOCK)
BUZZZ_EVT(FLOWRING_LOCK)
BUZZZ_EVT(FLOWRING_UNLOCK)
BUZZZ_EVT(FLOWID_LOCK)
BUZZZ_EVT(FLOWID_UNLOCK)
BUZZZ_EVT(START_XMIT_BGN)
BUZZZ_EVT(START_XMIT_END)
BUZZZ_EVT(PROCESS_CTRL_BGN)
BUZZZ_EVT(PROCESS_CTRL_END)
BUZZZ_EVT(UPDATE_TXFLOWRINGS_BGN)
BUZZZ_EVT(UPDATE_TXFLOWRINGS_END)
BUZZZ_EVT(PROCESS_TXCPL_BGN)
BUZZZ_EVT(PROCESS_TXCPL_END)
BUZZZ_EVT(PROCESS_RXCPL_BGN)
BUZZZ_EVT(PROCESS_RXCPL_END)
BUZZZ_EVT(GET_SRC_ADDR)
BUZZZ_EVT(WRITE_COMPLETE)
BUZZZ_EVT(ALLOC_RING_SPACE)
BUZZZ_EVT(ALLOC_RING_SPACE_RET)
BUZZZ_EVT(ALLOC_RING_SPACE_FAIL)
BUZZZ_EVT(PKTID_MAP_CLEAR)
BUZZZ_EVT(PKTID_NOT_AVAILABLE)
BUZZZ_EVT(PKTID_MAP_RSV)
BUZZZ_EVT(PKTID_MAP_SAVE)
BUZZZ_EVT(PKTID_MAP_ALLOC)
BUZZZ_EVT(PKTID_MAP_FREE)
BUZZZ_EVT(LOCKER_INUSE_ABORT)
BUZZZ_EVT(BUFFER_TYPE_ABORT1)
BUZZZ_EVT(BUFFER_TYPE_ABORT2)
BUZZZ_EVT(UPD_READ_IDX)
BUZZZ_EVT(STORE_RXCPLN_RD)
BUZZZ_EVT(EARLY_UPD_RXCPLN_RD)
BUZZZ_EVT(POST_TXDATA)
BUZZZ_EVT(RETURN_RXBUF)
BUZZZ_EVT(RXBUF_POST)
BUZZZ_EVT(RXBUF_POST_EVENT)
BUZZZ_EVT(RXBUF_POST_IOCTL)
BUZZZ_EVT(RXBUF_POST_CTRL_PKTGET_FAIL)
BUZZZ_EVT(RXBUF_POST_PKTGET_FAIL)
BUZZZ_EVT(RXBUF_POST_PKTID_FAIL)
BUZZZ_EVT(DHD_DUPLICATE_ALLOC)
BUZZZ_EVT(DHD_DUPLICATE_FREE)
BUZZZ_EVT(DHD_TEST_IS_ALLOC)
BUZZZ_EVT(DHD_TEST_IS_FREE)
BUZZZ_EVT(DHD_PROT_IOCT_BGN)
BUZZZ_EVT(DHDMSGBUF_CMPLT_BGN)
BUZZZ_EVT(DHDMSGBUF_CMPLT_END)
BUZZZ_EVT(DHD_PROT_IOCT_END)
BUZZZ_EVT(DHD_FILLUP_IOCT_REQST_BGN)
BUZZZ_EVT(DHD_FILLUP_IOCT_REQST_END)
BUZZZ_EVT(DHD_MSGBUF_RXBUF_POST_IOCTLRESP_BUFS_BGN)
BUZZZ_EVT(DHD_MSGBUF_RXBUF_POST_IOCTLRESP_BUFS_END)
BUZZZ_EVT(DHD_PROT_IOCTCMPLT_PROCESS_ONE)
BUZZZ_EVT(DHD_PROT_IOCTCMPLT_PROCESS_TWO)
BUZZZ_EVT(DHD_PROT_EVENT_PROCESS_BGN)
BUZZZ_EVT(DHD_PROT_EVENT_PROCESS_END)
BUZZZ_EVT(DHD_PROT_D2H_SYNC_LIVELOCK)
BUZZZ_EVT(DHD_IOCTL_BUFPOST)
BUZZZ_EVT(DHD_EVENT_BUFPOST)
BUZZZ_EVT(DHD_PROC_MSG_TYPE)
BUZZZ_EVT(DHD_BUS_RXCTL_ONE)
BUZZZ_EVT(DHD_BUS_RXCTL_TWO)
} buzzz_evt_id_t;
static inline void dhd_buzzz_fmt_init(void)
{
BUZZZ_FMT(DHD, "DHD events")
BUZZZ_FMT(GENERAL_LOCK, "+++LOCK GENERAL flags<0x%08x>")
BUZZZ_FMT(GENERAL_UNLOCK, "---UNLK GENERAL flags<0x%08x>")
BUZZZ_FMT(FLOWRING_LOCK, "+++LOCK FLOWRING flags<0x%08x>")
BUZZZ_FMT(FLOWRING_UNLOCK, "---UNLK FLOWRING flags<0x%08x>")
BUZZZ_FMT(FLOWID_LOCK, "+++LOCK FLOWID flags<0x%08x>")
BUZZZ_FMT(FLOWID_UNLOCK, "---UNLK FLOWID flags<0x%08x>")
BUZZZ_FMT(START_XMIT_BGN, "{ dhd_start_xmit() ifidx<%u> skb<0x%p>")
BUZZZ_FMT(START_XMIT_END, "} dhd_start_xmit()")
BUZZZ_FMT(PROCESS_CTRL_BGN, "{ dhd_prot_process_ctrlbuf()")
BUZZZ_FMT(PROCESS_CTRL_END, "} dhd_prot_process_ctrlbuf()")
BUZZZ_FMT(UPDATE_TXFLOWRINGS_BGN, "{ dhd_update_txflowrings()");
BUZZZ_FMT(UPDATE_TXFLOWRINGS_END, "} dhd_update_txflowrings()");
BUZZZ_FMT(PROCESS_TXCPL_BGN, "{ dhd_prot_process_msgbuf_txcpl()")
BUZZZ_FMT(PROCESS_TXCPL_END, "} dhd_prot_process_msgbuf_txcpl()")
BUZZZ_FMT(PROCESS_RXCPL_BGN, "{ dhd_prot_process_msgbuf_rxcpl()")
BUZZZ_FMT(PROCESS_RXCPL_END, "} dhd_prot_process_msgbuf_rxcpl()")
BUZZZ_FMT(GET_SRC_ADDR, "bytes<%u> @<0x%p> prot_get_src_addr()")
BUZZZ_FMT(WRITE_COMPLETE, "WR<%u> prot_ring_write_complete")
BUZZZ_FMT(ALLOC_RING_SPACE, "{ dhd_alloc_ring_space nitems<%d>")
BUZZZ_FMT(ALLOC_RING_SPACE_RET, "} dhd_alloc_ring_space() alloc<%d> @<0x%p>")
BUZZZ_FMT(ALLOC_RING_SPACE_FAIL, "FAILURE } dhd_alloc_ring_space() alloc<%d>")
BUZZZ_FMT(PKTID_MAP_CLEAR, "pktid map clear")
BUZZZ_FMT(PKTID_NOT_AVAILABLE, "FAILURE pktid pool depletion failures<%u>")
BUZZZ_FMT(PKTID_MAP_RSV, "pktid<%u> pkt<0x%p> dhd_pktid_map_reserve()")
BUZZZ_FMT(PKTID_MAP_SAVE, "pktid<%u> pkt<0x%p> dhd_pktid_map_save()")
BUZZZ_FMT(PKTID_MAP_ALLOC, "pktid<%u> pkt<0x%p> dhd_pktid_map_alloc()")
BUZZZ_FMT(PKTID_MAP_FREE, "pktid<%u> pkt<0x%p> dhd_pktid_map_free()")
BUZZZ_FMT(LOCKER_INUSE_ABORT, "ASSERT pktid<%u> pkt<0x%p> locker->inuse")
BUZZZ_FMT(BUFFER_TYPE_ABORT1, "ASSERT pktid<%u> pkt<0x%p> locker->dma")
BUZZZ_FMT(BUFFER_TYPE_ABORT2, "ASSERT locker->dma<%u> buf_type<%u>")
BUZZZ_FMT(UPD_READ_IDX, "RD<%u> prot_upd_read_idx()")
BUZZZ_FMT(STORE_RXCPLN_RD, "RD<%u> prot_store_rxcpln_read_idx()")
BUZZZ_FMT(EARLY_UPD_RXCPLN_RD, "RD<%u> prot_early_upd_rxcpln_read_idx()")
BUZZZ_FMT(POST_TXDATA, "flr<%u> pkt<0x%p> dhd_prot_txdata()")
BUZZZ_FMT(RETURN_RXBUF, "cnt<%u> dhd_prot_return_rxbuf()");
BUZZZ_FMT(RXBUF_POST, "cnt<%u> dhd_prot_rxbufpost()");
BUZZZ_FMT(RXBUF_POST_EVENT, "event dhd_prot_rxbufpost_ctrl()");
BUZZZ_FMT(RXBUF_POST_IOCTL, "ioctl dhd_prot_rxbufpost_ctrl()");
BUZZZ_FMT(RXBUF_POST_CTRL_PKTGET_FAIL, "FAILURE pktget dhd_prot_rxbufpost_ctrl()");
BUZZZ_FMT(RXBUF_POST_PKTGET_FAIL, "FAILURE pktget loop<%u> dhd_prot_rxbufpost()")
BUZZZ_FMT(RXBUF_POST_PKTID_FAIL, "FAILURE pktid loop<%u> dhd_prot_rxbufpost()")
BUZZZ_FMT(DHD_DUPLICATE_ALLOC, "ASSERT dhd_pktid_audit(%u) DHD_DUPLICATE_ALLOC")
BUZZZ_FMT(DHD_DUPLICATE_FREE, "ASSERT dhd_pktid_audit(%u) DHD_DUPLICATE_FREE")
BUZZZ_FMT(DHD_TEST_IS_ALLOC, "ASSERT dhd_pktid_audit(%u) DHD_TEST_IS_ALLOC")
BUZZZ_FMT(DHD_TEST_IS_FREE, "ASSERT dhd_pktid_audit(%u) DHD_TEST_IS_FREE")
BUZZZ_FMT(DHD_PROT_IOCT_BGN, "{ dhd_prot_ioct pending<%u> thread<0x%p>")
BUZZZ_FMT(DHDMSGBUF_CMPLT_BGN, "{ dhdmsgbuf_cmplt bus::retlen<%u> bus::pktid<%u>")
BUZZZ_FMT(DHDMSGBUF_CMPLT_END, "} dhdmsgbuf_cmplt resp_len<%d> pktid<%u>")
BUZZZ_FMT(DHD_PROT_IOCT_END, "} dhd_prot_ioct pending<%u> thread<0x%p>")
BUZZZ_FMT(DHD_FILLUP_IOCT_REQST_BGN, "{ dhd_fillup_ioct_reqst_ptrbased cmd<%u> transid<%u>")
BUZZZ_FMT(DHD_FILLUP_IOCT_REQST_END,
"} dhd_fillup_ioct_reqst_ptrbased transid<%u> bus::pktid<%u>")
BUZZZ_FMT(DHD_MSGBUF_RXBUF_POST_IOCTLRESP_BUFS_BGN,
"{ dhd_msgbuf_rxbuf_post_ioctlresp_bufs cur_posted<%u> bus::pktid<%u>")
BUZZZ_FMT(DHD_MSGBUF_RXBUF_POST_IOCTLRESP_BUFS_END,
"} dhd_msgbuf_rxbuf_post_ioctlresp_bufs cur_posted<%u> bus::pktid<%u>")
BUZZZ_FMT(DHD_PROT_IOCTCMPLT_PROCESS_ONE,
"{ dhd_prot_ioctlcmplt_process cmd<%d> transid<%d>")
BUZZZ_FMT(DHD_PROT_IOCTCMPLT_PROCESS_TWO,
"} dhd_prot_ioctlcmplt_process resplen<%u> pktid<%u>")
BUZZZ_FMT(DHD_PROT_EVENT_PROCESS_BGN, "{ dhd_prot_event_process pktid<%u>")
BUZZZ_FMT(DHD_PROT_EVENT_PROCESS_END, "} dhd_prot_event_process buflen<%u> pkt<0x%p>")
BUZZZ_FMT(DHD_PROT_D2H_SYNC_LIVELOCK, " dhd_prot_d2h_sync_livelock seqnum<%u>")
BUZZZ_FMT(DHD_IOCTL_BUFPOST, " dhd_prot_rxbufpost_ctrl ioctl pktid<%u> phyaddr<0x%x>")
BUZZZ_FMT(DHD_EVENT_BUFPOST, " dhd_prot_rxbufpost_ctrl event pktid<%u> phyaddr<0x%x>")
BUZZZ_FMT(DHD_PROC_MSG_TYPE, " dhd_process_msgtype msg<0x%x> epoch<%u>")
BUZZZ_FMT(DHD_BUS_RXCTL_ONE, "dhd_bus_rxctl prev resplen<%u> pktid<%u>")
BUZZZ_FMT(DHD_BUS_RXCTL_TWO, "dhd_bus_rxctl cur resplen<%u> pktid<%u>")
}
#define BUZZZ_LOG(ID, N, ARG...) dhd_buzzz_log ##N(BUZZZ_EVT__ ##ID, ##ARG)
#else /* DHD_BUZZZ_LOG_ENABLED */
/*
* Broadcom logging system - Empty implementaiton
*/
#define dhd_buzzz_attach() do { /* noop */ } while (0)
#define dhd_buzzz_detach() do { /* noop */ } while (0)
#define dhd_buzzz_panic(x) do { /* noop */ } while (0)
#define BUZZZ_LOG(ID, N, ARG...) do { /* noop */ } while (0)
#endif /* DHD_BUZZZ_LOG_ENABLED */
#endif /* _DHD_BUZZZ_H_INCLUDED_ */

View File

@@ -10,7 +10,6 @@
#define CCODE_43438
#define CCODE_43436
#define CCODE_43455C0
#define CCODE_43456C5
#endif
#if defined(BCMSDIO) || defined(BCMPCIE)
#define CCODE_4356A2
@@ -67,7 +66,7 @@ const char ccode_43455c0[] = \
"GB/6 GD/2 GF/2 GP/2 GR/4 GT/1 GU/30 "\
"HK/2 HR/4 HU/4 "\
"ID/1 IE/5 IL/14 IN/3 IS/4 IT/4 "\
"JO/3 JP/58 "\
"JO/3 JP/45 "\
"KH/2 KR/96 KW/5 KY/3 "\
"LA/2 LB/5 LI/4 LK/1 LS/2 LT/4 LU/3 LV/4 "\
"MA/2 MC/1 MD/2 ME/2 MK/2 MN/1 MQ/2 MR/2 MT/4 MU/2 MV/3 MW/1 MX/44 MY/3 "\
@@ -86,37 +85,6 @@ const char ccode_43455c0[] = \
#else
const char ccode_43455c0[] = "";
#endif
#ifdef CCODE_43456C5
const char ccode_43456c5[] = \
"AE/6 AG/2 AI/1 AL/2 AS/12 AT/4 AU/6 AW/2 AZ/2 "\
"BA/2 BD/1 BE/4 BG/4 BH/4 BM/12 BN/4 BR/4 BS/2 BY/3 "\
"CA/2 CH/4 CN/38 CO/17 CR/17 CY/4 CZ/4 "\
"DE/7 DK/4 "\
"EC/21 EE/4 EG/13 ES/4 ET/2 "\
"FI/4 FR/5 "\
"GB/6 GD/2 GF/2 GP/2 GR/4 GT/1 GU/30 "\
"HK/2 HR/4 HU/4 "\
"ID/1 IE/5 IL/14 IN/3 IS/4 IT/4 "\
"JO/3 JP/58 "\
"KH/2 KR/96 KW/5 KY/3 "\
"LA/2 LB/5 LI/4 LK/1 LS/2 LT/4 LU/3 LV/4 "\
"MA/2 MC/1 MD/2 ME/2 MK/2 MN/1 MQ/2 MR/2 MT/4 MU/2 MV/3 MW/1 MX/44 MY/3 "\
"NI/2 NL/4 NO/4 NZ/4 "\
"OM/4 "\
"PA/17 PE/20 PH/5 PL/4 PR/38 PT/4 PY/2 "\
"Q2/993 "\
"RE/2 RO/4 RS/2 RU/13 "\
"SE/4 SI/4 SK/4 SV/25 "\
"TH/5 TN/1 TR/7 TT/3 TW/65 "\
"UA/8 US/988 "\
"VA/2 VE/3 VG/2 VN/4 "\
"XZ/11 "\
"YT/2 "\
"ZA/6";
#else
const char ccode_43456c5[] = "";
#endif
#endif
#ifdef CCODE_4356A2
@@ -130,7 +98,7 @@ const char ccode_4356a2[] = \
"GB/6 GD/2 GF/2 GP/2 GR/4 GT/1 GU/12 "\
"HK/2 HR/4 HU/4 "\
"ID/13 IE/5 IL/7 IN/28 IS/4 IT/4 "\
"JO/3 JP/58 "\
"JO/3 JP/45 "\
"KH/2 KR/57 KW/5 KY/3 "\
"LA/2 LB/5 LI/4 LK/1 LS/2 LT/4 LU/3 LV/4 "\
"MA/2 MC/1 MD/2 ME/2 MK/2 MN/1 MO/2 MR/2 MT/4 MQ/2 MU/2 MV/3 MW/1 MX/20 MY/16 "\
@@ -183,26 +151,27 @@ const char ccode_4359c0[] = "";
#ifdef CCODE_4375B4
const char ccode_4375b4[] = \
"AE/6 AL/2 AM/1 AN/5 AR/21 AT/4 AU/6 AZ/2"\
"BA/2 BE/4 BG/4 BH/4 BN/4 BO/5 BR/17 BY/3"\
"CA/2 CH/4 CL/7 CN/38 CO/17 CR/17 CY/4 CZ/4"\
"DE/7 DK/4 DZ/2 EC/18 EE/4 EG/13 ES/4"\
"FI/4 FR/5"\
"GB/6 GR/4"\
"HK/999 HN/8 HR/4 HU/4"\
"ID/5 IE/5 IL/7 IN/3 IS/4 IT/4"\
"JO/3 JP/72"\
"KE/1 KR/96 KW/5 KZ/5"\
"LA/2 LB/5 LI/4 LK/2 LT/4 LU/4 LV/4"\
"MA/7 MC/1 ME/2 MK/2 MO/4 MT/4 MX/20 MY/19"\
"NL/4 NO/4 NZ/4"\
"OM/4"\
"PA/17 PE/20 PH/5 PK/2 PL/4 PR/20 PT/4"\
"RO/4 RU/62"\
"SA/5 SE/4 SG/12 SI/4 SK/4 SV/17"\
"TH/5 TN/1 TR/7 TT/3 TW/65"\
"UA/16 US/140 UY/10"\
"VE/3 VN/4"\
"AE/6 AL/2 AM/1 AN/5 AR/21 AT/4 AU/6 AZ/2 "\
"BA/2 BE/4 BG/4 BH/4 BN/4 BO/5 BR/17 BY/3 "\
"CA/2 CH/4 CL/7 CN/38 CO/17 CR/17 CY/4 CZ/4 "\
"DE/7 DK/4 DZ/2 EC/18 EE/4 EG/13 ES/4 "\
"FI/4 FR/5 "\
"GB/6 GR/4 "\
"HK/999 HN/8 HR/4 HU/4 "\
"ID/5 IE/5 IL/7 IN/3 IS/4 IT/4 "\
"JO/3 JP/72 "\
"KE/1 KR/96 KW/5 KZ/5 "\
"LA/2 LB/5 LI/4 LK/2 LT/4 LU/4 LV/4 "\
"MA/7 MC/1 ME/2 MK/2 MO/4 MT/4 MX/20 MY/19 "\
"NL/4 NO/4 NZ/4 "\
"OM/4 "\
"PA/17 PE/20 PH/5 PK/2 PL/4 PR/20 PT/4 "\
"RO/4 RU/62 "\
"SA/5 SE/4 SG/12 SI/4 SK/4 SV/17 "\
"TH/5 TN/1 TR/7 TT/3 TW/65 "\
"UA/16 US/140 UY/10 "\
"VE/3 VN/4 "\
"XZ/11 "\
"ZA/19";
#else
const char ccode_4375b4[] = "";
@@ -240,7 +209,6 @@ typedef struct ccode_list_map_t {
extern const char ccode_43438[];
extern const char ccode_43455c0[];
extern const char ccode_43456c5[];
extern const char ccode_4356a2[];
extern const char ccode_4359c0[];
extern const char ccode_4358u[];
@@ -248,23 +216,23 @@ extern const char ccode_4358u[];
const ccode_list_map_t ccode_list_map[] = {
/* ChipID Chiprev ccode */
#ifdef BCMSDIO
{BCM43430_CHIP_ID, 0, ccode_43438, ""},
{BCM43430_CHIP_ID, 1, ccode_43438, ""},
{BCM43430_CHIP_ID, 2, ccode_43436, ""},
{BCM4345_CHIP_ID, 6, ccode_43455c0, "XZ/11"},
{BCM43454_CHIP_ID, 6, ccode_43455c0, "XZ/11"},
{BCM4345_CHIP_ID, 9, ccode_43456c5, "XZ/11"},
{BCM43454_CHIP_ID, 9, ccode_43456c5, "XZ/11"},
{BCM4354_CHIP_ID, 2, ccode_4356a2, "XZ/11"},
{BCM4356_CHIP_ID, 2, ccode_4356a2, "XZ/11"},
{BCM4371_CHIP_ID, 2, ccode_4356a2, "XZ/11"},
{BCM4359_CHIP_ID, 9, ccode_4359c0, "XZ/11"},
{BCM43430_CHIP_ID, 0, ccode_43438, ""},
{BCM43430_CHIP_ID, 1, ccode_43438, ""},
{BCM43430_CHIP_ID, 2, ccode_43436, ""},
{BCM4345_CHIP_ID, 6, ccode_43455c0, "XZ/11"},
{BCM43454_CHIP_ID, 6, ccode_43455c0, "XZ/11"},
{BCM4345_CHIP_ID, 9, ccode_43455c0, "XZ/11"},
{BCM43454_CHIP_ID, 9, ccode_43455c0, "XZ/11"},
{BCM4354_CHIP_ID, 2, ccode_4356a2, "XZ/11"},
{BCM4356_CHIP_ID, 2, ccode_4356a2, "XZ/11"},
{BCM4371_CHIP_ID, 2, ccode_4356a2, "XZ/11"},
{BCM4359_CHIP_ID, 9, ccode_4359c0, "XZ/11"},
#endif
#ifdef BCMPCIE
{BCM4354_CHIP_ID, 2, ccode_4356a2, "XZ/11"},
{BCM4356_CHIP_ID, 2, ccode_4356a2, "XZ/11"},
{BCM4359_CHIP_ID, 9, ccode_4359c0, "XZ/11"},
{BCM4375_CHIP_ID, 5, ccode_4375b4, "XZ/11"},
{BCM4354_CHIP_ID, 2, ccode_4356a2, "XZ/11"},
{BCM4356_CHIP_ID, 2, ccode_4356a2, "XZ/11"},
{BCM4359_CHIP_ID, 9, ccode_4359c0, "XZ/11"},
{BCM4375_CHIP_ID, 5, ccode_4375b4, "XZ/11"},
#endif
#ifdef BCMDBUS
{BCM43569_CHIP_ID, 2, ccode_4358u, "XW/0"},

View File

@@ -1,14 +1,14 @@
/*
* DHD Protocol Module for CDC and BDC.
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,15 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_cdc.c 699163 2017-05-12 05:18:23Z $
* $Id$
*
* BDC is like CDC, except it includes a header for data packets to convey
* packet priority over the bus, and flags (e.g. to indicate checksum status
@@ -44,6 +40,11 @@
#include <dhd_bus.h>
#include <dhd_dbg.h>
#ifdef EXT_STA
#include <siutils.h>
#include <wlc_cfg.h>
#include <wlc_pub.h>
#endif /* EXT_STA */
#ifdef PROP_TXSTATUS
#include <wlfc_proto.h>
@@ -53,11 +54,6 @@
#include <dhd_config.h>
#endif /* BCMDBUS */
#ifdef DHD_ULP
#include <dhd_ulp.h>
#endif /* DHD_ULP */
#define RETRIES 2 /* # of retries to retrieve matching ioctl response */
#define BUS_HEADER_LEN (24+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE
* defined in dhd_sdio.c (amount of header tha might be added)
@@ -67,6 +63,10 @@
* round off at the end of buffer
*/
/* This value is from Legacy chipsets */
#define DEFAULT_WLC_API_VERSION_MAJOR 3
#define DEFAULT_WLC_API_VERSION_MINOR 0
typedef struct dhd_prot {
uint16 reqid;
uint8 pending;
@@ -79,6 +79,13 @@ typedef struct dhd_prot {
unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN];
} dhd_prot_t;
uint16
dhd_prot_get_ioctl_trans_id(dhd_pub_t *dhdp)
{
/* SDIO does not have ioctl_trans_id yet, so return -1 */
return -1;
}
static int
dhdcdc_msg(dhd_pub_t *dhd)
{
@@ -102,12 +109,10 @@ dhdcdc_msg(dhd_pub_t *dhd)
/* Send request */
#ifdef BCMDBUS
DHD_OS_IOCTL_RESP_LOCK(dhd);
prot->ctl_completed = FALSE;
err = dbus_send_ctl(dhd->bus, (void *)&prot->msg, len);
if (err) {
DHD_ERROR(("dbus_send_ctl error=%d\n", err));
DHD_OS_IOCTL_RESP_UNLOCK(dhd);
DHD_ERROR(("dbus_send_ctl error=0x%x\n", err));
DHD_OS_WAKE_UNLOCK(dhd);
return err;
}
@@ -123,14 +128,12 @@ dhdcdc_msg(dhd_pub_t *dhd)
DHD_ERROR(("Txctl wait timed out\n"));
err = -1;
}
DHD_OS_IOCTL_RESP_UNLOCK(dhd);
#endif /* BCMDBUS */
#if defined(BCMDBUS) && defined(INTR_EP_ENABLE)
/* If the ctl write is successfully completed, wait for an acknowledgement
* that indicates that it is now ok to do ctl read from the dongle
*/
if (err != -1) {
DHD_OS_IOCTL_RESP_LOCK(dhd);
prot->ctl_completed = FALSE;
if (dbus_poll_intr(dhd->dbus)) {
DHD_ERROR(("dbus_poll_intr not submitted\n"));
@@ -143,7 +146,6 @@ dhdcdc_msg(dhd_pub_t *dhd)
DHD_ERROR(("intr poll wait timed out\n"));
}
}
DHD_OS_IOCTL_RESP_UNLOCK(dhd);
}
#endif /* defined(BCMDBUS) && defined(INTR_EP_ENABLE) */
DHD_OS_WAKE_UNLOCK(dhd);
@@ -164,12 +166,10 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
do {
#ifdef BCMDBUS
DHD_OS_IOCTL_RESP_LOCK(dhd);
prot->ctl_completed = FALSE;
ret = dbus_recv_ctl(dhd->bus, (uchar*)&prot->msg, cdc_len);
if (ret) {
DHD_ERROR(("dbus_recv_ctl error=0x%x(%d)\n", ret, ret));
DHD_OS_IOCTL_RESP_UNLOCK(dhd);
goto done;
}
timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed);
@@ -177,12 +177,14 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
DHD_ERROR(("Rxctl timeout %d ctl_completed %d\n",
timeout, prot->ctl_completed));
ret = -1;
DHD_OS_IOCTL_RESP_UNLOCK(dhd);
goto done;
}
DHD_OS_IOCTL_RESP_UNLOCK(dhd);
/* XXX FIX: Must return cdc_len, not len, because after query_ioctl()
* it subtracts sizeof(cdc_ioctl_t); The other approach is
* to have dbus_recv_ctl() return actual len.
*/
ret = cdc_len;
#else
ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len);
@@ -191,12 +193,18 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
break;
} while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id);
/* update ret to len on success */
if (ret == cdc_len) {
ret = len;
}
#ifdef BCMDBUS
done:
#endif /* BCMDBUS */
return ret;
}
/* XXX: due to overlays this should not be called directly; call dhd_wl_ioctl_cmd() instead */
static int
dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action)
{
@@ -208,13 +216,12 @@ dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uin
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
/* Respond "bcmerror" and "bcmerrorstr" with local cache */
if (cmd == WLC_GET_VAR && buf)
{
if (!strcmp((char *)buf, "bcmerrorstr"))
{
strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN);
strlcpy((char *)buf, bcmerrorstr(dhd->dongle_error), len);
goto done;
}
else if (!strcmp((char *)buf, "bcmerror"))
@@ -226,6 +233,16 @@ dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uin
memset(msg, 0, sizeof(cdc_ioctl_t));
#ifdef BCMSPI
/* 11bit gSPI bus allows 2048bytes of max-data. We restrict 'len'
* value which is 8Kbytes for various 'get' commands to 2000. 48 bytes are
* left for sw headers and misc.
*/
if (len > 2000) {
DHD_ERROR(("dhdcdc_query_ioctl: len is truncated to 2000 bytes\n"));
len = 2000;
}
#endif /* BCMSPI */
msg->cmd = htol32(cmd);
msg->len = htol32(len);
msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT);
@@ -281,7 +298,11 @@ done:
return ret;
}
#ifdef DHD_PM_CONTROL_FROM_FILE
extern bool g_pm_control;
#endif /* DHD_PM_CONTROL_FROM_FILE */
/* XXX: due to overlays this should not be called directly; call dhd_wl_ioctl_cmd() instead */
static int
dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action)
{
@@ -306,6 +327,30 @@ dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8
}
if (cmd == WLC_SET_PM) {
#ifdef DHD_PM_CONTROL_FROM_FILE
if (g_pm_control == TRUE) {
DHD_ERROR(("%s: SET PM ignored!(Requested:%d)\n",
__FUNCTION__, buf ? *(char *)buf : 0));
goto done;
}
#endif /* DHD_PM_CONTROL_FROM_FILE */
#ifdef DHD_PM_OVERRIDE
{
extern bool g_pm_override;
if (g_pm_override == TRUE) {
DHD_ERROR(("%s: PM override SET PM ignored!(Requested:%d)\n",
__FUNCTION__, buf ? *(char *)buf : 0));
goto done;
}
}
#endif /* DHD_PM_OVERRIDE */
#if defined(WLAIBSS)
if (dhd->op_mode == DHD_FLAG_IBSS_MODE) {
DHD_ERROR(("%s: SET PM ignored for IBSS!(Requested:%d)\n",
__FUNCTION__, buf ? *(char *)buf : 0));
goto done;
}
#endif /* WLAIBSS */
DHD_TRACE_HW4(("%s: SET PM to %d\n", __FUNCTION__, buf ? *(char *)buf : 0));
}
@@ -323,13 +368,6 @@ dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8
if (buf)
memcpy(prot->buf, buf, len);
#ifdef DHD_ULP
if (buf && (!strncmp(buf, "ulp", sizeof("ulp")))) {
/* force all the writes after this point to NOT to use cached sbwad value */
dhd_ulp_disable_cached_sbwad(dhd);
}
#endif /* DHD_ULP */
if ((ret = dhdcdc_msg(dhd)) < 0) {
DHD_ERROR(("%s: dhdcdc_msg failed w/status %d\n", __FUNCTION__, ret));
goto done;
@@ -348,11 +386,11 @@ dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8
goto done;
}
#ifdef DHD_ULP
/* For ulp prototyping temporary */
if ((ret = dhd_ulp_check_ulp_request(dhd, buf)) < 0)
goto done;
#endif /* DHD_ULP */
/* Copy fw response to buf */
if (buf) {
ASSERT(ret == len);
memcpy(buf, (void*) prot->buf, len);
}
/* Check the ERROR flag */
if (flags & CDCF_IOC_ERROR)
@@ -378,14 +416,13 @@ dhd_prot_ctl_complete(dhd_pub_t *dhd)
prot = dhd->prot;
ASSERT(prot);
DHD_OS_IOCTL_RESP_LOCK(dhd);
prot->ctl_completed = TRUE;
dhd_os_ioctl_resp_wake(dhd);
DHD_OS_IOCTL_RESP_UNLOCK(dhd);
return 0;
}
#endif /* BCMDBUS */
/* XXX: due to overlays this should not be called directly; call dhd_wl_ioctl() instead */
int
dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len)
{
@@ -504,6 +541,11 @@ dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *PKTBUF)
if (PKTSUMNEEDED(PKTBUF))
h->flags |= BDC_FLAG_SUM_NEEDED;
#ifdef EXT_STA
/* save pkt encryption exemption info for dongle */
h->flags &= ~BDC_FLAG_EXEMPT;
h->flags |= (WLPKTFLAG_EXEMPT_GET(WLPKTTAG(pktbuf)) & BDC_FLAG_EXEMPT);
#endif /* EXT_STA */
h->priority = (PKTPRIO(PKTBUF) & BDC_PRIORITY_MASK);
h->flags2 = 0;
@@ -577,7 +619,6 @@ dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_in
PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN);
#endif /* BDC */
#ifdef PROP_TXSTATUS
if (!DHD_PKTTAG_PKTDIR(PKTTAG(pktbuf))) {
/*
@@ -600,7 +641,6 @@ exit:
return 0;
}
int
dhd_prot_attach(dhd_pub_t *dhd)
{
@@ -661,8 +701,18 @@ dhd_sync_with_dongle(dhd_pub_t *dhd)
{
int ret = 0;
wlc_rev_info_t revinfo;
char buf[128];
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
#ifndef OEM_ANDROID
/* Get the device MAC address */
strcpy(buf, "cur_etheraddr");
ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0);
if (ret < 0)
goto done;
memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
#endif /* OEM_ANDROID */
#ifdef DHD_FW_COREDUMP
/* Check the memdump capability */
dhd_get_memdump_info(dhd);
@@ -686,6 +736,30 @@ dhd_sync_with_dongle(dhd_pub_t *dhd)
}
#endif /* BCMDBUS */
/* query for 'wlc_ver' to get version info from firmware */
/* memsetting to zero */
bzero(buf, sizeof(buf));
ret = bcm_mkiovar("wlc_ver", NULL, 0, buf, sizeof(buf));
if (ret == 0) {
ret = BCME_BUFTOOSHORT;
goto done;
}
ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0);
if (ret == BCME_UNSUPPORTED) {
dhd->wlc_ver_major = DEFAULT_WLC_API_VERSION_MAJOR;
dhd->wlc_ver_minor = DEFAULT_WLC_API_VERSION_MINOR;
} else if (ret < 0) {
DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
goto done;
} else {
dhd->wlc_ver_major = ((wl_wlc_version_t*)buf)->wlc_ver_major;
dhd->wlc_ver_minor = ((wl_wlc_version_t*)buf)->wlc_ver_minor;
}
DHD_ERROR(("wlc_ver_major %d, wlc_ver_minor %d\n", dhd->wlc_ver_major, dhd->wlc_ver_minor));
#if defined(BCMDBUS) && defined(BCMDHDUSB)
/* dbus_set_revinfo(dhd->dbus, revinfo.chipnum, revinfo.chiprev); */
#endif /* BCMDBUS && BCMDHDUSB */
DHD_SSSR_DUMP_INIT(dhd);
@@ -696,6 +770,7 @@ dhd_sync_with_dongle(dhd_pub_t *dhd)
/* Always assumes wl for now */
dhd->iswl = TRUE;
/* XXX Could use WLC_GET_REVINFO to get driver version? */
done:
return ret;
}
@@ -711,7 +786,6 @@ dhd_prot_stop(dhd_pub_t *dhd)
/* Nothing to do for CDC */
}
static void
dhd_get_hostreorder_pkts(void *osh, struct reorder_info *ptr, void **pkt,
uint32 *pkt_count, void **pplast, uint8 start, uint8 end)
@@ -839,6 +913,7 @@ dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reord
ptr->p = (void *)(ptr+1);
ptr->max_idx = max_idx;
}
/* XXX: validate cur, exp indices */
if (flags & WLHOST_REORDERDATA_NEW_HOLE) {
DHD_REORDER(("%s: new hole, so cleanup pending buffers\n", __FUNCTION__));
if (ptr->pend_pkts) {
@@ -857,7 +932,6 @@ dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reord
cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET];
exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET];
if ((exp_idx == ptr->exp_idx) && (cur_idx != ptr->exp_idx)) {
/* still in the current hole */
/* enqueue the current on the buffer chain */

View File

@@ -1,14 +1,14 @@
/*
* Linux cfg80211 driver - Dongle Host Driver (DHD) related
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,15 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_cfg80211.c 699163 2017-05-12 05:18:23Z $
* $Id$
*/
#include <linux/vmalloc.h>
@@ -47,16 +43,31 @@ extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable,
#endif
static int dhd_dongle_up = FALSE;
#define PKT_FILTER_BUF_SIZE 64
#if defined(BCMDONGLEHOST)
#include <dngl_stats.h>
#include <dhd.h>
#include <dhdioctl.h>
#include <wlioctl.h>
#include <brcm_nl80211.h>
#include <dhd_cfg80211.h>
#endif /* defined(BCMDONGLEHOST) */
static s32 wl_dongle_up(struct net_device *ndev);
static s32 wl_dongle_down(struct net_device *ndev);
#ifndef OEM_ANDROID
#ifndef CUSTOMER_HW6
static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode);
#ifdef BCMSDIO /* glomming is a sdio specific feature */
static s32 wl_dongle_glom(struct net_device *ndev, s32 glom, u32 dongle_align);
#endif
static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, s32 scan_unassoc_time);
static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol);
static s32 wl_pattern_atoh(s8 *src, s8 *dst);
static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode);
#endif /* !CUSTOMER_HW6 */
#endif /* !OEM_ANDROID */
/**
* Function implementations
@@ -81,14 +92,14 @@ s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg)
WL_TRACE(("In\n"));
if (!dhd_dongle_up) {
WL_ERR(("Dongle is already down\n"));
return err;
WL_INFORM_MEM(("Dongle is already down\n"));
err = 0;
goto done;
}
ndev = bcmcfg_to_prmry_ndev(cfg);
wl_dongle_down(ndev);
dhd_dongle_up = FALSE;
return 0;
done:
return err;
}
s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val)
@@ -96,13 +107,6 @@ s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val)
dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
dhd->op_mode |= val;
WL_ERR(("Set : op_mode=0x%04x\n", dhd->op_mode));
#ifdef ARP_OFFLOAD_SUPPORT
if (dhd->arp_version == 1) {
/* IF P2P is enabled, disable arpoe */
dhd_arp_offload_set(dhd, 0);
dhd_arp_offload_enable(dhd, false);
}
#endif /* ARP_OFFLOAD_SUPPORT */
return 0;
}
@@ -113,17 +117,16 @@ s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg)
dhd->op_mode &= ~(DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE);
WL_ERR(("Clean : op_mode=0x%04x\n", dhd->op_mode));
#ifdef ARP_OFFLOAD_SUPPORT
if (dhd->arp_version == 1) {
/* IF P2P is disabled, enable arpoe back for STA mode. */
dhd_arp_offload_set(dhd, dhd_arp_mode);
dhd_arp_offload_enable(dhd, true);
}
#endif /* ARP_OFFLOAD_SUPPORT */
return 0;
}
#ifdef WL_STATIC_IF
int32
wl_cfg80211_update_iflist_info(struct bcm_cfg80211 *cfg, struct net_device *ndev,
int ifidx, uint8 *addr, int bssidx, char *name, int if_state)
{
return dhd_update_iflist_info(cfg->pub, ndev, ifidx, addr, bssidx, name, if_state);
}
#endif /* WL_STATIC_IF */
struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, const char *name,
uint8 *mac, uint8 bssidx, const char *dngl_name)
{
@@ -139,14 +142,31 @@ int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg,
int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg,
int ifidx, struct net_device* ndev, bool rtnl_lock_reqd)
{
#ifdef DHD_PCIE_RUNTIMEPM
dhdpcie_runtime_bus_wake(cfg->pub, CAN_SLEEP(), __builtin_return_address(0));
#endif /* DHD_PCIE_RUNTIMEPM */
return dhd_remove_if(cfg->pub, ifidx, rtnl_lock_reqd);
}
void wl_cfg80211_cleanup_if(struct net_device *net)
{
struct bcm_cfg80211 *cfg = wl_get_cfg(net);
#ifdef DHD_PCIE_RUNTIMEPM
dhdpcie_runtime_bus_wake(cfg->pub, CAN_SLEEP(), __builtin_return_address(0));
#else
BCM_REFERENCE(cfg);
#endif /* DHD_PCIE_RUNTIMEPM */
dhd_cleanup_if(net);
}
struct net_device * dhd_cfg80211_netdev_free(struct net_device *ndev)
{
struct bcm_cfg80211 *cfg;
if (ndev) {
cfg = wl_get_cfg(ndev);
if (ndev->ieee80211_ptr) {
kfree(ndev->ieee80211_ptr);
MFREE(cfg->osh, ndev->ieee80211_ptr, sizeof(struct wireless_dev));
ndev->ieee80211_ptr = NULL;
}
free_netdev(ndev);
@@ -170,10 +190,19 @@ wl_dongle_up(struct net_device *ndev)
{
s32 err = 0;
u32 local_up = 0;
#ifdef WLAN_ACCEL_BOOT
u32 bus_host_access = 1;
err = wldev_iovar_setint(ndev, "bus:host_access", bus_host_access);
if (unlikely(err)) {
WL_ERR(("bus:host_access(%d) error (%d)\n", bus_host_access, err));
}
#endif /* WLAN_ACCEL_BOOT */
err = wldev_ioctl_set(ndev, WLC_UP, &local_up, sizeof(local_up));
if (unlikely(err)) {
WL_ERR(("WLC_UP error (%d)\n", err));
} else {
WL_INFORM_MEM(("wl up\n"));
dhd_dongle_up = TRUE;
}
return err;
}
@@ -183,14 +212,290 @@ wl_dongle_down(struct net_device *ndev)
{
s32 err = 0;
u32 local_down = 0;
#ifdef WLAN_ACCEL_BOOT
u32 bus_host_access = 0;
#endif /* WLAN_ACCEL_BOOT */
err = wldev_ioctl_set(ndev, WLC_DOWN, &local_down, sizeof(local_down));
if (unlikely(err)) {
WL_ERR(("WLC_DOWN error (%d)\n", err));
}
#ifdef WLAN_ACCEL_BOOT
err = wldev_iovar_setint(ndev, "bus:host_access", bus_host_access);
if (unlikely(err)) {
WL_ERR(("bus:host_access(%d) error (%d)\n", bus_host_access, err));
}
#endif /* WLAN_ACCEL_BOOT */
WL_INFORM_MEM(("wl down\n"));
dhd_dongle_up = FALSE;
return err;
}
#ifndef OEM_ANDROID
#ifndef CUSTOMER_HW6
static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode)
{
s32 err = 0;
WL_TRACE(("In\n"));
err = wldev_ioctl_set(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode));
if (unlikely(err)) {
WL_ERR(("WLC_SET_PM error (%d)\n", err));
}
return err;
}
#ifdef BCMSDIO
static s32
wl_dongle_glom(struct net_device *ndev, s32 glom, u32 dongle_align)
{
s32 err = 0;
/* Match Host and Dongle rx alignment */
err = wldev_iovar_setint(ndev, "bus:txglomalign", dongle_align);
if (unlikely(err)) {
WL_ERR(("txglomalign error (%d)\n", err));
goto dongle_glom_out;
}
/* disable glom option per default */
if (glom != DEFAULT_GLOM_VALUE) {
err = wldev_iovar_setint(ndev, "bus:txglom", glom);
if (unlikely(err)) {
WL_ERR(("txglom error (%d)\n", err));
goto dongle_glom_out;
}
}
dongle_glom_out:
return err;
}
#endif /* BCMSDIO */
#endif /* !CUSTOMER_HW6 */
#endif /* !OEM_ANDROID */
s32
wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
{
s32 err = 0;
/* Setup timeout if Beacons are lost and roam is off to report link down */
if (roamvar) {
err = wldev_iovar_setint(ndev, "bcn_timeout", bcn_timeout);
if (unlikely(err)) {
WL_ERR(("bcn_timeout error (%d)\n", err));
goto dongle_rom_out;
}
}
/* Enable/Disable built-in roaming to allow supplicant to take care of roaming */
err = wldev_iovar_setint(ndev, "roam_off", roamvar);
if (unlikely(err)) {
WL_ERR(("roam_off error (%d)\n", err));
goto dongle_rom_out;
}
dongle_rom_out:
return err;
}
#ifndef OEM_ANDROID
#ifndef CUSTOMER_HW6
static s32
wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
s32 scan_unassoc_time)
{
s32 err = 0;
err = wldev_ioctl_set(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time,
sizeof(scan_assoc_time));
if (err) {
if (err == -EOPNOTSUPP) {
WL_INFORM(("Scan assoc time is not supported\n"));
} else {
WL_ERR(("Scan assoc time error (%d)\n", err));
}
goto dongle_scantime_out;
}
err = wldev_ioctl_set(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time,
sizeof(scan_unassoc_time));
if (err) {
if (err == -EOPNOTSUPP) {
WL_INFORM(("Scan unassoc time is not supported\n"));
} else {
WL_ERR(("Scan unassoc time error (%d)\n", err));
}
goto dongle_scantime_out;
}
dongle_scantime_out:
return err;
}
static s32
wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol)
{
s8 iovbuf[WLC_IOCTL_SMLEN];
s32 err = 0;
s32 len;
struct bcm_cfg80211 *cfg = wl_get_cfg(ndev);
dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
/* Set ARP offload */
len = bcm_mkiovar("arpoe", (char *)&arpoe, sizeof(arpoe), iovbuf, sizeof(iovbuf));
if (!len) {
WL_ERR(("%s: bcm_mkiovar failed:%d\n", __FUNCTION__, len));
return BCME_BADARG;
}
err = wldev_ioctl_set(ndev, WLC_SET_VAR, iovbuf, len);
if (err) {
if (err == -EOPNOTSUPP)
WL_INFORM(("arpoe is not supported\n"));
else
WL_ERR(("arpoe error (%d)\n", err));
goto dongle_offload_out;
}
len = bcm_mkiovar("arp_ol", (char *)&arp_ol, sizeof(arp_ol), iovbuf, sizeof(iovbuf));
if (!len) {
WL_ERR(("%s: bcm_mkiovar failed:%d\n", __FUNCTION__, len));
return BCME_BADARG;
}
err = wldev_ioctl_set(ndev, WLC_SET_VAR, iovbuf, len);
if (err) {
if (err == -EOPNOTSUPP)
WL_INFORM(("arp_ol is not supported\n"));
else
WL_ERR(("arp_ol error (%d)\n", err));
goto dongle_offload_out;
}
dhd->arpoe_enable = TRUE;
dhd->arpol_configured = TRUE;
WL_ERR(("arpoe:%d arpol:%d\n",
dhd->arpoe_enable, dhd->arpol_configured));
dongle_offload_out:
return err;
}
static s32 wl_pattern_atoh(s8 *src, s8 *dst)
{
int i;
if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
WL_ERR(("Mask invalid format. Needs to start with 0x\n"));
return -1;
}
src = src + 2; /* Skip past 0x */
if (strlen(src) % 2 != 0) {
WL_ERR(("Mask invalid format. Needs to be of even length\n"));
return -1;
}
for (i = 0; *src != '\0'; i++) {
char num[3];
if ((num[0] = src[0]) != '\0') {
num[1] = src[1];
}
num[2] = '\0';
dst[i] = (u8) simple_strtoul(num, NULL, 16);
src += 2;
}
return i;
}
static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode)
{
const s8 *str;
struct wl_pkt_filter pkt_filter;
struct wl_pkt_filter *pkt_filterp;
s32 buf_len;
s32 str_len;
u32 mask_size;
u32 pattern_size;
s8 buf[PKT_FILTER_BUF_SIZE] = {0};
s32 err = 0;
/* add a default packet filter pattern */
str = "pkt_filter_add";
str_len = strlen(str);
strlcpy(buf, str, sizeof(buf));
buf_len = str_len + 1;
pkt_filterp = (struct wl_pkt_filter *)(buf + str_len + 1);
/* Parse packet filter id. */
pkt_filter.id = htod32(100);
/* Parse filter polarity. */
pkt_filter.negate_match = htod32(0);
/* Parse filter type. */
pkt_filter.type = htod32(0);
/* Parse pattern filter offset. */
pkt_filter.u.pattern.offset = htod32(0);
/* Parse pattern filter mask. */
mask_size = htod32(wl_pattern_atoh("0xff",
(char *)pkt_filterp->u.pattern.
mask_and_pattern));
if (mask_size == (typeof(mask_size))-1 ||
(mask_size > (PKT_FILTER_BUF_SIZE - (buf_len) +
WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN))) {
/* mask_size has to be equal to pattern_size */
err = -EINVAL;
goto dongle_filter_out;
}
/* Parse pattern filter pattern. */
pattern_size = htod32(wl_pattern_atoh("0x00",
(char *)&pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
if (mask_size != pattern_size) {
WL_ERR(("Mask and pattern not the same size\n"));
err = -EINVAL;
goto dongle_filter_out;
}
pkt_filter.u.pattern.size_bytes = mask_size;
buf_len += WL_PKT_FILTER_FIXED_LEN;
buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
/* Keep-alive attributes are set in local
* variable (keep_alive_pkt), and
* then memcpy'ed into buffer (keep_alive_pktp) since there is no
* guarantee that the buffer is properly aligned.
*/
memcpy((char *)pkt_filterp, &pkt_filter,
WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
err = wldev_ioctl_set(ndev, WLC_SET_VAR, buf, buf_len);
if (err) {
if (err == -EOPNOTSUPP) {
WL_INFORM(("filter not supported\n"));
} else {
WL_ERR(("filter (%d)\n", err));
}
goto dongle_filter_out;
}
/* set mode to allow pattern */
err = wldev_iovar_setint(ndev, "pkt_filter_mode", filter_mode);
if (err) {
if (err == -EOPNOTSUPP) {
WL_INFORM(("filter_mode not supported\n"));
} else {
WL_ERR(("filter_mode (%d)\n", err));
}
goto dongle_filter_out;
}
dongle_filter_out:
return err;
}
#endif /* !CUSTOMER_HW6 */
#endif /* !OEM_ANDROID */
s32 dhd_config_dongle(struct bcm_cfg80211 *cfg)
{
@@ -199,21 +504,52 @@ s32 dhd_config_dongle(struct bcm_cfg80211 *cfg)
#endif
struct net_device *ndev;
s32 err = 0;
dhd_pub_t *dhd = NULL;
#if !defined(OEM_ANDROID) && defined(BCMSDIO)
s32 glom = CUSTOM_GLOM_SETTING;
BCM_REFERENCE(glom);
#endif
WL_TRACE(("In\n"));
if (dhd_dongle_up) {
WL_ERR(("Dongle is already up\n"));
return err;
}
ndev = bcmcfg_to_prmry_ndev(cfg);
dhd = (dhd_pub_t *)(cfg->pub);
err = wl_dongle_up(ndev);
if (unlikely(err)) {
WL_ERR(("wl_dongle_up failed\n"));
goto default_conf_out;
}
dhd_dongle_up = true;
if (dhd && dhd->fw_preinit) {
/* Init config will be done by fw preinit context */
return BCME_OK;
}
#ifndef OEM_ANDROID
#ifndef CUSTOMER_HW6
err = wl_dongle_power(ndev, PM_FAST);
if (unlikely(err)) {
WL_ERR(("wl_dongle_power failed\n"));
goto default_conf_out;
}
#ifdef BCMSDIO
err = wl_dongle_glom(ndev, glom, DHD_SDALIGN);
if (unlikely(err)) {
WL_ERR(("wl_dongle_glom failed\n"));
goto default_conf_out;
}
#endif /* BCMSDIO */
err = wl_dongle_roam(ndev, (cfg->roam_on ? 0 : 1), 3);
if (unlikely(err)) {
WL_ERR(("wl_dongle_roam failed\n"));
goto default_conf_out;
}
wl_dongle_scantime(ndev, 40, 80);
wl_dongle_offload(ndev, 1, 0xf);
wl_dongle_filter(ndev, 1);
#endif /* !CUSTOMER_HW6 */
#endif /* OEM_ANDROID */
default_conf_out:
@@ -235,14 +571,6 @@ int dhd_cfgvendor_priv_string_handler(struct bcm_cfg80211 *cfg, struct wireless_
dhd = cfg->pub;
DHD_OS_WAKE_LOCK(dhd);
/* send to dongle only if we are not waiting for reload already */
if (dhd->hang_was_sent) {
WL_ERR(("HANG was sent up earlier\n"));
DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS);
DHD_OS_WAKE_UNLOCK(dhd);
return OSL_ERROR(BCME_DONGLE_DOWN);
}
ndev = wdev_to_wlc_ndev(wdev, cfg);
index = dhd_net2idx(dhd->info, ndev);
if (index == DHD_BAD_IF) {

View File

@@ -1,14 +1,14 @@
/*
* Linux cfg80211 driver - Dongle Host Driver (DHD) related
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,18 +16,13 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_cfg80211.h 612483 2016-01-14 03:44:27Z $
* $Id$
*/
#ifndef __DHD_CFG80211__
#define __DHD_CFG80211__
@@ -50,5 +45,5 @@ s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg);
s32 dhd_config_dongle(struct bcm_cfg80211 *cfg);
int dhd_cfgvendor_priv_string_handler(struct bcm_cfg80211 *cfg,
struct wireless_dev *wdev, const struct bcm_nlmsg_hdr *nlioc, void *data);
s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout);
#endif /* __DHD_CFG80211__ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@
#define _dhd_config_
#include <bcmdevs.h>
#include <siutils.h>
#include <dngl_stats.h>
#include <dhd.h>
#include <wlioctl.h>
@@ -13,8 +14,10 @@
#define FW_TYPE_APSTA 1
#define FW_TYPE_P2P 2
#define FW_TYPE_MESH 3
#define FW_TYPE_ES 4
#define FW_TYPE_MFG 5
#define FW_TYPE_EZMESH 4
#define FW_TYPE_ES 5
#define FW_TYPE_MFG 6
#define FW_TYPE_MINIME 7
#define FW_TYPE_G 0
#define FW_TYPE_AG 1
@@ -31,6 +34,7 @@ extern uint dhd_doflow;
extern uint dhd_slpauto;
#endif
#ifdef SET_FWNV_BY_MAC
typedef struct wl_mac_range {
uint32 oui;
uint32 nic_start;
@@ -47,6 +51,7 @@ typedef struct wl_mac_list_ctrl {
int count;
struct wl_mac_list *m_mac_list_head;
} wl_mac_list_ctrl_t;
#endif
typedef struct wl_chip_nv_path {
uint chip;
@@ -104,10 +109,11 @@ typedef struct mchan_params {
} mchan_params_t;
enum in4way_flags {
NO_SCAN_IN4WAY = (1 << (0)),
NO_BTC_IN4WAY = (1 << (1)),
DONT_DELETE_GC_AFTER_WPS = (1 << (2)),
WAIT_DISCONNECTED = (1 << (3)),
STA_NO_SCAN_IN4WAY = (1 << (0)),
STA_NO_BTC_IN4WAY = (1 << (1)),
STA_WAIT_DISCONNECTED = (1 << (2)),
STA_START_AUTH_DELAY = (1 << (3)),
AP_WAIT_STA_RECONNECT = (1 << (4)),
};
enum in_suspend_flags {
@@ -122,11 +128,18 @@ enum in_suspend_flags {
};
enum in_suspend_mode {
AUTO_SUSPEND = -1,
EARLY_SUSPEND = 0,
PM_NOTIFIER = 1
};
#ifdef HOST_TPUT_TEST
enum data_drop_mode {
NO_DATA_DROP = 0,
TXPKT_DROP = 1,
XMIT_DROP = 2
};
#endif
enum eapol_status {
EAPOL_STATUS_NONE = 0,
EAPOL_STATUS_REQID = 1,
@@ -142,20 +155,33 @@ enum eapol_status {
EAPOL_STATUS_WPS_M8 = 11,
EAPOL_STATUS_WSC_DONE = 12,
EAPOL_STATUS_4WAY_START = 13,
EAPOL_STATUS_4WAY_M1 = 14,
EAPOL_STATUS_4WAY_M2 = 15,
EAPOL_STATUS_4WAY_M3 = 16,
EAPOL_STATUS_4WAY_M4 = 17,
EAPOL_STATUS_GROUPKEY_M1 = 18,
EAPOL_STATUS_GROUPKEY_M2 = 19,
EAPOL_STATUS_4WAY_DONE = 20
AUTH_SAE_COMMIT_M1 = 14,
AUTH_SAE_COMMIT_M2 = 15,
AUTH_SAE_CONFIRM_M3 = 16,
AUTH_SAE_CONFIRM_M4 = 17,
EAPOL_STATUS_4WAY_M1 = 18,
EAPOL_STATUS_4WAY_M2 = 19,
EAPOL_STATUS_4WAY_M3 = 20,
EAPOL_STATUS_4WAY_M4 = 21,
EAPOL_STATUS_GROUPKEY_M1 = 22,
EAPOL_STATUS_GROUPKEY_M2 = 23,
EAPOL_STATUS_4WAY_DONE = 24
};
typedef struct dhd_conf {
uint devid;
uint chip;
uint chiprev;
#if defined(BCMPCIE)
uint svid;
uint ssid;
#endif
#ifdef GET_OTP_MODULE_NAME
char module_name[16];
#endif
struct ether_addr otp_mac;
int fw_type;
#ifdef BCMSDIO
#ifdef SET_FWNV_BY_MAC
wl_mac_list_ctrl_t fw_by_mac;
wl_mac_list_ctrl_t nv_by_mac;
#endif
@@ -209,19 +235,34 @@ typedef struct dhd_conf {
int txglom_bucket_size;
int txinrx_thres;
int dhd_txminmax; // -1=DATABUFCNT(bus)
#ifdef DYNAMIC_MAX_HDR_READ
int max_hdr_read;
#endif
bool oob_enabled_later;
#ifdef MINIME
uint32 ramsize;
#endif
#if defined(SDIO_ISR_THREAD)
bool intr_extn;
#endif
#ifdef BCMSDIO_RXLIM_POST
bool rxlim_en;
#endif
#ifdef BCMSDIO_TXSEQ_SYNC
bool txseq_sync;
#endif
#ifdef BCMSDIO_INTSTATUS_WAR
uint read_intr_mode;
#endif
#endif
#ifdef BCMPCIE
int bus_deepsleep_disable;
int flow_ring_queue_threshold;
int d2h_intr_method;
#endif
int dpc_cpucore;
int rxf_cpucore;
int dhd_dpc_prio;
int frameburst;
bool deepsleep;
int pm;
@@ -230,6 +271,8 @@ typedef struct dhd_conf {
int suspend_bcn_li_dtim;
#ifdef DHDTCPACK_SUPPRESS
uint8 tcpack_sup_mode;
uint32 tcpack_sup_ratio;
uint32 tcpack_sup_delay;
#endif
int pktprio8021x;
uint insuspend;
@@ -255,9 +298,10 @@ typedef struct dhd_conf {
int ctrl_resched;
mchan_params_t *mchan;
char *wl_preinit;
char *wl_suspend;
char *wl_resume;
int tsq;
int orphan_move;
uint eapol_status;
uint in4way;
#ifdef WL_EXT_WOWL
uint wowl;
@@ -266,18 +310,47 @@ typedef struct dhd_conf {
char hw_ether[62];
#endif
wait_queue_head_t event_complete;
#ifdef PROPTX_MAXCOUNT
int proptx_maxcnt_2g;
int proptx_maxcnt_5g;
#endif /* DYNAMIC_PROPTX_MAXCOUNT */
#ifdef HOST_TPUT_TEST
int data_drop_mode;
uint tput_measure_ms;
struct osl_timespec tput_ts;
unsigned long net_len;
#endif
#ifdef TPUT_MONITOR
uint tput_monitor_ms;
#endif
#ifdef DHD_TPUT_PATCH
bool tput_patch;
int mtu;
bool pktsetsum;
#endif
#ifdef SET_XPS_CPUS
bool xps_cpus;
#endif
#ifdef SET_RPS_CPUS
bool rps_cpus;
#endif
#ifdef CHECK_DOWNLOAD_FW
bool fwchk;
#endif
} dhd_conf_t;
#ifdef BCMSDIO
int dhd_conf_get_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, uint8 *mac);
void dhd_conf_get_otp(dhd_pub_t *dhd, bcmsdh_info_t *sdh, si_t *sih);
#if defined(HW_OOB) || defined(FORCE_WOWLAN)
void dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, uint chip);
void dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, struct si_pub *sih);
#endif
void dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable);
int dhd_conf_set_blksize(bcmsdh_info_t *sdh);
#endif
void dhd_conf_set_path_params(dhd_pub_t *dhd, void *sdh,
char *fw_path, char *nv_path);
#ifdef BCMPCIE
int dhd_conf_get_otp(dhd_pub_t *dhd, si_t *sih);
bool dhd_conf_legacy_msi_chip(dhd_pub_t *dhd);
#endif
void dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path);
int dhd_conf_set_intiovar(dhd_pub_t *dhd, uint cmd, char *name, int val,
int def, bool down);
int dhd_conf_get_band(dhd_pub_t *dhd);
@@ -311,8 +384,11 @@ void dhd_conf_set_garp(dhd_pub_t *dhd, int ifidx, uint32 ipa, bool enable);
#ifdef PROP_TXSTATUS
int dhd_conf_get_disable_proptx(dhd_pub_t *dhd);
#endif
#ifdef HOST_TPUT_TEST
void dhd_conf_tput_measure(dhd_pub_t *dhd);
#endif
uint dhd_conf_get_insuspend(dhd_pub_t *dhd, uint mask);
int dhd_conf_set_suspend_resume(dhd_pub_t *dhd, int suspend, int suspend_mode);
int dhd_conf_set_suspend_resume(dhd_pub_t *dhd, int suspend);
void dhd_conf_postinit_ioctls(dhd_pub_t *dhd);
int dhd_conf_preinit(dhd_pub_t *dhd);
int dhd_conf_reset(dhd_pub_t *dhd);

View File

@@ -0,0 +1,220 @@
/*
* Broadcom Dongle Host Driver (DHD)
*
* Copyright (C) 1999-2018, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: dhd_csi.c 606280 2015-12-15 05:28:25Z $
*/
#include <osl.h>
#include <bcmutils.h>
#include <bcmendian.h>
#include <linuxver.h>
#include <linux/list.h>
#include <linux/sort.h>
#include <dngl_stats.h>
#include <wlioctl.h>
#include <bcmevent.h>
#include <dhd.h>
#include <dhd_dbg.h>
#include <dhd_csi.h>
#define NULL_CHECK(p, s, err) \
do { \
if (!(p)) { \
printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \
err = BCME_ERROR; \
return err; \
} \
} while (0)
#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \
(ts).tv_nsec / NSEC_PER_USEC)
#define NULL_ADDR "\x00\x00\x00\x00\x00\x00"
int
dhd_csi_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data)
{
int ret = BCME_OK;
bool is_new = TRUE;
cfr_dump_data_t *p_event;
cfr_dump_list_t *ptr, *next, *new;
NULL_CHECK(dhd, "dhd is NULL", ret);
DHD_TRACE(("Enter %s\n", __FUNCTION__));
if (!event_data) {
DHD_ERROR(("%s: event_data is NULL\n", __FUNCTION__));
return -EINVAL;
}
p_event = (cfr_dump_data_t *)event_data;
/* check if this addr exist */
if (!list_empty(&dhd->csi_list)) {
list_for_each_entry_safe(ptr, next, &dhd->csi_list, list) {
if (bcmp(&ptr->entry.header.peer_macaddr, &p_event->header.peer_macaddr,
ETHER_ADDR_LEN) == 0) {
int pos = 0, dump_len = 0, remain = 0;
is_new = FALSE;
DHD_INFO(("CSI data exist\n"));
if (p_event->header.status == 0) {
bcopy(&p_event->header, &ptr->entry.header, sizeof(cfr_dump_header_t));
dump_len = p_event->header.cfr_dump_length;
if (dump_len < MAX_EVENT_SIZE) {
bcopy(&p_event->data, &ptr->entry.data, dump_len);
} else {
/* for big csi data */
uint8 *p = (uint8 *)&ptr->entry.data;
remain = p_event->header.remain_length;
if (remain) {
pos = dump_len - remain - MAX_EVENT_SIZE;
p += pos;
bcopy(&p_event->data, p, MAX_EVENT_SIZE);
}
/* copy rest of csi data */
else {
pos = dump_len - (dump_len % MAX_EVENT_SIZE);
p += pos;
bcopy(&p_event->data, p, (dump_len % MAX_EVENT_SIZE));
}
}
return BCME_OK;
}
}
}
}
if (is_new) {
if (dhd->csi_count < MAX_CSI_NUM) {
new = (cfr_dump_list_t *)MALLOCZ(dhd->osh, sizeof(cfr_dump_list_t));
if (!new){
DHD_ERROR(("Malloc cfr dump list error\n"));
return BCME_NOMEM;
}
bcopy(&p_event->header, &new->entry.header, sizeof(cfr_dump_header_t));
DHD_INFO(("New entry data size %d\n", p_event->header.cfr_dump_length));
/* for big csi data */
if (p_event->header.remain_length) {
DHD_TRACE(("remain %d\n", p_event->header.remain_length));
bcopy(&p_event->data, &new->entry.data, MAX_EVENT_SIZE);
}
else
bcopy(&p_event->data, &new->entry.data, p_event->header.cfr_dump_length);
INIT_LIST_HEAD(&(new->list));
list_add_tail(&(new->list), &dhd->csi_list);
dhd->csi_count++;
}
else {
DHD_TRACE(("Over maximum CSI Number 8. SKIP it.\n"));
}
}
return ret;
}
int
dhd_csi_init(dhd_pub_t *dhd)
{
int err = BCME_OK;
NULL_CHECK(dhd, "dhd is NULL", err);
INIT_LIST_HEAD(&dhd->csi_list);
dhd->csi_count = 0;
return err;
}
int
dhd_csi_deinit(dhd_pub_t *dhd)
{
int err = BCME_OK;
cfr_dump_list_t *ptr, *next;
NULL_CHECK(dhd, "dhd is NULL", err);
if (!list_empty(&dhd->csi_list)) {
list_for_each_entry_safe(ptr, next, &dhd->csi_list, list) {
list_del(&ptr->list);
MFREE(dhd->osh, ptr, sizeof(cfr_dump_list_t));
}
}
return err;
}
void
dhd_csi_clean_list(dhd_pub_t *dhd)
{
cfr_dump_list_t *ptr, *next;
int num = 0;
if (!dhd) {
DHD_ERROR(("NULL POINTER: %s\n", __FUNCTION__));
return;
}
if (!list_empty(&dhd->csi_list)) {
list_for_each_entry_safe(ptr, next, &dhd->csi_list, list) {
if (0 == ptr->entry.header.remain_length) {
list_del(&ptr->list);
num++;
MFREE(dhd->osh, ptr, sizeof(cfr_dump_list_t));
}
}
}
dhd->csi_count = 0;
DHD_TRACE(("Clean up %d record\n", num));
}
int
dhd_csi_dump_list(dhd_pub_t *dhd, char *buf)
{
int ret = BCME_OK;
cfr_dump_list_t *ptr, *next;
uint8 * pbuf = buf;
int num = 0;
int length = 0;
NULL_CHECK(dhd, "dhd is NULL", ret);
/* check if this addr exist */
if (!list_empty(&dhd->csi_list)) {
list_for_each_entry_safe(ptr, next, &dhd->csi_list, list) {
if (ptr->entry.header.remain_length) {
DHD_ERROR(("data not ready %d\n", ptr->entry.header.remain_length));
continue;
}
bcopy(&ptr->entry.header, pbuf, sizeof(cfr_dump_header_t));
length += sizeof(cfr_dump_header_t);
pbuf += sizeof(cfr_dump_header_t);
DHD_TRACE(("Copy data size %d\n", ptr->entry.header.cfr_dump_length));
bcopy(&ptr->entry.data, pbuf, ptr->entry.header.cfr_dump_length);
length += ptr->entry.header.cfr_dump_length;
pbuf += ptr->entry.header.cfr_dump_length;
num++;
}
}
DHD_TRACE(("dump %d record %d bytes\n", num, length));
return length;
}

View File

@@ -0,0 +1,77 @@
/*
* Broadcom Dongle Host Driver (DHD), CSI
*
* Copyright (C) 1999-2018, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: dhd_csi.h 558438 2015-05-22 06:05:11Z $
*/
#ifndef __DHD_CSI_H__
#define __DHD_CSI_H__
/* Maxinum csi file dump size */
#define MAX_CSI_FILESZ (32 * 1024)
/* Maxinum subcarrier number */
#define MAXINUM_CFR_DATA 256 * 4
#define CSI_DUMP_PATH "/sys/bcm-dhd/csi"
#define MAX_EVENT_SIZE 1400
/* maximun csi number stored at dhd */
#define MAX_CSI_NUM 8
typedef struct cfr_dump_header {
/* 0 - successful; 1 - Failed */
uint8 status;
/* Peer MAC address */
uint8 peer_macaddr[6];
/* Number of Space Time Streams */
uint8 sts;
/* Number of RX chain */
uint8 num_rx;
/* Number of subcarrier */
uint16 num_carrier;
/* Length of the CSI dump */
uint32 cfr_dump_length;
/* remain unsend CSI data length */
uint32 remain_length;
/* RSSI */
int8 rssi;
} __attribute__((packed)) cfr_dump_header_t;
typedef struct cfr_dump_data {
cfr_dump_header_t header;
uint32 data[MAXINUM_CFR_DATA];
} cfr_dump_data_t;
typedef struct {
struct list_head list;
cfr_dump_data_t entry;
} cfr_dump_list_t;
int dhd_csi_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data);
int dhd_csi_init(dhd_pub_t *dhd);
int dhd_csi_deinit(dhd_pub_t *dhd);
void dhd_csi_clean_list(dhd_pub_t *dhd);
int dhd_csi_dump_list(dhd_pub_t *dhd, char *buf);
#endif /* __DHD_CSI_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,333 @@
/*
* Platform Dependent file for Samsung Exynos
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id$
*/
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/poll.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/io.h>
#include <linux/workqueue.h>
#include <linux/unistd.h>
#include <linux/bug.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#if defined(CONFIG_SOC_EXYNOS8895) || defined(CONFIG_SOC_EXYNOS9810) || \
defined(CONFIG_SOC_EXYNOS9820) || defined(CONFIG_SOC_EXYNOS9830) || \
defined(CONFIG_SOC_EXYNOS2100) || defined(CONFIG_SOC_EXYNOS1000)
#include <linux/exynos-pci-ctrl.h>
#endif /* CONFIG_SOC_EXYNOS8895 || CONFIG_SOC_EXYNOS9810 ||
* CONFIG_SOC_EXYNOS9820 || CONFIG_SOC_EXYNOS9830 ||
* CONFIG_SOC_EXYNOS2100 || CONFIG_SOC_EXYNOS1000
*/
#if defined(CONFIG_64BIT)
#include <asm-generic/gpio.h>
#endif /* CONFIG_64BIT */
#ifdef BCMDHD_MODULAR
#if IS_ENABLED(CONFIG_SEC_SYSFS)
#include <linux/sec_sysfs.h>
#endif /* CONFIG_SEC_SYSFS */
#if IS_ENABLED(CONFIG_DRV_SAMSUNG)
#include <linux/sec_class.h>
#endif /* CONFIG_SEC_SYSFS */
#else
#if defined(CONFIG_SEC_SYSFS)
#include <linux/sec_sysfs.h>
#elif defined(CONFIG_DRV_SAMSUNG)
#include <linux/sec_class.h>
#endif /* CONFIG_SEC_SYSFS */
#endif /* BCMDHD_MODULAR */
#include <linux/wlan_plat.h>
#if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE)
#define PINCTL_DELAY 150
#endif /* CONFIG_MACH_A7LTE || CONFIG_NOBLESSE */
#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
extern void dhd_exit_wlan_mem(void);
extern int dhd_init_wlan_mem(void);
extern void *dhd_wlan_mem_prealloc(int section, unsigned long size);
#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
#define WIFI_TURNON_DELAY 200
static int wlan_pwr_on = -1;
#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE
static int wlan_host_wake_irq = 0;
static unsigned int wlan_host_wake_up = -1;
#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */
#if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE)
extern struct device *mmc_dev_for_wlan;
#endif /* CONFIG_MACH_A7LTE || CONFIG_NOBLESSE */
#ifdef CONFIG_BCMDHD_PCIE
extern int pcie_ch_num;
extern void exynos_pcie_pm_resume(int);
extern void exynos_pcie_pm_suspend(int);
#endif /* CONFIG_BCMDHD_PCIE */
#if defined(CONFIG_SOC_EXYNOS7870) || defined(CONFIG_SOC_EXYNOS9110)
extern struct mmc_host *wlan_mmc;
extern void mmc_ctrl_power(struct mmc_host *host, bool onoff);
#endif /* SOC_EXYNOS7870 || CONFIG_SOC_EXYNOS9110 */
static int
dhd_wlan_power(int onoff)
{
#if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE)
struct pinctrl *pinctrl = NULL;
#endif /* CONFIG_MACH_A7LTE || ONFIG_NOBLESSE */
printk(KERN_INFO"%s Enter: power %s\n", __FUNCTION__, onoff ? "on" : "off");
#if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE)
if (onoff) {
pinctrl = devm_pinctrl_get_select(mmc_dev_for_wlan, "sdio_wifi_on");
if (IS_ERR(pinctrl))
printk(KERN_INFO "%s WLAN SDIO GPIO control error\n", __FUNCTION__);
msleep(PINCTL_DELAY);
}
#endif /* CONFIG_MACH_A7LTE || CONFIG_NOBLESSE */
if (gpio_direction_output(wlan_pwr_on, onoff)) {
printk(KERN_ERR "%s failed to control WLAN_REG_ON to %s\n",
__FUNCTION__, onoff ? "HIGH" : "LOW");
return -EIO;
}
#if defined(CONFIG_MACH_A7LTE) || defined(CONFIG_NOBLESSE)
if (!onoff) {
pinctrl = devm_pinctrl_get_select(mmc_dev_for_wlan, "sdio_wifi_off");
if (IS_ERR(pinctrl))
printk(KERN_INFO "%s WLAN SDIO GPIO control error\n", __FUNCTION__);
}
#endif /* CONFIG_MACH_A7LTE || CONFIG_NOBLESSE */
#if defined(CONFIG_SOC_EXYNOS7870) || defined(CONFIG_SOC_EXYNOS9110)
if (wlan_mmc)
mmc_ctrl_power(wlan_mmc, onoff);
#endif /* SOC_EXYNOS7870 || CONFIG_SOC_EXYNOS9110 */
return 0;
}
static int
dhd_wlan_reset(int onoff)
{
return 0;
}
#ifndef CONFIG_BCMDHD_PCIE
extern void (*notify_func_callback)(void *dev_id, int state);
extern void *mmc_host_dev;
#endif /* !CONFIG_BCMDHD_PCIE */
static int
dhd_wlan_set_carddetect(int val)
{
#ifndef CONFIG_BCMDHD_PCIE
pr_err("%s: notify_func=%p, mmc_host_dev=%p, val=%d\n",
__FUNCTION__, notify_func_callback, mmc_host_dev, val);
if (notify_func_callback) {
notify_func_callback(mmc_host_dev, val);
} else {
pr_warning("%s: Nobody to notify\n", __FUNCTION__);
}
#else
if (val) {
exynos_pcie_pm_resume(pcie_ch_num);
} else {
exynos_pcie_pm_suspend(pcie_ch_num);
}
#endif /* CONFIG_BCMDHD_PCIE */
return 0;
}
int __init
dhd_wlan_init_gpio(void)
{
const char *wlan_node = "samsung,brcm-wlan";
struct device_node *root_node = NULL;
struct device *wlan_dev;
wlan_dev = sec_device_create(NULL, "wlan");
root_node = of_find_compatible_node(NULL, NULL, wlan_node);
if (!root_node) {
WARN(1, "failed to get device node of bcm4354\n");
return -ENODEV;
}
/* ========== WLAN_PWR_EN ============ */
wlan_pwr_on = of_get_gpio(root_node, 0);
if (!gpio_is_valid(wlan_pwr_on)) {
WARN(1, "Invalied gpio pin : %d\n", wlan_pwr_on);
return -ENODEV;
}
if (gpio_request(wlan_pwr_on, "WLAN_REG_ON")) {
WARN(1, "fail to request gpio(WLAN_REG_ON)\n");
return -ENODEV;
}
#ifdef CONFIG_BCMDHD_PCIE
gpio_direction_output(wlan_pwr_on, 1);
msleep(WIFI_TURNON_DELAY);
#else
gpio_direction_output(wlan_pwr_on, 0);
#endif /* CONFIG_BCMDHD_PCIE */
gpio_export(wlan_pwr_on, 1);
if (wlan_dev)
gpio_export_link(wlan_dev, "WLAN_REG_ON", wlan_pwr_on);
#ifdef CONFIG_BCMDHD_PCIE
exynos_pcie_pm_resume(pcie_ch_num);
#endif /* CONFIG_BCMDHD_PCIE */
#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE
/* ========== WLAN_HOST_WAKE ============ */
wlan_host_wake_up = of_get_gpio(root_node, 1);
if (!gpio_is_valid(wlan_host_wake_up)) {
WARN(1, "Invalied gpio pin : %d\n", wlan_host_wake_up);
return -ENODEV;
}
if (gpio_request(wlan_host_wake_up, "WLAN_HOST_WAKE")) {
WARN(1, "fail to request gpio(WLAN_HOST_WAKE)\n");
return -ENODEV;
}
gpio_direction_input(wlan_host_wake_up);
gpio_export(wlan_host_wake_up, 1);
if (wlan_dev)
gpio_export_link(wlan_dev, "WLAN_HOST_WAKE", wlan_host_wake_up);
wlan_host_wake_irq = gpio_to_irq(wlan_host_wake_up);
#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */
return 0;
}
#if defined(CONFIG_BCMDHD_OOB_HOST_WAKE) && defined(CONFIG_BCMDHD_GET_OOB_STATE)
int
dhd_get_wlan_oob_gpio(void)
{
return gpio_is_valid(wlan_host_wake_up) ?
gpio_get_value(wlan_host_wake_up) : -1;
}
EXPORT_SYMBOL(dhd_get_wlan_oob_gpio);
#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE && CONFIG_BCMDHD_GET_OOB_STATE */
struct resource dhd_wlan_resources = {
.name = "bcmdhd_wlan_irq",
.start = 0,
.end = 0,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE |
#ifdef CONFIG_BCMDHD_PCIE
IORESOURCE_IRQ_HIGHEDGE,
#else
IORESOURCE_IRQ_HIGHLEVEL,
#endif /* CONFIG_BCMDHD_PCIE */
};
EXPORT_SYMBOL(dhd_wlan_resources);
struct wifi_platform_data dhd_wlan_control = {
.set_power = dhd_wlan_power,
.set_reset = dhd_wlan_reset,
.set_carddetect = dhd_wlan_set_carddetect,
#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
.mem_prealloc = dhd_wlan_mem_prealloc,
#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
};
EXPORT_SYMBOL(dhd_wlan_control);
int __init
dhd_wlan_init(void)
{
int ret;
printk(KERN_INFO "%s: START.......\n", __FUNCTION__);
ret = dhd_wlan_init_gpio();
if (ret < 0) {
printk(KERN_ERR "%s: failed to initiate GPIO, ret=%d\n",
__FUNCTION__, ret);
goto fail;
}
#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE
dhd_wlan_resources.start = wlan_host_wake_irq;
dhd_wlan_resources.end = wlan_host_wake_irq;
#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */
#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
ret = dhd_init_wlan_mem();
if (ret < 0) {
printk(KERN_ERR "%s: failed to alloc reserved memory,"
" ret=%d\n", __FUNCTION__, ret);
}
#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
fail:
return ret;
}
int
dhd_wlan_deinit(void)
{
#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE
gpio_free(wlan_host_wake_up);
#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */
gpio_free(wlan_pwr_on);
#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
dhd_exit_wlan_mem();
#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
return 0;
}
#ifndef BCMDHD_MODULAR
#if defined(CONFIG_MACH_UNIVERSAL7420) || defined(CONFIG_SOC_EXYNOS8890) || \
defined(CONFIG_SOC_EXYNOS8895) || defined(CONFIG_SOC_EXYNOS9810) || \
defined(CONFIG_SOC_EXYNOS9820) || defined(CONFIG_SOC_EXYNOS9830)
#if defined(CONFIG_DEFERRED_INITCALLS)
deferred_module_init(dhd_wlan_init);
#else
late_initcall(dhd_wlan_init);
#endif /* CONFIG_DEFERRED_INITCALLS */
#else
device_initcall(dhd_wlan_init);
#endif /* CONFIG Exynos PCIE Platforms */
#endif /* !BCMDHD_MODULAR */

View File

@@ -1,14 +1,14 @@
/*
* Customer code to add GPIO control during WLAN start/stop
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,15 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_custom_gpio.c 664997 2016-10-14 11:56:35Z $
* $Id$
*/
#include <typedefs.h>
@@ -37,10 +33,15 @@
#include <wlioctl.h>
#ifndef BCMDONGLEHOST
#include <wlc_pub.h>
#include <wl_dbg.h>
#else
#define WL_ERROR(x) printf x
#define WL_TRACE(x)
#endif
#if defined(OOB_INTR_ONLY)
#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
#if defined(BCMLXSDMMC)
extern int sdioh_mmc_irq(int irq);
@@ -67,7 +68,7 @@ int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr)
{
int host_oob_irq = 0;
#if defined(CUSTOMER_HW2)
#if defined(CUSTOMER_HW2) || defined(CUSTOMER_HW4) || defined(BOARD_HIKEY)
host_oob_irq = wifi_platform_get_irq_number(adapter, irq_flags_ptr);
#else
@@ -86,11 +87,11 @@ int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr)
WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n",
__FUNCTION__, dhd_oob_gpio_num));
#endif
#endif /* CUSTOMER_HW2 || CUSTOMER_HW4 || BOARD_HIKEY */
return (host_oob_irq);
}
#endif
#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
/* Customer function to control hw specific wlan gpios */
int
@@ -101,7 +102,7 @@ dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff)
return err;
}
#ifdef GET_CUSTOM_MAC_ENABLE
#if 0
/* Function to get custom MAC address */
int
dhd_custom_get_mac_address(void *adapter, unsigned char *buf)
@@ -113,7 +114,8 @@ dhd_custom_get_mac_address(void *adapter, unsigned char *buf)
return -EINVAL;
/* Customer access to MAC address stored outside of DHD driver */
#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
#if (defined(CUSTOMER_HW2) || defined(CUSTOMER_HW10) || defined(BOARD_HIKEY)) && \
(LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
ret = wifi_platform_get_mac_addr(adapter, buf);
#endif
@@ -129,6 +131,7 @@ dhd_custom_get_mac_address(void *adapter, unsigned char *buf)
}
#endif /* GET_CUSTOM_MAC_ENABLE */
#ifndef CUSTOMER_HW4
/* Customized Locale table : OPTIONAL feature */
const struct cntry_locales_custom translate_custom_table[] = {
/* Table should be filled out based on custom platform regulatory requirement */
@@ -176,7 +179,7 @@ const struct cntry_locales_custom translate_custom_table[] = {
{"TR", "TR", 0},
{"NO", "NO", 0},
#endif /* EXMAPLE_TABLE */
#if defined(CUSTOMER_HW2)
#if (defined(CUSTOMER_HW2) || defined(BOARD_HIKEY)) && !defined(CUSTOMER_HW5)
#if defined(BCM4335_CHIP)
{"", "XZ", 11}, /* Universal if Country code is unknown or empty */
#endif
@@ -233,14 +236,144 @@ const struct cntry_locales_custom translate_custom_table[] = {
{"PS", "XZ", 11}, /* Universal if Country code is PALESTINIAN TERRITORY, OCCUPIED */
{"TL", "XZ", 11}, /* Universal if Country code is TIMOR-LESTE (EAST TIMOR) */
{"MH", "XZ", 11}, /* Universal if Country code is MARSHALL ISLANDS */
#ifdef BCM4330_CHIP
{"RU", "RU", 1},
{"US", "US", 5}
#endif
#endif
#elif defined(CUSTOMER_HW5)
{"", "XZ", 11},
{"AE", "AE", 212},
{"AG", "AG", 2},
{"AI", "AI", 2},
{"AL", "AL", 2},
{"AN", "AN", 3},
{"AR", "AR", 212},
{"AS", "AS", 15},
{"AT", "AT", 4},
{"AU", "AU", 212},
{"AW", "AW", 2},
{"AZ", "AZ", 2},
{"BA", "BA", 2},
{"BD", "BD", 2},
{"BE", "BE", 4},
{"BG", "BG", 4},
{"BH", "BH", 4},
{"BM", "BM", 15},
{"BN", "BN", 4},
{"BR", "BR", 212},
{"BS", "BS", 2},
{"BY", "BY", 3},
{"BW", "BW", 1},
{"CA", "CA", 212},
{"CH", "CH", 212},
{"CL", "CL", 212},
{"CN", "CN", 212},
{"CO", "CO", 212},
{"CR", "CR", 21},
{"CY", "CY", 212},
{"CZ", "CZ", 212},
{"DE", "DE", 212},
{"DK", "DK", 4},
{"DZ", "DZ", 1},
{"EC", "EC", 23},
{"EE", "EE", 4},
{"EG", "EG", 212},
{"ES", "ES", 212},
{"ET", "ET", 2},
{"FI", "FI", 4},
{"FR", "FR", 212},
{"GB", "GB", 212},
{"GD", "GD", 2},
{"GF", "GF", 2},
{"GP", "GP", 2},
{"GR", "GR", 212},
{"GT", "GT", 0},
{"GU", "GU", 17},
{"HK", "HK", 212},
{"HR", "HR", 4},
{"HU", "HU", 4},
{"IN", "IN", 212},
{"ID", "ID", 212},
{"IE", "IE", 5},
{"IL", "IL", 7},
{"IN", "IN", 212},
{"IS", "IS", 4},
{"IT", "IT", 212},
{"JO", "JO", 3},
{"JP", "JP", 212},
{"KH", "KH", 4},
{"KI", "KI", 1},
{"KR", "KR", 212},
{"KW", "KW", 5},
{"KY", "KY", 4},
{"KZ", "KZ", 212},
{"LA", "LA", 4},
{"LB", "LB", 6},
{"LI", "LI", 4},
{"LK", "LK", 3},
{"LS", "LS", 2},
{"LT", "LT", 4},
{"LR", "LR", 2},
{"LU", "LU", 3},
{"LV", "LV", 4},
{"MA", "MA", 2},
{"MC", "MC", 1},
{"MD", "MD", 2},
{"ME", "ME", 2},
{"MK", "MK", 2},
{"MN", "MN", 0},
{"MO", "MO", 2},
{"MR", "MR", 2},
{"MT", "MT", 4},
{"MQ", "MQ", 2},
{"MU", "MU", 2},
{"MV", "MV", 3},
{"MX", "MX", 212},
{"MY", "MY", 212},
{"NI", "NI", 0},
{"NL", "NL", 212},
{"NO", "NO", 4},
{"NP", "NP", 3},
{"NZ", "NZ", 9},
{"OM", "OM", 4},
{"PA", "PA", 17},
{"PE", "PE", 212},
{"PG", "PG", 2},
{"PH", "PH", 212},
{"PL", "PL", 212},
{"PR", "PR", 25},
{"PT", "PT", 212},
{"PY", "PY", 4},
{"RE", "RE", 2},
{"RO", "RO", 212},
{"RS", "RS", 2},
{"RU", "RU", 212},
{"SA", "SA", 212},
{"SE", "SE", 212},
{"SG", "SG", 212},
{"SI", "SI", 4},
{"SK", "SK", 212},
{"SN", "SN", 2},
{"SV", "SV", 25},
{"TH", "TH", 212},
{"TR", "TR", 212},
{"TT", "TT", 5},
{"TW", "TW", 212},
{"UA", "UA", 212},
{"UG", "UG", 2},
{"US", "US", 212},
{"UY", "UY", 5},
{"VA", "VA", 2},
{"VE", "VE", 3},
{"VG", "VG", 2},
{"VI", "VI", 18},
{"VN", "VN", 4},
{"YT", "YT", 2},
{"ZA", "ZA", 212},
{"ZM", "ZM", 2},
{"XT", "XT", 212},
{"XZ", "XZ", 11},
{"XV", "XV", 17},
{"Q1", "Q1", 77},
#endif /* (CUSTOMER_HW2 || BOARD_HIKEY) && CUSTOMER_HW5 */
};
/* Customized Locale convertor
* input : ISO 3166-1 country abbreviation
* output: customized cspec
@@ -253,6 +386,7 @@ get_customized_country_code(void *adapter, char *country_iso_code,
get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec)
#endif /* CUSTOM_COUNTRY_CODE */
{
#if defined(OEM_ANDROID)
#if (defined(CUSTOMER_HW) || defined(CUSTOMER_HW2)) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
struct cntry_locales_custom *cloc_ptr;
@@ -295,5 +429,9 @@ get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t
cspec->rev = translate_custom_table[0].custom_locale_rev;
#endif /* EXMAPLE_TABLE */
return;
#endif /* defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) */
#endif /* (defined(CUSTOMER_HW2) || defined(BOARD_HIKEY)) &&
* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36))
*/
#endif /* OEM_ANDROID */
}
#endif /* !CUSTOMER_HW4 */

View File

@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Platform Dependent file for Hikey
*
* Copyright (C) 1999-2019, Broadcom.
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -18,9 +17,6 @@
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* <<Broadcom-WL-IPTag/Open:>>
*
@@ -35,17 +31,22 @@
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/skbuff.h>
#include <linux/wlan_plat.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/of_gpio.h>
#ifdef CONFIG_WIFI_CONTROL_FUNC
#include <linux/wlan_plat.h>
#else
#include <dhd_plat.h>
#endif /* CONFIG_WIFI_CONTROL_FUNC */
#include <dhd_dbg.h>
#include <dhd.h>
#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
extern int dhd_init_wlan_mem(void);
extern void *dhd_wlan_mem_prealloc(int section, unsigned long size);
#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
#define WIFI_TURNON_DELAY 200
#define WLAN_REG_ON_GPIO 491
#define WLAN_HOST_WAKE_GPIO 493
@@ -70,59 +71,58 @@ dhd_wifi_init_gpio(void)
wlan_reg_on = of_get_named_gpio(root_node, WIFI_WL_REG_ON_PROPNAME, 0);
wlan_host_wake_up = of_get_named_gpio(root_node, WIFI_WLAN_HOST_WAKE_PROPNAME, 0);
} else {
printk(KERN_ERR "failed to get device node of BRCM WLAN, use default GPIOs\n");
DHD_ERROR(("failed to get device node of BRCM WLAN, use default GPIOs\n"));
wlan_reg_on = WLAN_REG_ON_GPIO;
wlan_host_wake_up = WLAN_HOST_WAKE_GPIO;
}
/* ========== WLAN_PWR_EN ============ */
printk(KERN_INFO "%s: gpio_wlan_power : %d\n", __FUNCTION__, wlan_reg_on);
DHD_INFO(("%s: gpio_wlan_power : %d\n", __FUNCTION__, wlan_reg_on));
/*
* For reg_on, gpio_request will fail if the gpio is configured to output-high
* in the dts using gpio-hog, so do not return error for failure.
*/
if (gpio_request_one(wlan_reg_on, GPIOF_OUT_INIT_HIGH, "WL_REG_ON")) {
printk(KERN_ERR "%s: Failed to request gpio %d for WL_REG_ON, "
DHD_ERROR(("%s: Failed to request gpio %d for WL_REG_ON, "
"might have configured in the dts\n",
__FUNCTION__, wlan_reg_on);
__FUNCTION__, wlan_reg_on));
} else {
printk(KERN_ERR "%s: gpio_request WL_REG_ON done - WLAN_EN: GPIO %d\n",
__FUNCTION__, wlan_reg_on);
DHD_ERROR(("%s: gpio_request WL_REG_ON done - WLAN_EN: GPIO %d\n",
__FUNCTION__, wlan_reg_on));
}
gpio_reg_on_val = gpio_get_value(wlan_reg_on);
printk(KERN_INFO "%s: Initial WL_REG_ON: [%d]\n",
__FUNCTION__, gpio_get_value(wlan_reg_on));
DHD_INFO(("%s: Initial WL_REG_ON: [%d]\n",
__FUNCTION__, gpio_get_value(wlan_reg_on)));
if (gpio_reg_on_val == 0) {
printk(KERN_INFO "%s: WL_REG_ON is LOW, drive it HIGH\n", __FUNCTION__);
DHD_INFO(("%s: WL_REG_ON is LOW, drive it HIGH\n", __FUNCTION__));
if (gpio_direction_output(wlan_reg_on, 1)) {
printk(KERN_ERR "%s: WL_REG_ON is failed to pull up\n", __FUNCTION__);
DHD_ERROR(("%s: WL_REG_ON is failed to pull up\n", __FUNCTION__));
return -EIO;
}
}
printk(KERN_ERR "%s: WL_REG_ON is pulled up\n", __FUNCTION__);
/* Wait for WIFI_TURNON_DELAY due to power stability */
msleep(WIFI_TURNON_DELAY);
/* ========== WLAN_HOST_WAKE ============ */
printk(KERN_INFO "%s: gpio_wlan_host_wake : %d\n", __FUNCTION__, wlan_host_wake_up);
DHD_INFO(("%s: gpio_wlan_host_wake : %d\n", __FUNCTION__, wlan_host_wake_up));
if (gpio_request_one(wlan_host_wake_up, GPIOF_IN, "WLAN_HOST_WAKE")) {
printk(KERN_ERR "%s: Failed to request gpio %d for WLAN_HOST_WAKE\n",
__FUNCTION__, wlan_host_wake_up);
DHD_ERROR(("%s: Failed to request gpio %d for WLAN_HOST_WAKE\n",
__FUNCTION__, wlan_host_wake_up));
return -ENODEV;
} else {
printk(KERN_ERR "%s: gpio_request WLAN_HOST_WAKE done"
DHD_ERROR(("%s: gpio_request WLAN_HOST_WAKE done"
" - WLAN_HOST_WAKE: GPIO %d\n",
__FUNCTION__, wlan_host_wake_up);
__FUNCTION__, wlan_host_wake_up));
}
if (gpio_direction_input(wlan_host_wake_up)) {
printk(KERN_ERR "%s: Failed to set WL_HOST_WAKE gpio direction\n", __FUNCTION__);
DHD_ERROR(("%s: Failed to set WL_HOST_WAKE gpio direction\n", __FUNCTION__));
return -EIO;
}
wlan_host_wake_irq = gpio_to_irq(wlan_host_wake_up);
@@ -133,27 +133,26 @@ dhd_wifi_init_gpio(void)
extern void kirin_pcie_power_on_atu_fixup(void) __attribute__ ((weak));
extern int kirin_pcie_lp_ctrl(u32 enable) __attribute__ ((weak));
#ifndef BOARD_HIKEY_MODULAR
int
dhd_wlan_power(int onoff)
{
printk(KERN_INFO"------------------------------------------------");
printk(KERN_INFO"------------------------------------------------\n");
printk(KERN_INFO"%s Enter: power %s\n", __func__, onoff ? "on" : "off");
DHD_INFO(("------------------------------------------------"));
DHD_INFO(("------------------------------------------------\n"));
DHD_INFO(("%s Enter: power %s\n", __func__, onoff ? "on" : "off"));
if (onoff) {
if (gpio_direction_output(wlan_reg_on, 1)) {
printk(KERN_ERR "%s: WL_REG_ON is failed to pull up\n", __FUNCTION__);
DHD_ERROR(("%s: WL_REG_ON is failed to pull up\n", __FUNCTION__));
return -EIO;
}
if (gpio_get_value(wlan_reg_on)) {
printk(KERN_INFO"WL_REG_ON on-step-2 : [%d]\n",
gpio_get_value(wlan_reg_on));
DHD_INFO(("WL_REG_ON on-step-2 : [%d]\n",
gpio_get_value(wlan_reg_on)));
} else {
printk("[%s] gpio value is 0. We need reinit.\n", __func__);
DHD_ERROR(("[%s] gpio value is 0. We need reinit.\n", __func__));
if (gpio_direction_output(wlan_reg_on, 1)) {
printk(KERN_ERR "%s: WL_REG_ON is "
"failed to pull up\n", __func__);
DHD_ERROR(("%s: WL_REG_ON is "
"failed to pull up\n", __func__));
}
}
@@ -167,37 +166,36 @@ dhd_wlan_power(int onoff)
if (kirin_pcie_power_on_atu_fixup) {
kirin_pcie_power_on_atu_fixup();
} else {
printk(KERN_ERR "[%s] kirin_pcie_power_on_atu_fixup is NULL. "
"REG_ON may not work\n", __func__);
DHD_ERROR(("[%s] kirin_pcie_power_on_atu_fixup is NULL. "
"REG_ON may not work\n", __func__));
}
/* Enable ASPM after powering ON */
if (kirin_pcie_lp_ctrl) {
kirin_pcie_lp_ctrl(onoff);
} else {
printk(KERN_ERR "[%s] kirin_pcie_lp_ctrl is NULL. "
"ASPM may not work\n", __func__);
DHD_ERROR(("[%s] kirin_pcie_lp_ctrl is NULL. "
"ASPM may not work\n", __func__));
}
} else {
/* Disable ASPM before powering off */
if (kirin_pcie_lp_ctrl) {
kirin_pcie_lp_ctrl(onoff);
} else {
printk(KERN_ERR "[%s] kirin_pcie_lp_ctrl is NULL. "
"ASPM may not work\n", __func__);
DHD_ERROR(("[%s] kirin_pcie_lp_ctrl is NULL. "
"ASPM may not work\n", __func__));
}
if (gpio_direction_output(wlan_reg_on, 0)) {
printk(KERN_ERR "%s: WL_REG_ON is failed to pull up\n", __FUNCTION__);
DHD_ERROR(("%s: WL_REG_ON is failed to pull up\n", __FUNCTION__));
return -EIO;
}
if (gpio_get_value(wlan_reg_on)) {
printk(KERN_INFO"WL_REG_ON on-step-2 : [%d]\n",
gpio_get_value(wlan_reg_on));
DHD_INFO(("WL_REG_ON on-step-2 : [%d]\n",
gpio_get_value(wlan_reg_on)));
}
}
return 0;
}
EXPORT_SYMBOL(dhd_wlan_power);
#endif /* BOARD_HIKEY_MODULAR */
static int
dhd_wlan_reset(int onoff)
@@ -238,17 +236,15 @@ struct resource dhd_wlan_resources = {
EXPORT_SYMBOL(dhd_wlan_resources);
struct wifi_platform_data dhd_wlan_control = {
#ifndef BOARD_HIKEY_MODULAR
.set_power = dhd_wlan_power,
#endif /* BOARD_HIKEY_MODULAR */
.set_reset = dhd_wlan_reset,
.set_carddetect = dhd_wlan_set_carddetect,
#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
.mem_prealloc = dhd_wlan_mem_prealloc,
#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
#ifdef BCMSDIO
.get_wake_irq = dhd_wlan_get_wake_irq,
#endif // endif
.get_wake_irq = dhd_wlan_get_wake_irq,
#endif
};
EXPORT_SYMBOL(dhd_wlan_control);
@@ -257,11 +253,11 @@ dhd_wlan_init(void)
{
int ret;
printk(KERN_INFO"%s: START.......\n", __FUNCTION__);
DHD_INFO(("%s: START.......\n", __FUNCTION__));
ret = dhd_wifi_init_gpio();
if (ret < 0) {
printk(KERN_ERR "%s: failed to initiate GPIO, ret=%d\n",
__FUNCTION__, ret);
DHD_ERROR(("%s: failed to initiate GPIO, ret=%d\n",
__FUNCTION__, ret));
goto fail;
}
@@ -269,15 +265,15 @@ dhd_wlan_init(void)
dhd_wlan_resources.end = wlan_host_wake_irq;
#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
ret = dhd_init_wlan_mem();
if (ret < 0) {
printk(KERN_ERR "%s: failed to alloc reserved memory,"
" ret=%d\n", __FUNCTION__, ret);
}
ret = dhd_init_wlan_mem();
if (ret < 0) {
DHD_ERROR(("%s: failed to alloc reserved memory,"
" ret=%d\n", __FUNCTION__, ret));
}
#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
fail:
printk(KERN_INFO"%s: FINISH.......\n", __FUNCTION__);
DHD_INFO(("%s: FINISH.......\n", __FUNCTION__));
return ret;
}
@@ -288,7 +284,7 @@ dhd_wlan_deinit(void)
gpio_free(wlan_reg_on);
return 0;
}
#ifndef BOARD_HIKEY_MODULAR
#ifndef BCMDHD_MODULAR
/* Required only for Built-in DHD */
device_initcall(dhd_wlan_init);
#endif /* BOARD_HIKEY_MODULAR */

View File

@@ -1,14 +1,14 @@
/*
* Platform Dependent file for usage of Preallocted Memory
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,14 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_custom_memprealloc.c 707595 2017-06-28 08:28:30Z $
* $Id$
*/
#include <linux/device.h>
@@ -54,20 +51,14 @@
#define WLAN_STATIC_DHD_LOG_DUMP_BUF 15
#define WLAN_STATIC_DHD_LOG_DUMP_BUF_EX 16
#define WLAN_STATIC_DHD_PKTLOG_DUMP_BUF 17
#define WLAN_STATIC_STAT_REPORT_BUF 18
#define WLAN_SCAN_BUF_SIZE (64 * 1024)
#if defined(CONFIG_64BIT)
#define WLAN_DHD_INFO_BUF_SIZE (32 * 1024)
#define WLAN_DHD_INFO_BUF_SIZE (64 * 1024)
#define WLAN_DHD_WLFC_BUF_SIZE (64 * 1024)
#define WLAN_DHD_IF_FLOW_LKUP_SIZE (64 * 1024)
#else
#define WLAN_DHD_INFO_BUF_SIZE (32 * 1024)
#define WLAN_DHD_WLFC_BUF_SIZE (16 * 1024)
#define WLAN_DHD_IF_FLOW_LKUP_SIZE (20 * 1024)
#endif /* CONFIG_64BIT */
#define WLAN_DHD_MEMDUMP_SIZE (1536 * 1024)
/* Have 2MB ramsize to accomodate future chips */
#define WLAN_DHD_MEMDUMP_SIZE (3 * 1024 * 1024)
#define PREALLOC_WLAN_SEC_NUM 4
#define PREALLOC_WLAN_BUF_NUM 160
@@ -84,7 +75,7 @@
#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_BUF_NUM * 1024)
#define DHD_SKB_1PAGE_BUF_NUM 0
#define DHD_SKB_2PAGE_BUF_NUM 128
#define DHD_SKB_2PAGE_BUF_NUM 192
#define DHD_SKB_4PAGE_BUF_NUM 0
#else
@@ -120,13 +111,11 @@
#define WLAN_DHD_PKTID_IOCTL_MAP_SIZE ((WLAN_DHD_PKTID_IOCTL_MAP_HDR_SIZE) + \
((WLAN_MAX_PKTID_IOCTL_ITEMS+1) * WLAN_DHD_PKTID_IOCTL_MAP_ITEM_SIZE))
#define DHD_LOG_DUMP_BUF_SIZE (1024 * 1024)
#define DHD_LOG_DUMP_BUF_EX_SIZE (8 * 1024)
#define DHD_LOG_DUMP_BUF_SIZE (1024 * 1024 * 4)
#define DHD_LOG_DUMP_BUF_EX_SIZE (1024 * 1024 * 2)
#define DHD_PKTLOG_DUMP_BUF_SIZE (64 * 1024)
#define DHD_STAT_REPORT_BUF_SIZE (128 * 1024)
#define WLAN_DHD_WLFC_HANGER_MAXITEMS 3072
#define WLAN_DHD_WLFC_HANGER_ITEM_SIZE 32
#define WLAN_DHD_WLFC_HANGER_SIZE ((WLAN_DHD_WLFC_HANGER_ITEM_SIZE) + \
@@ -158,18 +147,8 @@ static void *wlan_static_dhd_pktid_ioctl_map = NULL;
static void *wlan_static_dhd_log_dump_buf = NULL;
static void *wlan_static_dhd_log_dump_buf_ex = NULL;
static void *wlan_static_dhd_pktlog_dump_buf = NULL;
static void *wlan_static_stat_report_buf = NULL;
#define GET_STATIC_BUF(section, config_size, req_size, buf) ({\
void *__ret; \
if (req_size > config_size) {\
pr_err("request " #section " size(%lu) is bigger than" \
" static size(%d)\n", \
req_size, config_size); \
__ret = NULL; \
} else { __ret = buf;} \
__ret; \
})
void dhd_exit_wlan_mem(void);
void
*dhd_wlan_mem_prealloc(int section, unsigned long size)
@@ -246,7 +225,6 @@ void
return wlan_static_dhd_pktid_map;
}
if (section == WLAN_STATIC_DHD_PKTID_IOCTL_MAP) {
if (size > WLAN_DHD_PKTID_IOCTL_MAP_SIZE) {
pr_err("request DHD_PKTID_IOCTL_MAP size(%lu) is bigger than"
@@ -287,11 +265,6 @@ void
return wlan_static_dhd_pktlog_dump_buf;
}
if (section == WLAN_STATIC_STAT_REPORT_BUF) {
return GET_STATIC_BUF(WLAN_STATIC_STAT_REPORT_BUF,
DHD_STAT_REPORT_BUF_SIZE, size, wlan_static_stat_report_buf);
}
if ((section < 0) || (section >= PREALLOC_WLAN_SEC_NUM)) {
return NULL;
}
@@ -310,23 +283,28 @@ dhd_init_wlan_mem(void)
int i;
int j;
#if !defined(CONFIG_BCMDHD_PCIE)
for (i = 0; i < DHD_SKB_1PAGE_BUF_NUM; i++) {
wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_1PAGE_BUFSIZE);
wlan_static_skb[i] = __dev_alloc_skb(DHD_SKB_1PAGE_BUFSIZE, GFP_KERNEL);
if (!wlan_static_skb[i]) {
pr_err("Failed to alloc 1PAGE SKB BUF\n");
goto err_skb_alloc;
}
}
#endif /* !CONFIG_BCMDHD_PCIE */
for (i = DHD_SKB_1PAGE_BUF_NUM; i < WLAN_SKB_1_2PAGE_BUF_NUM; i++) {
wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_2PAGE_BUFSIZE);
wlan_static_skb[i] = __dev_alloc_skb(DHD_SKB_2PAGE_BUFSIZE, GFP_KERNEL);
if (!wlan_static_skb[i]) {
pr_err("Failed to alloc 2PAGE SKB BUF\n");
goto err_skb_alloc;
}
}
#if !defined(CONFIG_BCMDHD_PCIE)
wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_4PAGE_BUFSIZE);
wlan_static_skb[i] = __dev_alloc_skb(DHD_SKB_4PAGE_BUFSIZE, GFP_KERNEL);
if (!wlan_static_skb[i]) {
pr_err("Failed to alloc 4PAGE SKB BUF\n");
goto err_skb_alloc;
}
#endif /* !CONFIG_BCMDHD_PCIE */
@@ -337,6 +315,7 @@ dhd_init_wlan_mem(void)
kmalloc(wlan_mem_array[i].size, GFP_KERNEL);
if (!wlan_mem_array[i].mem_ptr) {
pr_err("Failed to mem_alloc for WLAN\n");
goto err_mem_alloc;
}
}
@@ -425,16 +404,32 @@ dhd_init_wlan_mem(void)
goto err_mem_alloc;
}
wlan_static_stat_report_buf = kmalloc(DHD_STAT_REPORT_BUF_SIZE, GFP_KERNEL);
if (!wlan_static_stat_report_buf) {
pr_err("Failed to alloc wlan_static_stat_report_buf\n");
goto err_mem_alloc;
}
pr_err("%s: WIFI MEM Allocated\n", __FUNCTION__);
return 0;
err_mem_alloc:
dhd_exit_wlan_mem();
return -ENOMEM;
err_skb_alloc:
/*
* When all the skb alloc buf couldn't alloced, free these buf with alloced size
* dhd_exit_wlan_mem will free with total size (don't know alloced size)
*/
pr_err("Failed to skb_alloc for WLAN\n");
for (j = 0; j < i; j++) {
dev_kfree_skb(wlan_static_skb[j]);
}
return -ENOMEM;
}
EXPORT_SYMBOL(dhd_init_wlan_mem);
void
dhd_exit_wlan_mem(void)
{
int i = 0;
#ifdef CONFIG_BCMDHD_PREALLOC_MEMDUMP
if (wlan_static_dhd_memdump_ram) {
kfree(wlan_static_dhd_memdump_ram);
@@ -489,25 +484,17 @@ err_mem_alloc:
kfree(wlan_static_dhd_pktlog_dump_buf);
}
if (wlan_static_stat_report_buf) {
kfree(wlan_static_stat_report_buf);
for (i = 0; i < PREALLOC_WLAN_SEC_NUM; i++) {
if (wlan_mem_array[i].mem_ptr) {
kfree(wlan_mem_array[i].mem_ptr);
}
}
pr_err("Failed to mem_alloc for WLAN\n");
for (j = 0; j < i; j++) {
kfree(wlan_mem_array[j].mem_ptr);
for (i = 0; i < WLAN_SKB_BUF_NUM; i++) {
dev_kfree_skb(wlan_static_skb[i]);
}
i = WLAN_SKB_BUF_NUM;
err_skb_alloc:
pr_err("Failed to skb_alloc for WLAN\n");
for (j = 0; j < i; j++) {
dev_kfree_skb(wlan_static_skb[j]);
}
return -ENOMEM;
return;
}
EXPORT_SYMBOL(dhd_init_wlan_mem);
EXPORT_SYMBOL(dhd_exit_wlan_mem);
#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */

View File

@@ -1,14 +1,14 @@
/*
* Platform Dependent file for Qualcomm MSM/APQ
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,14 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_custom_msm.c 674523 2016-12-09 04:05:27Z $
* $Id$
*
*/
@@ -34,17 +31,17 @@
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/skbuff.h>
#include <linux/wlan_plat.h>
#include <linux/mmc/host.h>
#ifdef CONFIG_BCMDHD_PCIE
#include <linux/msm_pcie.h>
#endif /* CONFIG_BCMDHD_PCIE */
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/of_gpio.h>
#if defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_ARCH_MSM8998)
#include <linux/msm_pcie.h>
#endif /* CONFIG_ARCH_MSM8996 || CONFIG_ARCH_MSM8998 */
#include <linux/wlan_plat.h>
#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
extern void dhd_exit_wlan_mem(void);
extern int dhd_init_wlan_mem(void);
extern void *dhd_wlan_mem_prealloc(int section, unsigned long size);
#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
@@ -58,11 +55,13 @@ static int wlan_reg_on = -1;
#define WIFI_WL_REG_ON_PROPNAME "wlan-en-gpio"
#endif /* CUSTOMER_HW2 */
#if defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_ARCH_MSM8998)
#if defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_ARCH_MSM8998) || \
defined(CONFIG_ARCH_SDM845) || defined(CONFIG_ARCH_SM8150) || \
defined(CONFIG_ARCH_KONA) || defined(CONFIG_ARCH_LAHAINA)
#define MSM_PCIE_CH_NUM 0
#else
#define MSM_PCIE_CH_NUM 1
#endif /* CONFIG_ARCH_MSM8996 || CONFIG_ARCH_MSM8998 */
#endif /* MSM PCIE Platforms */
#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE
static int wlan_host_wake_up = -1;
@@ -119,7 +118,7 @@ dhd_wifi_init_gpio(void)
#ifndef CUSTOMER_HW2
if (gpio_request_one(wlan_host_wake_up, GPIOF_IN, "WLAN_HOST_WAKE")) {
printk(KERN_ERR "%s: Failed to request gpio %d for WLAN_HOST_WAKE\n",
printk(KERN_ERR "%s: Faiiled to request gpio %d for WLAN_HOST_WAKE\n",
__FUNCTION__, wlan_host_wake_up);
return -ENODEV;
} else {
@@ -133,10 +132,10 @@ dhd_wifi_init_gpio(void)
wlan_host_wake_irq = gpio_to_irq(wlan_host_wake_up);
#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */
#if defined(CONFIG_BCM4359) || defined(CONFIG_BCM4361)
#ifdef CONFIG_BCMDHD_PCIE
printk(KERN_INFO "%s: Call msm_pcie_enumerate\n", __FUNCTION__);
msm_pcie_enumerate(MSM_PCIE_CH_NUM);
#endif /* CONFIG_BCM4359 || CONFIG_BCM4361 */
#endif /* CONFIG_BCMDHD_PCIE */
return 0;
}
@@ -144,8 +143,6 @@ dhd_wifi_init_gpio(void)
int
dhd_wlan_power(int onoff)
{
printk(KERN_INFO"------------------------------------------------");
printk(KERN_INFO"------------------------------------------------\n");
printk(KERN_INFO"%s Enter: power %s\n", __func__, onoff ? "on" : "off");
if (onoff) {
@@ -186,9 +183,23 @@ dhd_wlan_reset(int onoff)
static int
dhd_wlan_set_carddetect(int val)
{
#ifdef CONFIG_BCMDHD_PCIE
printk(KERN_INFO "%s: Call msm_pcie_enumerate\n", __FUNCTION__);
msm_pcie_enumerate(MSM_PCIE_CH_NUM);
#endif /* CONFIG_BCMDHD_PCIE */
return 0;
}
#if defined(CONFIG_BCMDHD_OOB_HOST_WAKE) && defined(CONFIG_BCMDHD_GET_OOB_STATE)
int
dhd_get_wlan_oob_gpio(void)
{
return gpio_is_valid(wlan_host_wake_up) ?
gpio_get_value(wlan_host_wake_up) : -1;
}
EXPORT_SYMBOL(dhd_get_wlan_oob_gpio);
#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE && CONFIG_BCMDHD_GET_OOB_STATE */
struct resource dhd_wlan_resources = {
.name = "bcmdhd_wlan_irq",
.start = 0, /* Dummy */
@@ -242,7 +253,25 @@ fail:
printk(KERN_INFO"%s: FINISH.......\n", __FUNCTION__);
return ret;
}
#if defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_ARCH_MSM8998)
int
dhd_wlan_deinit(void)
{
#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE
gpio_free(wlan_host_wake_up);
#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */
gpio_free(wlan_reg_on);
#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
dhd_exit_wlan_mem();
#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
return 0;
}
#ifndef BCMDHD_MODULAR
#if defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_ARCH_MSM8998) || \
defined(CONFIG_ARCH_SDM845) || defined(CONFIG_ARCH_SM8150) || \
defined(CONFIG_ARCH_KONA) || defined(CONFIG_ARCH_LAHAINA)
#if defined(CONFIG_DEFERRED_INITCALLS)
deferred_module_init(dhd_wlan_init);
#else
@@ -250,4 +279,5 @@ late_initcall(dhd_wlan_init);
#endif /* CONFIG_DEFERRED_INITCALLS */
#else
device_initcall(dhd_wlan_init);
#endif /* CONFIG_ARCH_MSM8996 || CONFIG_ARCH_MSM8998 */
#endif /* MSM PCIE Platforms */
#endif /* !BCMDHD_MODULAR */

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,14 @@
/*
* Debug/trace/assert driver definitions for Dongle Host Driver.
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,72 +16,328 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_dbg.h 667145 2016-10-26 04:27:53Z $
* $Id$
*/
#ifndef _dhd_dbg_
#define _dhd_dbg_
#if defined(DHD_EFI) && defined(DHD_LOG_DUMP)
extern void dhd_log_dump_print(const char *fmt, ...);
extern void dhd_log_dump_print_drv(const char *fmt, ...);
#endif
#if defined(DHD_DEBUG)
#if defined(NDIS)
#include "wl_nddbg.h"
#endif /* defined(NDIS) */
#ifdef DHD_LOG_DUMP
extern void dhd_log_dump_write(int type, const char *fmt, ...);
extern char *dhd_log_dump_get_timestamp(void);
#ifdef DHD_EFI
/* FW verbose/console output to FW ring buffer */
extern void dhd_log_dump_print(const char *fmt, ...);
/* DHD verbose/console output to DHD ring buffer */
extern void dhd_log_dump_print_drv(const char *fmt, ...);
#define DHD_LOG_DUMP_WRITE(fmt, ...) dhd_log_dump_print_drv(fmt, ##__VA_ARGS__)
#define DHD_LOG_DUMP_WRITE_FW(fmt, ...) dhd_log_dump_print(fmt, ##__VA_ARGS__)
#else
#ifndef _DHD_LOG_DUMP_DEFINITIONS_
#define _DHD_LOG_DUMP_DEFINITIONS_
#define DLD_BUF_TYPE_GENERAL 0
#define DLD_BUF_TYPE_SPECIAL 1
#define DHD_LOG_DUMP_WRITE(fmt, ...) dhd_log_dump_write(DLD_BUF_TYPE_GENERAL, fmt, ##__VA_ARGS__)
#define DHD_LOG_DUMP_WRITE_EX(fmt, ...) dhd_log_dump_write(DLD_BUF_TYPE_SPECIAL, fmt, ##__VA_ARGS__)
#define GENERAL_LOG_HDR "\n-------------------- General log ---------------------------\n"
#define PRESERVE_LOG_HDR "\n-------------------- Preserve log ---------------------------\n"
#define SPECIAL_LOG_HDR "\n-------------------- Special log ---------------------------\n"
#define DHD_DUMP_LOG_HDR "\n-------------------- 'dhd dump' log -----------------------\n"
#define EXT_TRAP_LOG_HDR "\n-------------------- Extended trap data -------------------\n"
#define HEALTH_CHK_LOG_HDR "\n-------------------- Health check data --------------------\n"
#ifdef DHD_DUMP_PCIE_RINGS
#define FLOWRING_DUMP_HDR "\n-------------------- Flowring dump --------------------\n"
#endif /* DHD_DUMP_PCIE_RINGS */
#define DHD_LOG_DUMP_DLD(fmt, ...) \
dhd_log_dump_write(DLD_BUF_TYPE_GENERAL, NULL, 0, fmt, ##__VA_ARGS__)
#define DHD_LOG_DUMP_DLD_EX(fmt, ...) \
dhd_log_dump_write(DLD_BUF_TYPE_SPECIAL, NULL, 0, fmt, ##__VA_ARGS__)
#define DHD_LOG_DUMP_DLD_PRSRV(fmt, ...) \
dhd_log_dump_write(DLD_BUF_TYPE_PRESERVE, NULL, 0, fmt, ##__VA_ARGS__)
#endif /* !_DHD_LOG_DUMP_DEFINITIONS_ */
#ifndef DHD_LOG_DUMP_RING_DEFINITIONS
#define DHD_LOG_DUMP_RING_DEFINITIONS
#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING
/* Enabled DHD_DEBUGABILITY_LOG_DUMP_RING */
extern void dhd_dbg_ring_write(int type, char *binary_data,
int binary_len, const char *fmt, ...);
extern char* dhd_dbg_get_system_timestamp(void);
#define DHD_DBG_RING(fmt, ...) \
dhd_dbg_ring_write(DRIVER_LOG_RING_ID, NULL, 0, fmt, ##__VA_ARGS__)
#define DHD_DBG_RING_EX(fmt, ...) \
dhd_dbg_ring_write(FW_VERBOSE_RING_ID, NULL, 0, fmt, ##__VA_ARGS__)
#define DHD_DBG_RING_ROAM(fmt, ...) \
dhd_dbg_ring_write(ROAM_STATS_RING_ID, NULL, 0, fmt, ##__VA_ARGS__)
#define DHD_LOG_DUMP_WRITE DHD_DBG_RING
#define DHD_LOG_DUMP_WRITE_EX DHD_DBG_RING_EX
#define DHD_LOG_DUMP_WRITE_PRSRV DHD_DBG_RING
#define DHD_LOG_DUMP_WRITE_ROAM DHD_DBG_RING_ROAM
#define DHD_PREFIX_TS "[%s][%s]: ", dhd_dbg_get_system_timestamp(), dhd_log_dump_get_timestamp()
#define DHD_PREFIX_TS_FN DHD_PREFIX_TS
#define DHD_LOG_DUMP_WRITE_TS DHD_DBG_RING(DHD_PREFIX_TS)
#define DHD_LOG_DUMP_WRITE_TS_FN DHD_DBG_RING(DHD_PREFIX_TS_FN)
#define DHD_LOG_DUMP_WRITE_EX_TS DHD_DBG_RING_EX(DHD_PREFIX_TS)
#define DHD_LOG_DUMP_WRITE_EX_TS_FN DHD_DBG_RING_EX(DHD_PREFIX_TS_FN)
#define DHD_LOG_DUMP_WRITE_PRSRV_TS DHD_DBG_RING(DHD_PREFIX_TS)
#define DHD_LOG_DUMP_WRITE_PRSRV_TS_FN DHD_DBG_RING(DHD_PREFIX_TS_FN)
#define DHD_LOG_DUMP_WRITE_ROAM_TS DHD_DBG_RING_ROAM(DHD_PREFIX_TS)
#define DHD_LOG_DUMP_WRITE_ROAM_TS_FN DHD_DBG_RING_ROAM(DHD_PREFIX_TS_FN)
#else
/* Not enabled DHD_DEBUGABILITY_LOG_DUMP_RING */
#define DHD_LOG_DUMP_WRITE DHD_LOG_DUMP_DLD
#define DHD_LOG_DUMP_WRITE_EX DHD_LOG_DUMP_DLD_EX
#define DHD_LOG_DUMP_WRITE_PRSRV DHD_LOG_DUMP_DLD_PRSRV
#define DHD_LOG_DUMP_WRITE_ROAM DHD_LOG_DUMP_DLD
#define DHD_PREFIX_TS "[%s]: ", dhd_log_dump_get_timestamp()
#define DHD_PREFIX_TS_FN "[%s] %s: ", dhd_log_dump_get_timestamp(), __func__
#define DHD_LOG_DUMP_WRITE_TS DHD_LOG_DUMP_DLD(DHD_PREFIX_TS)
#define DHD_LOG_DUMP_WRITE_TS_FN DHD_LOG_DUMP_DLD(DHD_PREFIX_TS_FN)
#define DHD_LOG_DUMP_WRITE_EX_TS DHD_LOG_DUMP_DLD_EX(DHD_PREFIX_TS)
#define DHD_LOG_DUMP_WRITE_EX_TS_FN DHD_LOG_DUMP_DLD_EX(DHD_PREFIX_TS_FN)
#define DHD_LOG_DUMP_WRITE_PRSRV_TS DHD_LOG_DUMP_DLD_PRSRV(DHD_PREFIX_TS)
#define DHD_LOG_DUMP_WRITE_PRSRV_TS_FN DHD_LOG_DUMP_DLD_PRSRV(DHD_PREFIX_TS_FN)
#define DHD_LOG_DUMP_WRITE_ROAM_TS DHD_LOG_DUMP_DLD(DHD_PREFIX_TS)
#define DHD_LOG_DUMP_WRITE_ROAM_TS_FN DHD_LOG_DUMP_DLD(DHD_PREFIX_TS_FN)
#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
#endif /* DHD_LOG_DUMP_RING_DEFINITIONS */
#endif /* DHD_EFI */
#define CONCISE_DUMP_BUFLEN 32 * 1024
#define ECNTRS_LOG_HDR "\n-------------------- Ecounters log --------------------------\n"
#ifdef DHD_STATUS_LOGGING
#define STATUS_LOG_HDR "\n-------------------- Status log -----------------------\n"
#endif /* DHD_STATUS_LOGGING */
#define RTT_LOG_HDR "\n-------------------- RTT log --------------------------\n"
#define BCM_TRACE_LOG_HDR "\n-------------------- BCM Trace log --------------------------\n"
#define COOKIE_LOG_HDR "\n-------------------- Cookie List ----------------------------\n"
#endif /* DHD_LOG_DUMP */
#if defined(CUSTOMER_DBG_SYSTEM_TIME) && defined(DHD_DEBUGABILITY_LOG_DUMP_RING)
#define DBG_PRINT_PREFIX "[%s][dhd] ", dhd_dbg_get_system_timestamp()
#else
#define DBG_PRINT_PREFIX "[dhd] "
#endif
#define DBG_PRINT_SYSTEM_TIME pr_cont(DBG_PRINT_PREFIX)
#if defined(BCMDBG) || defined(DHD_DEBUG)
#if defined(NDIS)
#define DHD_ERROR(args) do {if (dhd_msg_level & DHD_ERROR_VAL) \
{printf args; DHD_NDDBG_OUTPUT args;}} while (0)
#define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) \
{printf args; DHD_NDDBG_OUTPUT args;}} while (0)
#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) \
{printf args; DHD_NDDBG_OUTPUT args;}} while (0)
#define DHD_ERROR_ROAM(args) DHD_ERROR(args)
#else
/* NON-NDIS cases */
#ifdef DHD_LOG_DUMP
#ifdef DHD_EFI
/* defined(DHD_EFI) && defined(DHD_LOG_DUMP) */
#define DHD_ERROR(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
printf args; \
dhd_log_dump_print_drv("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \
dhd_log_dump_print_drv args; \
DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_INFO(args) \
do { \
if (dhd_msg_level & DHD_INFO_VAL) { \
printf args; \
dhd_log_dump_print_drv("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \
dhd_log_dump_print_drv args; \
} \
} while (0)
#else /* DHD_EFI */
#define DHD_ERROR(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
printf args; \
DHD_LOG_DUMP_WRITE("[%s] %s: ", dhd_log_dump_get_timestamp(), __func__); \
DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#else /* DHD_EFI */
/* !defined(DHD_EFI) and defined(DHD_LOG_DUMP) */
#define DHD_ERROR(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
DBG_PRINT_SYSTEM_TIME; \
pr_cont args; \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0)
#endif /* DHD_EFI */
#else /* DHD_LOG_DUMP */
/* !defined(DHD_LOG_DUMP cases) */
#define DHD_ERROR(args) do {if (dhd_msg_level & DHD_ERROR_VAL) printf args;} while (0)
#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0)
#define DHD_ERROR_ROAM(args) DHD_ERROR(args)
#endif /* DHD_LOG_DUMP */
#define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) printf args;} while (0)
#endif /* defined(NDIS) */
#ifdef DHD_LOG_DUMP
/* LOG_DUMP defines common to EFI and NON-EFI */
#ifdef DHD_EFI
/* EFI builds with LOG DUMP enabled */
#define DHD_ERROR_MEM(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
if (dhd_msg_level & DHD_ERROR_MEM_VAL) { \
printf args; \
} \
DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_IOVAR_MEM(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
if (dhd_msg_level & DHD_IOVAR_MEM_VAL) { \
printf args; \
} \
DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_LOG_MEM(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_EVENT(args) \
do { \
if (dhd_msg_level & DHD_EVENT_VAL) { \
DHD_LOG_DUMP_WRITE_FW("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE_FW args; \
} \
} while (0)
#define DHD_ECNTR_LOG(args) DHD_EVENT(args)
#define DHD_ERROR_EX(args) DHD_ERROR(args)
#define DHD_ERROR_ROAM(args) DHD_ERROR(args)
#define DHD_MSGTRACE_LOG(args) \
do { \
if (dhd_msg_level & DHD_MSGTRACE_VAL) { \
DHD_LOG_DUMP_WRITE_FW("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE_FW args; \
} \
} while (0)
#define DHD_PRSRV_MEM(args) DHD_EVENT(args)
#else
/* NON-EFI builds with LOG DUMP enabled */
#define DHD_ERROR_MEM(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
if (dhd_msg_level & DHD_ERROR_MEM_VAL) { \
DBG_PRINT_SYSTEM_TIME; \
pr_cont args; \
} \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_IOVAR_MEM(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
if (dhd_msg_level & DHD_IOVAR_MEM_VAL) { \
DBG_PRINT_SYSTEM_TIME; \
pr_cont args; \
} \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_LOG_MEM(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_EVENT(args) \
do { \
if (dhd_msg_level & DHD_EVENT_VAL) { \
DBG_PRINT_SYSTEM_TIME; \
pr_cont args; \
DHD_LOG_DUMP_WRITE_PRSRV_TS; \
DHD_LOG_DUMP_WRITE_PRSRV args; \
} \
} while (0)
#define DHD_PRSRV_MEM(args) \
do { \
if (dhd_msg_level & DHD_EVENT_VAL) { \
if (dhd_msg_level & DHD_PRSRV_MEM_VAL) { \
DBG_PRINT_SYSTEM_TIME; \
printf args; \
} \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
/* Re-using 'DHD_MSGTRACE_VAL' for controlling printing of ecounter binary event
* logs to console and debug dump -- need to cleanup in the future to use separate
* 'DHD_ECNTR_VAL' bitmap flag. 'DHD_MSGTRACE_VAL' will be defined only
* for non-android builds.
*/
#define DHD_ECNTR_LOG(args) \
do { \
if (dhd_msg_level & DHD_EVENT_VAL) { \
if (dhd_msg_level & DHD_MSGTRACE_VAL) { \
DBG_PRINT_SYSTEM_TIME; \
pr_cont args; \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} \
} while (0)
#define DHD_ERROR_EX(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
DBG_PRINT_SYSTEM_TIME; \
pr_cont args; \
DHD_LOG_DUMP_WRITE_EX_TS; \
DHD_LOG_DUMP_WRITE_EX args; \
} \
} while (0)
#define DHD_MSGTRACE_LOG(args) \
do { \
if (dhd_msg_level & DHD_MSGTRACE_VAL) { \
DBG_PRINT_SYSTEM_TIME; \
pr_cont args; \
} \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} while (0)
#define DHD_ERROR_ROAM(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
DBG_PRINT_SYSTEM_TIME; \
pr_cont args; \
DHD_LOG_DUMP_WRITE_ROAM_TS; \
DHD_LOG_DUMP_WRITE_ROAM args; \
} \
} while (0)
#endif /* DHD_EFI */
#else /* DHD_LOG_DUMP */
/* !DHD_LOG_DUMP */
#define DHD_MSGTRACE_LOG(args) do {if (dhd_msg_level & DHD_MSGTRACE_VAL) printf args;} while (0)
#define DHD_ERROR_MEM(args) DHD_ERROR(args)
#define DHD_IOVAR_MEM(args) DHD_ERROR(args)
#define DHD_LOG_MEM(args) DHD_ERROR(args)
#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0)
#define DHD_ECNTR_LOG(args) DHD_EVENT(args)
#define DHD_PRSRV_MEM(args) DHD_EVENT(args)
#define DHD_ERROR_EX(args) DHD_ERROR(args)
#define DHD_ERROR_ROAM(args) DHD_ERROR(args)
#endif /* DHD_LOG_DUMP */
#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0)
#define DHD_CTL(args) do {if (dhd_msg_level & DHD_CTL_VAL) printf args;} while (0)
@@ -90,106 +346,72 @@ do { \
#define DHD_BYTES(args) do {if (dhd_msg_level & DHD_BYTES_VAL) printf args;} while (0)
#define DHD_INTR(args) do {if (dhd_msg_level & DHD_INTR_VAL) printf args;} while (0)
#define DHD_GLOM(args) do {if (dhd_msg_level & DHD_GLOM_VAL) printf args;} while (0)
#ifdef DHD_LOG_DUMP
#ifndef DHD_EFI
#define DHD_EVENT(args) \
do { \
if (dhd_msg_level & DHD_EVENT_VAL) { \
printf args; \
DHD_LOG_DUMP_WRITE("[%s] %s: ", dhd_log_dump_get_timestamp(), __func__); \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#else
#define DHD_EVENT(args) \
do { \
if (dhd_msg_level & DHD_EVENT_VAL) { \
dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \
dhd_log_dump_print args; \
} \
} while (0)
#endif /* !DHD_EFI */
#else
#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0)
#endif /* DHD_LOG_DUMP */
#define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) printf args;} while (0)
#define DHD_ISCAN(args) do {if (dhd_msg_level & DHD_ISCAN_VAL) printf args;} while (0)
#define DHD_ARPOE(args) do {if (dhd_msg_level & DHD_ARPOE_VAL) printf args;} while (0)
#define DHD_REORDER(args) do {if (dhd_msg_level & DHD_REORDER_VAL) printf args;} while (0)
#define DHD_PNO(args) do {if (dhd_msg_level & DHD_PNO_VAL) printf args;} while (0)
#define DHD_RTT(args) do {if (dhd_msg_level & DHD_RTT_VAL) printf args;} while (0)
#define DHD_PKT_MON(args) do {if (dhd_msg_level & DHD_PKT_MON_VAL) printf args;} while (0)
#ifdef DHD_LOG_DUMP
#ifndef DHD_EFI
#define DHD_MSGTRACE_LOG(args) \
do { \
if (dhd_msg_level & DHD_MSGTRACE_VAL) { \
printf args; \
DHD_LOG_DUMP_WRITE("[%s] %s: ", dhd_log_dump_get_timestamp(), __func__); \
DHD_LOG_DUMP_WRITE args; \
} \
#if defined(DHD_LOG_DUMP)
#if defined(DHD_EFI)
#define DHD_FWLOG(args) DHD_MSGTRACE_LOG(args)
#elif defined(DHD_LOG_PRINT_RATE_LIMIT)
#define DHD_FW_VERBOSE(args) \
do { \
if (dbgring_msg_level & DHD_FWLOG_VAL) { \
DHD_LOG_DUMP_WRITE_EX args; \
} \
} while (0)
#define DHD_FWLOG(args) \
do { \
if (dhd_msg_level & DHD_FWLOG_VAL) { \
if (control_logtrace && !log_print_threshold) \
printf args; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#else
#define DHD_MSGTRACE_LOG(args) \
do { \
if (dhd_msg_level & DHD_MSGTRACE_VAL) { \
dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \
dhd_log_dump_print args; \
} \
#define DHD_FW_VERBOSE(args) \
do { \
if (dbgring_msg_level & DHD_FWLOG_VAL) { \
DHD_LOG_DUMP_WRITE_EX args; \
} \
} while (0)
#endif /* !DHD_EFI */
#define DHD_FWLOG(args) \
do { \
if (dhd_msg_level & DHD_FWLOG_VAL) { \
if (control_logtrace) \
printf args; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#endif /* DHD_EFI */
#else /* DHD_LOG_DUMP */
#if defined(NDIS) && (NDISVER >= 0x0630)
#define DHD_FWLOG(args) do {if (dhd_msg_level & DHD_FWLOG_VAL) \
{printf args; DHD_NDDBG_OUTPUT args;}} while (0)
#else
#define DHD_MSGTRACE_LOG(args) do {if (dhd_msg_level & DHD_MSGTRACE_VAL) printf args;} while (0)
#define DHD_FWLOG(args) do {if (dhd_msg_level & DHD_FWLOG_VAL) printf args;} while (0)
#endif /* defined(NDIS) && (NDISVER >= 0x0630) */
#endif /* DHD_LOG_DUMP */
#if defined(DHD_LOG_DUMP) && defined(DHD_EFI)
#define DHD_FWLOG(args) DHD_MSGTRACE_LOG(args)
#else
#define DHD_FWLOG(args) do {if (dhd_msg_level & DHD_FWLOG_VAL) printf args;} while (0)
#endif /* DHD_LOG_DUMP & DHD_EFI */
#define DHD_DBGIF(args) do {if (dhd_msg_level & DHD_DBGIF_VAL) printf args;} while (0)
#ifdef DHD_LOG_DUMP
#ifdef DHD_EFI
#define DHD_ERROR_MEM(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
dhd_log_dump_print_drv("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \
dhd_log_dump_print_drv args; \
} \
} while (0)
#define DHD_ERROR_EX(args) DHD_ERROR(args)
#else
#define DHD_ERROR_MEM(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
if (dhd_msg_level & DHD_ERROR_MEM_VAL) { \
printf args; \
} \
DHD_LOG_DUMP_WRITE("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_ERROR_EX(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
printf args; \
DHD_LOG_DUMP_WRITE_EX("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \
DHD_LOG_DUMP_WRITE_EX args; \
} \
} while (0)
#endif /* DHD_EFI */
#else
#define DHD_ERROR_MEM(args) DHD_ERROR(args)
#define DHD_ERROR_EX(args) DHD_ERROR(args)
#endif /* DHD_LOG_DUMP */
#ifdef DHD_PCIE_NATIVE_RUNTIMEPM
#define DHD_RPM(args) do {if (dhd_msg_level & DHD_RPM_VAL) printf args;} while (0)
#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
#ifdef CUSTOMER_HW4_DEBUG
#define DHD_TRACE_HW4 DHD_ERROR
#define DHD_INFO_HW4 DHD_ERROR
#define DHD_ERROR_NO_HW4 DHD_INFO
#else
#define DHD_TRACE_HW4 DHD_TRACE
#define DHD_INFO_HW4 DHD_INFO
#define DHD_ERROR_NO_HW4 DHD_ERROR
#endif /* CUSTOMER_HW4_DEBUG */
#define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL)
@@ -203,6 +425,7 @@ do { \
#define DHD_INTR_ON() (dhd_msg_level & DHD_INTR_VAL)
#define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL)
#define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL)
#define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL)
#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL)
#define DHD_ARPOE_ON() (dhd_msg_level & DHD_ARPOE_VAL)
#define DHD_REORDER_ON() (dhd_msg_level & DHD_REORDER_VAL)
@@ -214,36 +437,46 @@ do { \
#define DHD_DBGIF_ON() (dhd_msg_level & DHD_DBGIF_VAL)
#define DHD_PKT_MON_ON() (dhd_msg_level & DHD_PKT_MON_VAL)
#define DHD_PKT_MON_DUMP_ON() (dhd_msg_level & DHD_PKT_MON_DUMP_VAL)
#ifdef DHD_PCIE_NATIVE_RUNTIMEPM
#define DHD_RPM_ON() (dhd_msg_level & DHD_RPM_VAL)
#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
#else /* defined(BCMDBG) || defined(DHD_DEBUG) */
#if defined(DHD_EFI)
extern void dhd_log_dump_print_drv(const char *fmt, ...);
extern char *dhd_log_dump_get_timestamp(void);
#if defined(NDIS)
#define DHD_ERROR(args) do {if (dhd_msg_level & DHD_ERROR_VAL) \
{printf args; DHD_NDDBG_OUTPUT args;}} while (0)
#define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) \
{DHD_NDDBG_OUTPUT args;}} while (0)
#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) \
{DHD_NDDBG_OUTPUT args;}} while (0)
#elif defined(DHD_EFI) && defined(DHD_LOG_DUMP)
#define DHD_ERROR(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
printf args; \
dhd_log_dump_print_drv("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \
dhd_log_dump_print_drv args; \
DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_INFO(args) \
do { \
if (dhd_msg_level & DHD_INFO_VAL) { \
printf args; \
dhd_log_dump_print_drv("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \
dhd_log_dump_print_drv args; \
DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_TRACE(args)
#else /* DHD_EFI */
#define DHD_ERROR_ROAM(args) DHD_ERROR(args)
#else /* DHD_EFI && DHD_LOG_DUMP */
#define DHD_ERROR(args) do {if (dhd_msg_level & DHD_ERROR_VAL) \
printf args;} while (0)
#define DHD_TRACE(args)
#define DHD_INFO(args)
#endif
#define DHD_ERROR_ROAM(args) DHD_ERROR(args)
#endif /* defined(NDIS) */
#define DHD_DATA(args)
#define DHD_CTL(args)
@@ -257,14 +490,19 @@ do { \
#define DHD_EVENT(args) \
do { \
if (dhd_msg_level & DHD_EVENT_VAL) { \
dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \
dhd_log_dump_print args; \
DHD_LOG_DUMP_WRITE_FW("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE_FW args; \
} \
} while (0)
#define DHD_ECNTR_LOG(args) DHD_EVENT(args)
#else
#define DHD_EVENT(args)
#define DHD_ECNTR_LOG(args) DHD_EVENT(args)
#endif /* DHD_EFI && DHD_LOG_DUMP */
#define DHD_PRSRV_MEM(args) DHD_EVENT(args)
#define DHD_BTA(args)
#define DHD_ISCAN(args)
#define DHD_ARPOE(args)
#define DHD_REORDER(args)
@@ -276,8 +514,8 @@ do { \
#define DHD_MSGTRACE_LOG(args) \
do { \
if (dhd_msg_level & DHD_MSGTRACE_VAL) { \
dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \
dhd_log_dump_print args; \
DHD_LOG_DUMP_WRITE_FW("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE_FW args; \
} \
} while (0)
#define DHD_FWLOG(args) DHD_MSGTRACE_LOG(args)
@@ -289,25 +527,43 @@ do { \
#define DHD_DBGIF(args)
#if defined(DHD_EFI) && defined(DHD_LOG_DUMP)
#define DHD_ERROR_MEM(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \
dhd_log_dump_print args; \
#define DHD_ERROR_MEM(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_ERROR_EX(args) DHD_ERROR(args)
#define DHD_IOVAR_MEM(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_LOG_MEM(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_ERROR_EX(args) DHD_ERROR(args)
#else
#define DHD_ERROR_MEM(args) DHD_ERROR(args)
#define DHD_ERROR_MEM(args) DHD_ERROR(args)
#define DHD_IOVAR_MEM(args) DHD_ERROR(args)
#define DHD_LOG_MEM(args) DHD_ERROR(args)
#define DHD_ERROR_EX(args) DHD_ERROR(args)
#endif /* DHD_EFI && DHD_LOG_DUMP */
#endif /* DHD_EFI */
#define DHD_ERROR_ROAM(args) DHD_ERROR(args)
#ifdef CUSTOMER_HW4_DEBUG
#define DHD_TRACE_HW4 DHD_ERROR
#define DHD_INFO_HW4 DHD_ERROR
#define DHD_ERROR_NO_HW4 DHD_INFO
#else
#define DHD_TRACE_HW4 DHD_TRACE
#define DHD_INFO_HW4 DHD_INFO
#define DHD_ERROR_NO_HW4 DHD_ERROR
#endif /* CUSTOMER_HW4_DEBUG */
#define DHD_ERROR_ON() 0
@@ -321,6 +577,7 @@ do { \
#define DHD_INTR_ON() 0
#define DHD_GLOM_ON() 0
#define DHD_EVENT_ON() 0
#define DHD_BTA_ON() 0
#define DHD_ISCAN_ON() 0
#define DHD_ARPOE_ON() 0
#define DHD_REORDER_ON() 0
@@ -332,14 +589,55 @@ do { \
#define DHD_MSGTRACE_ON() 0
#define DHD_FWLOG_ON() 0
#define DHD_DBGIF_ON() 0
#endif
#ifdef DHD_PCIE_NATIVE_RUNTIMEPM
#define DHD_RPM_ON() 0
#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
#endif /* defined(BCMDBG) || defined(DHD_DEBUG) */
#define PRINT_RATE_LIMIT_PERIOD 5000000u /* 5s in units of us */
#define DHD_ERROR_RLMT(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
static uint64 __err_ts = 0; \
static uint32 __err_cnt = 0; \
uint64 __cur_ts = 0; \
__cur_ts = OSL_SYSUPTIME_US(); \
if (__err_ts == 0 || (__cur_ts > __err_ts && \
(__cur_ts - __err_ts > PRINT_RATE_LIMIT_PERIOD))) { \
__err_ts = __cur_ts; \
DHD_ERROR(args); \
DHD_ERROR(("[Repeats %u times]\n", __err_cnt)); \
__err_cnt = 0; \
} else { \
++__err_cnt; \
} \
} \
} while (0)
/* even in non-BCMDBG builds, logging of dongle iovars should be available */
#define DHD_DNGL_IOVAR_SET(args) \
do {if (dhd_msg_level & DHD_DNGL_IOVAR_SET_VAL) printf args;} while (0)
#ifdef BCMPERFSTATS
#define DHD_LOG(args) do {if (dhd_msg_level & DHD_LOG_VAL) bcmlog args;} while (0)
#else
#define DHD_LOG(args)
#endif
#if defined(BCMINTERNAL) && defined(LINUX) && defined(BCMSDIO) && (defined(BCMDBG) || \
defined(DHD_DEBUG))
extern void dhd_blog(char *cp, int size);
#define DHD_BLOG(cp, size) do { dhd_blog(cp, size);} while (0)
#else
#define DHD_BLOG(cp, size)
#endif
#define DHD_NONE(args)
extern int dhd_msg_level;
extern int dbgring_msg_level;
#ifdef DHD_LOG_PRINT_RATE_LIMIT
extern int log_print_threshold;
#endif /* DHD_LOG_PRINT_RATE_LIMIT */
/* Defines msg bits */
#include <dhdioctl.h>

View File

@@ -1,10 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* DHD debug ring API and structures
* DHD debug ring API and structures - implementation
*
* <<Broadcom-WL-IPTag/Open:>>
*
* Copyright (C) 1999-2019, Broadcom.
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -20,11 +17,10 @@
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: dhd_dbg_ring.c 792099 2018-12-03 15:45:56Z $
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id$
*/
#include <typedefs.h>
#include <osl.h>
@@ -35,6 +31,64 @@
#include <dhd_dbg.h>
#include <dhd_dbg_ring.h>
dhd_dbg_ring_t *
dhd_dbg_ring_alloc_init(dhd_pub_t *dhd, uint16 ring_id,
char *ring_name, uint32 ring_sz, void *allocd_buf,
bool pull_inactive)
{
dhd_dbg_ring_t *ring = NULL;
int ret = 0;
unsigned long flags = 0;
ring = MALLOCZ(dhd->osh, sizeof(dhd_dbg_ring_t));
if (!ring)
goto fail;
ret = dhd_dbg_ring_init(dhd, ring, ring_id,
(uint8 *)ring_name, ring_sz,
allocd_buf, pull_inactive);
if (ret != BCME_OK) {
DHD_ERROR(("%s: unable to init ring %s!\n",
__FUNCTION__, ring_name));
goto fail;
}
DHD_DBG_RING_LOCK(ring->lock, flags);
ring->state = RING_ACTIVE;
ring->threshold = 0;
DHD_DBG_RING_UNLOCK(ring->lock, flags);
return ring;
fail:
if (ring) {
dhd_dbg_ring_deinit(dhd, ring);
ring->ring_buf = NULL;
ring->ring_size = 0;
MFREE(dhd->osh, ring, sizeof(dhd_dbg_ring_t));
}
return NULL;
}
void
dhd_dbg_ring_dealloc_deinit(void **ring_ptr, dhd_pub_t *dhd)
{
dhd_dbg_ring_t *ring = NULL;
dhd_dbg_ring_t **dbgring = (dhd_dbg_ring_t **)ring_ptr;
if (!dbgring)
return;
ring = *dbgring;
if (ring) {
dhd_dbg_ring_deinit(dhd, ring);
ring->ring_buf = NULL;
ring->ring_size = 0;
MFREE(dhd->osh, ring, sizeof(dhd_dbg_ring_t));
*dbgring = NULL;
}
}
int
dhd_dbg_ring_init(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring, uint16 id, uint8 *name,
uint32 ring_sz, void *allocd_buf, bool pull_inactive)
@@ -43,19 +97,16 @@ dhd_dbg_ring_init(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring, uint16 id, uint8 *name,
unsigned long flags = 0;
if (allocd_buf == NULL) {
return BCME_NOMEM;
return BCME_NOMEM;
} else {
buf = allocd_buf;
}
ring->lock = DHD_DBG_RING_LOCK_INIT(dhdp->osh);
if (!ring->lock)
return BCME_NOMEM;
DHD_DBG_RING_LOCK(ring->lock, flags);
ring->id = id;
strncpy(ring->name, name, DBGRING_NAME_MAX);
ring->name[DBGRING_NAME_MAX - 1] = 0;
strlcpy((char *)ring->name, (char *)name, sizeof(ring->name));
ring->ring_size = ring_sz;
ring->wp = ring->rp = 0;
ring->ring_buf = buf;
@@ -73,6 +124,7 @@ void
dhd_dbg_ring_deinit(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring)
{
unsigned long flags = 0;
DHD_DBG_RING_LOCK(ring->lock, flags);
ring->id = 0;
ring->name[0] = 0;
@@ -90,6 +142,7 @@ dhd_dbg_ring_sched_pull(dhd_dbg_ring_t *ring, uint32 pending_len,
os_pullreq_t pull_fn, void *os_pvt, const int id)
{
unsigned long flags = 0;
DHD_DBG_RING_LOCK(ring->lock, flags);
/* if the current pending size is bigger than threshold and
* threshold is set
@@ -115,6 +168,7 @@ dhd_dbg_ring_get_pending_len(dhd_dbg_ring_t *ring)
{
uint32 pending_len = 0;
unsigned long flags = 0;
DHD_DBG_RING_LOCK(ring->lock, flags);
if (ring->stat.written_bytes > ring->stat.read_bytes) {
pending_len = ring->stat.written_bytes - ring->stat.read_bytes;
@@ -159,7 +213,7 @@ dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data)
DHD_ERROR(("%s: RING%d[%s] w_len=%u, ring_size=%u,"
" write size exceeds ring size !\n",
__FUNCTION__, ring->id, ring->name, w_len, ring->ring_size));
return BCME_BUFTOOLONG;
return BCME_ERROR;
}
/* Claim the space */
do {
@@ -200,7 +254,7 @@ dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data)
ring->rp);
/* check bounds before incrementing read ptr */
if (ring->rp + ENTRY_LENGTH(r_entry) >= ring->ring_size) {
DHD_ERROR(("%s: RING%d[%s] rp points out of boundary, "
DHD_ERROR(("%s: RING%d[%s] rp points out of boundary,"
"ring->wp=%u, ring->rp=%u, ring->ring_size=%d\n",
__FUNCTION__, ring->id, ring->name, ring->wp,
ring->rp, ring->ring_size));
@@ -213,9 +267,9 @@ dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data)
if (ring->tail_padded &&
((ring->rp + ring->rem_len) == ring->ring_size)) {
DHD_DBGIF(("%s: RING%d[%s] Found padding,"
" avail_size=%d, w_len=%d, set rp=0\n",
__FUNCTION__, ring->id, ring->name,
avail_size, w_len));
" avail_size=%d, w_len=%d, set rp = 0\n",
__FUNCTION__,
ring->id, ring->name, avail_size, w_len));
ring->rp = 0;
ring->tail_padded = FALSE;
ring->rem_len = 0;
@@ -271,14 +325,11 @@ dhd_dbg_ring_pull_single(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool
dhd_dbg_ring_entry_t *r_entry = NULL;
uint32 rlen = 0;
char *buf = NULL;
unsigned long flags;
if (!ring || !data || buf_len <= 0) {
return 0;
}
DHD_DBG_RING_LOCK(ring->lock, flags);
/* pull from ring is allowed for inactive (suspended) ring
* in case of ecounters only, this is because, for ecounters
* when a trap occurs the ring is suspended and data is then
@@ -352,7 +403,6 @@ dhd_dbg_ring_pull_single(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool
ring->id, ring->name, ring->stat.read_bytes, ring->wp, ring->rp));
exit:
DHD_DBG_RING_UNLOCK(ring->lock, flags);
return rlen;
}
@@ -361,17 +411,13 @@ int
dhd_dbg_ring_pull(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool strip_hdr)
{
int32 r_len, total_r_len = 0;
unsigned long flags;
if (!ring || !data)
return 0;
DHD_DBG_RING_LOCK(ring->lock, flags);
if (!ring->pull_inactive && (ring->state != RING_ACTIVE)) {
DHD_DBG_RING_UNLOCK(ring->lock, flags);
return 0;
}
DHD_DBG_RING_UNLOCK(ring->lock, flags);
while (buf_len > 0) {
r_len = dhd_dbg_ring_pull_single(ring, data, buf_len, strip_hdr);
@@ -389,6 +435,7 @@ int
dhd_dbg_ring_config(dhd_dbg_ring_t *ring, int log_level, uint32 threshold)
{
unsigned long flags = 0;
if (!ring)
return BCME_BADADDR;

View File

@@ -1,10 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* DHD debug ring header file
* DHD debug ring header file - interface
*
* <<Broadcom-WL-IPTag/Open:>>
*
* Copyright (C) 1999-2019, Broadcom.
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -20,11 +17,10 @@
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: dhd_dbg_ring.h 795094 2018-12-17 08:56:58Z $
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id$
*/
#ifndef __DHD_DBG_RING_H__
@@ -32,7 +28,11 @@
#include <bcmutils.h>
#if defined(LINUX)
#define PACKED_STRUCT __attribute__ ((packed))
#else
#define PACKED_STRUCT
#endif
#define DBGRING_NAME_MAX 32
@@ -97,9 +97,9 @@ typedef struct dhd_dbg_ring {
#define DBGRING_FLUSH_THRESHOLD(ring) (ring->ring_size / 3)
#define RING_STAT_TO_STATUS(ring, status) \
do { \
strncpy(status.name, ring->name, \
sizeof(status.name) - 1); \
do { \
/* status.name/ring->name are the same length so no need to check return value */ \
(void)memcpy_s(status.name, sizeof(status.name), ring->name, sizeof(ring->name)); \
status.ring_id = ring->id; \
status.ring_buffer_byte_size = ring->ring_size; \
status.written_bytes = ring->stat.written_bytes; \
@@ -113,6 +113,7 @@ typedef struct dhd_dbg_ring {
#define PAYLOAD_MAX_LEN 65535
#define PAYLOAD_ECNTR_MAX_LEN 1648u
#define PAYLOAD_RTT_MAX_LEN 1648u
#define PAYLOAD_BCM_TRACE_MAX_LEN 1648u
#define PENDING_LEN_MAX 0xFFFFFFFF
#define DBG_RING_STATUS_SIZE (sizeof(dhd_dbg_ring_status_t))
@@ -125,6 +126,10 @@ typedef struct dhd_dbg_ring {
typedef void (*os_pullreq_t)(void *os_priv, const int ring_id);
dhd_dbg_ring_t *dhd_dbg_ring_alloc_init(dhd_pub_t *dhd, uint16 ring_id,
char *ring_name, uint32 ring_sz, void *allocd_buf,
bool pull_inactive);
void dhd_dbg_ring_dealloc_deinit(void **dbgring, dhd_pub_t *dhd);
int dhd_dbg_ring_init(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring, uint16 id, uint8 *name,
uint32 ring_sz, void *allocd_buf, bool pull_inactive);
void dhd_dbg_ring_deinit(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring);

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,14 @@
/*
* DHD debugability header file
*
* <<Broadcom-WL-IPTag/Open:>>
* Copyright (C) 2020, Broadcom.
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -18,28 +16,18 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: dhd_debug.h 705824 2017-06-19 13:58:39Z $
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id$
*/
#ifndef _dhd_debug_h_
#define _dhd_debug_h_
#include <event_log.h>
#include <bcmutils.h>
enum {
DEBUG_RING_ID_INVALID = 0,
FW_VERBOSE_RING_ID,
FW_EVENT_RING_ID,
DHD_EVENT_RING_ID,
NAN_EVENT_RING_ID,
/* add new id here */
DEBUG_RING_ID_MAX
};
#include <dhd_dbg_ring.h>
enum {
/* Feature set */
@@ -62,21 +50,34 @@ enum {
DBG_RING_ENTRY_FLAGS_HAS_TIMESTAMP = (1 << (1))
};
#define DBGRING_NAME_MAX 32
/* firmware verbose ring, ring id 1 */
#define FW_VERBOSE_RING_NAME "fw_verbose"
#define FW_VERBOSE_RING_SIZE (64 * 1024)
#define FW_VERBOSE_RING_SIZE (256 * 1024)
/* firmware event ring, ring id 2 */
#define FW_EVENT_RING_NAME "fw_event"
#define FW_EVENT_RING_SIZE (64 * 1024)
/* DHD connection event ring, ring id 3 */
#define DHD_EVENT_RING_NAME "dhd_event"
#define DHD_EVENT_RING_SIZE (64 * 1024)
/* NAN event ring, ring id 4 */
#define NAN_EVENT_RING_NAME "nan_event"
#define NAN_EVENT_RING_SIZE (64 * 1024)
#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING
/* DHD driver log ring */
#define DRIVER_LOG_RING_NAME "driver_log"
#define DRIVER_LOG_RING_SIZE (256 * 1024)
/* ROAM stats log ring */
#define ROAM_STATS_RING_NAME "roam_stats"
#define ROAM_STATS_RING_SIZE (64 * 1024)
#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
#ifdef BTLOG
/* BT log ring, ring id 5 */
#define BT_LOG_RING_NAME "bt_log"
#define BT_LOG_RING_SIZE (64 * 1024)
#endif /* BTLOG */
#define TLV_LOG_SIZE(tlv) ((tlv) ? (sizeof(tlv_log) + (tlv)->len) : 0)
#define TLV_LOG_NEXT(tlv) \
@@ -94,13 +95,6 @@ enum {
#define DBG_RING_ACTIVE(dhdp, ring_id) 0
#endif /* DEBUGABILITY */
#define TXACTIVESZ(r, w, d) (((r) <= (w)) ? ((w) - (r)) : ((d) - (r) + (w)))
#define DBG_RING_READ_AVAIL_SPACE(w, r, d) (((w) >= (r)) ? ((w) - (r)) : ((d) - (r)))
#define DBG_RING_WRITE_SPACE_AVAIL_CONT(r, w, d) (((w) >= (r)) ? ((d) - (w)) : ((r) - (w)))
#define DBG_RING_WRITE_SPACE_AVAIL(r, w, d) (d - (TXACTIVESZ(r, w, d)))
#define DBG_RING_CHECK_WRITE_SPACE(r, w, d) \
MIN(DBG_RING_WRITE_SPACE_AVAIL(r, w, d), DBG_RING_WRITE_SPACE_AVAIL_CONT(r, w, d))
enum {
/* driver receive association command from kernel */
WIFI_EVENT_ASSOCIATION_REQUESTED = 0,
@@ -296,10 +290,16 @@ typedef struct per_packet_status_entry {
uint8 *data;
} per_packet_status_entry_t;
#if defined(LINUX)
#define PACKED_STRUCT __attribute__ ((packed))
#else
#define PACKED_STRUCT
#endif
#if defined(LINUX)
typedef struct log_conn_event {
uint16 event;
tlv_log *tlvs;
tlv_log tlvs[0];
/*
* separate parameter structure per event to be provided and optional data
* the event_data is expected to include an official android part, with some
@@ -308,6 +308,7 @@ typedef struct log_conn_event {
* understood by the developer only.
*/
} PACKED_STRUCT log_conn_event_t;
#endif /* defined(LINUX) */
/*
* Ring buffer name for power events ring. note that power event are extremely frequents
@@ -343,59 +344,39 @@ enum {
DBG_RING_ENTRY_NAN_EVENT_TYPE
};
typedef struct dhd_dbg_ring_entry {
uint16 len; /* payload length excluding the header */
uint8 flags;
uint8 type; /* Per ring specific */
uint64 timestamp; /* present if has_timestamp bit is set. */
} PACKED_STRUCT dhd_dbg_ring_entry_t;
#define DBG_RING_ENTRY_SIZE (sizeof(dhd_dbg_ring_entry_t))
#define ENTRY_LENGTH(hdr) ((hdr)->len + DBG_RING_ENTRY_SIZE)
#define PAYLOAD_MAX_LEN 65535
typedef struct dhd_dbg_ring_status {
uint8 name[DBGRING_NAME_MAX];
uint32 flags;
int ring_id; /* unique integer representing the ring */
/* total memory size allocated for the buffer */
uint32 ring_buffer_byte_size;
uint32 verbose_level;
/* number of bytes that was written to the buffer by driver */
uint32 written_bytes;
/* number of bytes that was read from the buffer by user land */
uint32 read_bytes;
/* number of records that was read from the buffer by user land */
uint32 written_records;
} dhd_dbg_ring_status_t;
struct log_level_table {
int log_level;
uint16 tag;
uint8 sets;
char *desc;
};
#ifdef DEBUGABILITY
#ifdef OEM_ANDROID
/*
* Assuming that the Ring lock is mutex, bailing out if the
* callers are from atomic context. On a long term, one has to
* schedule a job to execute in sleepable context so that
* contents are pushed to the ring.
*/
#define DBG_EVENT_LOG(dhdp, connect_state) \
{ \
do { \
uint16 state = connect_state; \
if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) \
if (CAN_SLEEP() && DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) \
dhd_os_push_push_ring_data(dhdp, DHD_EVENT_RING_ID, \
&state, sizeof(state)); \
} while (0); \
}
#else
#define DBG_EVENT_LOG(dhdp, connect_state)
#endif /* DEBUGABILITY */
#define DBG_EVENT_LOG(dhd, connect_state)
#endif /* !OEM_ANDROID */
/*
* Packet logging - HAL specific data
* XXX: These should be moved to wl_cfgvendor.h
*/
#define MD5_PREFIX_LEN 4
#define MAX_FATE_LOG_LEN 32
#define MAX_FRAME_LEN_ETHERNET 1518
#define MAX_FRAME_LEN_80211_MGMT 2352 /* 802.11-2012 Fig. 8-34 */
@@ -415,8 +396,8 @@ typedef enum {
*/
TX_PKT_FATE_FW_DROP_INVALID,
/* Dropped by firmware due to lack of buffer space. */
TX_PKT_FATE_FW_DROP_NOBUFS,
/* Dropped by firmware due to lifetime expiration. */
TX_PKT_FATE_FW_DROP_EXPTIME,
/*
* Dropped by firmware for any other reason. Includes
@@ -440,6 +421,9 @@ typedef enum {
/* Dropped by driver for any other reason. */
TX_PKT_FATE_DRV_DROP_OTHER,
/* Packet free by firmware. */
TX_PKT_FATE_FW_PKT_FREE,
} wifi_tx_packet_fate;
typedef enum {
@@ -479,6 +463,9 @@ typedef enum {
/* Dropped by driver for any other reason. */
RX_PKT_FATE_DRV_DROP_OTHER,
/* Indicate RX Host Wake up packet. */
RX_PKT_FATE_WAKE_PKT,
} wifi_rx_packet_fate;
typedef enum {
@@ -581,7 +568,6 @@ typedef struct compat_wifi_frame_info {
} frame_content;
} compat_wifi_frame_info_t;
typedef struct compat_wifi_tx_report {
char md5_prefix[MD5_PREFIX_LEN];
wifi_tx_packet_fate fate;
@@ -594,7 +580,6 @@ typedef struct compat_wifi_rx_report {
compat_wifi_frame_info_t frame_inf;
} compat_wifi_rx_report_t;
/*
* Packet logging - internal data
*/
@@ -673,38 +658,6 @@ typedef struct dhd_dbg_pkt_mon
dbg_mon_rx_pkts_t rx_pkt_mon;
} dhd_dbg_pkt_mon_t;
enum dbg_ring_state {
RING_STOP = 0, /* ring is not initialized */
RING_ACTIVE, /* ring is live and logging */
RING_SUSPEND /* ring is initialized but not logging */
};
struct ring_statistics {
/* number of bytes that was written to the buffer by driver */
uint32 written_bytes;
/* number of bytes that was read from the buffer by user land */
uint32 read_bytes;
/* number of records that was written to the buffer by driver */
uint32 written_records;
};
typedef struct dhd_dbg_ring {
int id; /* ring id */
uint8 name[DBGRING_NAME_MAX]; /* name string */
uint32 ring_size; /* numbers of item in ring */
uint32 wp; /* write pointer */
uint32 rp; /* read pointer */
uint32 log_level; /* log_level */
uint32 threshold; /* threshold bytes */
void * ring_buf; /* pointer of actually ring buffer */
void * lock; /* spin lock for ring access */
struct ring_statistics stat; /* statistics */
enum dbg_ring_state state; /* ring state enum */
bool tail_padded; /* writer does not have enough space */
uint32 rem_len; /* number of bytes from wp_pad to end */
bool sched_pull; /* schedule reader immediately */
} dhd_dbg_ring_t;
typedef struct dhd_dbg {
dhd_dbg_ring_t dbg_rings[DEBUG_RING_ID_MAX];
void *private; /* os private_data */
@@ -765,12 +718,12 @@ typedef struct dhd_dbg {
#ifdef DUMP_IOCTL_IOV_LIST
typedef struct dhd_iov_li {
dll_t list;
uint32 cmd;
char buff[100];
uint32 cmd; /* command number */
char buff[100]; /* command name */
} dhd_iov_li_t;
#endif /* DUMP_IOCTL_IOV_LIST */
#define IOV_LIST_MAX_LEN 5
#endif /* DUMP_IOCTL_IOV_LIST */
#ifdef DHD_DEBUG
typedef struct {
@@ -781,26 +734,81 @@ typedef struct {
} dhd_dbg_mwli_t;
#endif /* DHD_DEBUG */
#define DHD_OW_BI_RAW_EVENT_LOG_FMT 0xFFFF
/* LSB 2 bits of format number to identify the type of event log */
#define DHD_EVENT_LOG_HDR_MASK 0x3
#define DHD_EVENT_LOG_FMT_NUM_OFFSET 2
#define DHD_EVENT_LOG_FMT_NUM_MASK 0x3FFF
/**
* OW:- one word
* TW:- two word
* NB:- non binary
* BI:- binary
*/
#define DHD_OW_NB_EVENT_LOG_HDR 0
#define DHD_TW_NB_EVENT_LOG_HDR 1
#define DHD_BI_EVENT_LOG_HDR 3
#define DHD_INVALID_EVENT_LOG_HDR 2
#define DHD_TW_VALID_TAG_BITS_MASK 0xF
#define DHD_OW_BI_EVENT_FMT_NUM 0x3FFF
#define DHD_TW_BI_EVENT_FMT_NUM 0x3FFE
#define DHD_TW_EVENT_LOG_TAG_OFFSET 8
#define EVENT_TAG_TIMESTAMP_OFFSET 1
#define EVENT_TAG_TIMESTAMP_EXT_OFFSET 2
typedef struct prcd_event_log_hdr {
uint32 tag; /* Event_log entry tag */
uint32 count; /* Count of 4-byte entries */
uint32 fmt_num_raw; /* Format number */
uint32 fmt_num; /* Format number >> 2 */
uint32 armcycle; /* global ARM CYCLE for TAG */
uint32 *log_ptr; /* start of payload */
uint32 payload_len;
/* Extended event log header info
* 0 - legacy, 1 - extended event log header present
*/
bool ext_event_log_hdr;
bool binary_payload; /* 0 - non binary payload, 1 - binary payload */
} prcd_event_log_hdr_t; /* Processed event log header */
/* dhd_dbg functions */
extern void dhd_dbg_trace_evnt_handler(dhd_pub_t *dhdp, void *event_data,
void *raw_event_ptr, uint datalen);
void dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data,
void *raw_event_ptr, uint datalen, bool msgtrace_hdr_present,
uint32 msgtrace_seqnum);
#ifdef BTLOG
extern void dhd_dbg_bt_log_handler(dhd_pub_t *dhdp, void *data, uint datalen);
#endif /* BTLOG */
extern int dhd_dbg_attach(dhd_pub_t *dhdp, dbg_pullreq_t os_pullreq,
dbg_urgent_noti_t os_urgent_notifier, void *os_priv);
extern void dhd_dbg_detach(dhd_pub_t *dhdp);
extern int dhd_dbg_start(dhd_pub_t *dhdp, bool start);
extern int dhd_dbg_set_configuration(dhd_pub_t *dhdp, int ring_id,
int log_level, int flags, uint32 threshold);
extern int dhd_dbg_get_ring_status(dhd_pub_t *dhdp, int ring_id,
dhd_dbg_ring_status_t *dbg_ring_status);
extern int dhd_dbg_ring_push(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_entry_t *hdr, void *data);
extern int dhd_dbg_ring_pull(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len);
extern int dhd_dbg_ring_pull_single(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len,
bool strip_header);
extern int dhd_dbg_find_ring_id(dhd_pub_t *dhdp, char *ring_name);
extern dhd_dbg_ring_t *dhd_dbg_get_ring_from_ring_id(dhd_pub_t *dhdp, int ring_id);
extern void *dhd_dbg_get_priv(dhd_pub_t *dhdp);
extern int dhd_dbg_send_urgent_evt(dhd_pub_t *dhdp, const void *data, const uint32 len);
extern void dhd_dbg_verboselog_printf(dhd_pub_t *dhdp, event_log_hdr_t *hdr,
void *raw_event_ptr, uint32 *log_ptr);
extern void dhd_dbg_verboselog_printf(dhd_pub_t *dhdp, prcd_event_log_hdr_t *plog_hdr,
void *raw_event_ptr, uint32 *log_ptr, uint32 logset, uint16 block);
int dhd_dbg_pull_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len);
int dhd_dbg_pull_single_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len,
bool strip_header);
int dhd_dbg_push_to_ring(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_entry_t *hdr,
void *data);
int __dhd_dbg_get_ring_status(dhd_dbg_ring_t *ring, dhd_dbg_ring_status_t *ring_status);
int dhd_dbg_get_ring_status(dhd_pub_t *dhdp, int ring_id,
dhd_dbg_ring_status_t *dbg_ring_status);
#ifdef SHOW_LOGTRACE
void dhd_dbg_read_ring_into_trace_buf(dhd_dbg_ring_t *ring, trace_buf_info_t *trace_buf_info);
#endif /* SHOW_LOGTRACE */
#ifdef DBG_PKT_MON
extern int dhd_dbg_attach_pkt_monitor(dhd_pub_t *dhdp,
@@ -820,6 +828,9 @@ extern int dhd_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf,
extern int dhd_dbg_detach_pkt_monitor(dhd_pub_t *dhdp);
#endif /* DBG_PKT_MON */
extern bool dhd_dbg_process_tx_status(dhd_pub_t *dhdp, void *pkt,
uint32 pktid, uint16 status);
/* os wrapper function */
extern int dhd_os_dbg_attach(dhd_pub_t *dhdp);
extern void dhd_os_dbg_detach(dhd_pub_t *dhdp);
@@ -865,4 +876,16 @@ extern void dhd_iov_li_delete(dhd_pub_t *dhd, dll_t *list_head);
#ifdef DHD_DEBUG
extern void dhd_mw_list_delete(dhd_pub_t *dhd, dll_t *list_head);
#endif /* DHD_DEBUG */
void print_roam_enhanced_log(prcd_event_log_hdr_t *plog_hdr);
typedef void (*print_roam_enhance_log_func)(prcd_event_log_hdr_t *plog_hdr);
typedef struct _pr_roam_tbl {
uint8 version;
uint8 id;
print_roam_enhance_log_func pr_func;
} pr_roam_tbl_t;
extern uint32 dhd_dbg_get_fwverbose(dhd_pub_t *dhdp);
extern void dhd_dbg_set_fwverbose(dhd_pub_t *dhdp, uint32 new_val);
#endif /* _dhd_debug_h_ */

View File

@@ -1,16 +1,14 @@
/*
* DHD debugability Linux os layer
*
* <<Broadcom-WL-IPTag/Open:>>
* Copyright (C) 2020, Broadcom.
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -18,12 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: dhd_debug_linux.c 710862 2017-07-14 07:43:59Z $
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id$
*/
#include <typedefs.h>
@@ -37,6 +34,7 @@
#include <net/cfg80211.h>
#include <wl_cfgvendor.h>
#include <dhd_config.h>
typedef void (*dbg_ring_send_sub_t)(void *ctx, const int ring_id, const void *data,
const uint32 len, const dhd_dbg_ring_status_t ring_status);
@@ -55,17 +53,17 @@ typedef struct dhd_dbg_os_ring_info {
} linux_dbgring_info_t;
struct log_level_table dhd_event_map[] = {
{1, WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED, 0, "DRIVER EAPOL TX REQ"},
{1, WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED, 0, "DRIVER EAPOL RX"},
{2, WIFI_EVENT_DRIVER_SCAN_REQUESTED, 0, "SCAN_REQUESTED"},
{2, WIFI_EVENT_DRIVER_SCAN_COMPLETE, 0, "SCAN COMPELETE"},
{3, WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND, 0, "SCAN RESULT FOUND"},
{2, WIFI_EVENT_DRIVER_PNO_ADD, 0, "PNO ADD"},
{2, WIFI_EVENT_DRIVER_PNO_REMOVE, 0, "PNO REMOVE"},
{2, WIFI_EVENT_DRIVER_PNO_NETWORK_FOUND, 0, "PNO NETWORK FOUND"},
{2, WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED, 0, "PNO SCAN_REQUESTED"},
{1, WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND, 0, "PNO SCAN RESULT FOUND"},
{1, WIFI_EVENT_DRIVER_PNO_SCAN_COMPLETE, 0, "PNO SCAN COMPELETE"}
{1, WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED, "DRIVER EAPOL TX REQ"},
{1, WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED, "DRIVER EAPOL RX"},
{2, WIFI_EVENT_DRIVER_SCAN_REQUESTED, "SCAN_REQUESTED"},
{2, WIFI_EVENT_DRIVER_SCAN_COMPLETE, "SCAN COMPELETE"},
{3, WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND, "SCAN RESULT FOUND"},
{2, WIFI_EVENT_DRIVER_PNO_ADD, "PNO ADD"},
{2, WIFI_EVENT_DRIVER_PNO_REMOVE, "PNO REMOVE"},
{2, WIFI_EVENT_DRIVER_PNO_NETWORK_FOUND, "PNO NETWORK FOUND"},
{2, WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED, "PNO SCAN_REQUESTED"},
{1, WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND, "PNO SCAN RESULT FOUND"},
{1, WIFI_EVENT_DRIVER_PNO_SCAN_COMPLETE, "PNO SCAN COMPELETE"}
};
static void
@@ -77,6 +75,8 @@ debug_data_send(dhd_pub_t *dhdp, int ring_id, const void *data, const uint32 len
ndev = dhd_linux_get_primary_netdev(dhdp);
if (!ndev)
return;
if (!VALID_RING(ring_id))
return;
if (ring_send_sub_cb[ring_id]) {
ring_sub_send = ring_send_sub_cb[ring_id];
ring_sub_send(ndev, ring_id, data, len, ring_status);
@@ -101,25 +101,24 @@ dbg_ring_poll_worker(struct work_struct *work)
struct delayed_work *d_work = to_delayed_work(work);
bool sched = TRUE;
dhd_dbg_ring_t *ring;
#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
linux_dbgring_info_t *ring_info =
container_of(d_work, linux_dbgring_info_t, work);
#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
dhd_pub_t *dhdp = ring_info->dhdp;
int ringid = ring_info->ring_id;
linux_dbgring_info_t *ring_info;
dhd_pub_t *dhdp;
int ringid;
dhd_dbg_ring_status_t ring_status;
void *buf;
dhd_dbg_ring_entry_t *hdr;
uint32 buflen, rlen;
unsigned long flags;
GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
ring_info = container_of(d_work, linux_dbgring_info_t, work);
GCC_DIAGNOSTIC_POP();
dhdp = ring_info->dhdp;
ringid = ring_info->ring_id;
ring = &dhdp->dbg->dbg_rings[ringid];
flags = dhd_os_spin_lock(ring->lock);
DHD_DBG_RING_LOCK(ring->lock, flags);
dhd_dbg_get_ring_status(dhdp, ringid, &ring_status);
if (ring->wp > ring->rp) {
@@ -141,7 +140,10 @@ dbg_ring_poll_worker(struct work_struct *work)
goto exit;
}
rlen = dhd_dbg_ring_pull(dhdp, ringid, buf, buflen);
DHD_DBG_RING_UNLOCK(ring->lock, flags);
rlen = dhd_dbg_pull_from_ring(dhdp, ringid, buf, buflen);
DHD_DBG_RING_LOCK(ring->lock, flags);
if (!ring->sched_pull) {
ring->sched_pull = TRUE;
}
@@ -166,8 +168,7 @@ exit:
schedule_delayed_work(d_work, ring_info->interval);
}
}
dhd_os_spin_unlock(ring->lock, flags);
DHD_DBG_RING_UNLOCK(ring->lock, flags);
return;
}
@@ -199,13 +200,12 @@ dhd_os_start_logging(dhd_pub_t *dhdp, char *ring_name, int log_level,
int ret = BCME_OK;
int ring_id;
linux_dbgring_info_t *os_priv, *ring_info;
uint32 ms;
ring_id = dhd_dbg_find_ring_id(dhdp, ring_name);
if (!VALID_RING(ring_id))
return BCME_UNSUPPORTED;
DHD_DBGIF(("%s , log_level : %d, time_intval : %d, threshod %d Bytes\n",
DHD_INFO(("%s , log_level : %d, time_intval : %d, threshod %d Bytes\n",
__FUNCTION__, log_level, time_intval, threshold));
/* change the configuration */
@@ -220,14 +220,6 @@ dhd_os_start_logging(dhd_pub_t *dhdp, char *ring_name, int log_level,
return BCME_ERROR;
ring_info = &os_priv[ring_id];
ring_info->log_level = log_level;
if (ring_id == FW_VERBOSE_RING_ID || ring_id == FW_EVENT_RING_ID) {
ring_info->tsoffset = local_clock();
if (dhd_wl_ioctl_get_intiovar(dhdp, "rte_timesync", &ms, WLC_GET_VAR,
FALSE, 0))
DHD_ERROR(("%s rte_timesync failed\n", __FUNCTION__));
do_div(ring_info->tsoffset, 1000000);
ring_info->tsoffset -= ms;
}
if (time_intval == 0 || log_level == 0) {
ring_info->interval = 0;
cancel_delayed_work_sync(&ring_info->work);
@@ -253,7 +245,7 @@ dhd_os_reset_logging(dhd_pub_t *dhdp)
/* Stop all rings */
for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
DHD_DBGIF(("%s: Stop ring buffer %d\n", __FUNCTION__, ring_id));
DHD_INFO(("%s: Stop ring buffer %d\n", __FUNCTION__, ring_id));
ring_info = &os_priv[ring_id];
/* cancel any pending work */
@@ -284,8 +276,8 @@ dhd_os_suppress_logging(dhd_pub_t *dhdp, bool suppress)
if (!os_priv)
return BCME_ERROR;
max_log_level = MAX(os_priv[FW_VERBOSE_RING_ID].log_level,
os_priv[FW_EVENT_RING_ID].log_level);
max_log_level = os_priv[FW_VERBOSE_RING_ID].log_level;
if (max_log_level == SUPPRESS_LOG_LEVEL) {
/* suppress the logging in FW not to wake up host while device in suspend mode */
ret = dhd_iovar(dhdp, 0, "logtrace", (char *)&enable, sizeof(enable), NULL, 0,
@@ -352,7 +344,7 @@ dhd_os_push_push_ring_data(dhd_pub_t *dhdp, int ring_id, void *data, int32 data_
msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_BINARY;
msg_hdr.timestamp = local_clock();
/* convert to ms */
do_div(msg_hdr.timestamp, 1000000);
msg_hdr.timestamp = DIV_U64_BY_U32(msg_hdr.timestamp, NSEC_PER_MSEC);
msg_hdr.len = data_len;
/* filter the event for higher log level with current log level */
for (i = 0; i < ARRAYSIZE(dhd_event_map); i++) {
@@ -362,7 +354,17 @@ dhd_os_push_push_ring_data(dhd_pub_t *dhdp, int ring_id, void *data, int32 data_
}
}
}
ret = dhd_dbg_ring_push(dhdp, ring_id, &msg_hdr, event_data);
#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING
else if (ring_id == FW_VERBOSE_RING_ID || ring_id == DRIVER_LOG_RING_ID ||
ring_id == ROAM_STATS_RING_ID) {
msg_hdr.type = DBG_RING_ENTRY_DATA_TYPE;
msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_TIMESTAMP;
msg_hdr.timestamp = local_clock();
msg_hdr.timestamp = DIV_U64_BY_U32(msg_hdr.timestamp, NSEC_PER_MSEC);
msg_hdr.len = strlen(data);
}
#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
ret = dhd_dbg_push_to_ring(dhdp, ring_id, &msg_hdr, event_data);
if (ret) {
DHD_ERROR(("%s : failed to push data into the ring (%d) with ret(%d)\n",
__FUNCTION__, ring_id, ret));
@@ -435,8 +437,15 @@ int
dhd_os_dbg_get_feature(dhd_pub_t *dhdp, int32 *features)
{
int ret = BCME_OK;
/* XXX : we need to find a way to get the features for dbg */
*features = 0;
*features |= DBG_MEMORY_DUMP_SUPPORTED;
#ifdef DEBUGABILITY
#ifndef DEBUGABILITY_DISABLE_MEMDUMP
// fix for RequestFirmwareDebugDump issue of VTS
if ((dhdp->conf->chip != BCM43751_CHIP_ID) && (dhdp->conf->chip != BCM43752_CHIP_ID) &&
(dhdp->conf->chip != BCM4375_CHIP_ID))
*features |= DBG_MEMORY_DUMP_SUPPORTED;
#endif /* !DEBUGABILITY_DISABLE_MEMDUMP */
if (FW_SUPPORTED(dhdp, logtrace)) {
*features |= DBG_CONNECT_EVENT_SUPPORTED;
*features |= DBG_VERBOSE_LOG_SUPPORTED;
@@ -449,6 +458,7 @@ dhd_os_dbg_get_feature(dhd_pub_t *dhdp, int32 *features)
*features |= DBG_PACKET_FATE_SUPPORTED;
}
#endif /* DBG_PKT_MON */
#endif /* DEBUGABILITY */
return ret;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
/*
* Wifi dongle status Filter and Report
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id$
*/
#ifndef dhd_event_log_filter_h
#define dhd_event_log_filter_h
#include <dhd.h>
#include <event_log_tag.h>
#include <dhd_debug.h>
typedef struct {
uint16 version;
uint8 htr_type; /* from wl_slice_hist_XX_stats_xtlv_id */
uint8 htr_num; /* number of elements in htr_running or htr_rc */
uint32 htr_rn_last; /* last reasons along with seq, etc */
uint32 htr_rn_ts_last; /* last time stamps corr to htr_rn_last */
uint32 htr_rn_prev; /* last reasons along with seq, etc */
uint32 htr_rn_ts_prev; /* last time stamps corr to htr_rn_prev */
uint32 htr_rc_max; /* largest toss reasons and counts */
uint32 htr_rc_ts_max; /* latest time stamp corr to htr_rc_max */
uint32 htr_rc_secnd; /* second largest toss reasons and counts */
uint32 htr_rc_ts_secnd; /* latest time stamps corr to htr_rc_second */
} evt_hist_compact_toss_stats_v1_t;
int dhd_event_log_filter_init(dhd_pub_t *dhdp, uint8 *buf, uint32 buf_size);
void dhd_event_log_filter_deinit(dhd_pub_t *dhdp);
void dhd_event_log_filter_event_handler(
dhd_pub_t *dhdp, prcd_event_log_hdr_t *plog_hdr, uint32 *data);
void dhd_event_log_filter_notify_connect_request(dhd_pub_t *dhdp, uint8 *bssid, int channel);
void dhd_event_log_filter_notify_connect_done(dhd_pub_t *dhdp, uint8 *bssid, int roam);
#ifdef WLADPS_ENERGY_GAIN
int dhd_event_log_filter_adps_energy_gain(dhd_pub_t *dhdp);
#endif /* WLADPS_ENERGY_GAIN */
#endif /* !dhd_event_log_filter_h */

View File

@@ -6,14 +6,14 @@
* Provides type definitions and function prototypes used to create, delete and manage flow rings at
* high level.
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -21,17 +21,14 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_flowring.h 672438 2016-11-28 12:35:24Z $
* $Id$
*/
/** XXX Twiki: [PCIeFullDongleArchitecture] */
/****************
* Common types *
@@ -61,11 +58,51 @@
#endif /* IDLE_TX_FLOW_MGMT */
#define FLOW_RING_STATUS_STA_FREEING 7
#if defined(DHD_HTPUT_TUNABLES)
#define HTPUT_FLOW_RING_PRIO PRIO_8021D_BE
#define HTPUT_NUM_STA_FLOW_RINGS 1u
#define HTPUT_NUM_CLIENT_FLOW_RINGS 3u
#define HTPUT_TOTAL_FLOW_RINGS (HTPUT_NUM_STA_FLOW_RINGS + HTPUT_NUM_CLIENT_FLOW_RINGS)
#define DHD_IS_FLOWID_HTPUT(pub, flowid) \
((flowid >= (pub)->htput_flow_ring_start) && \
(flowid < ((pub)->htput_flow_ring_start + HTPUT_TOTAL_FLOW_RINGS)))
#endif /* DHD_HTPUT_TUNABLES */
#ifdef DHD_EFI
#define DHD_FLOWRING_RX_BUFPOST_PKTSZ 1600
/*
* Each lbuf is of size 2048 bytes. But the last 112 bytes is occupied for lbuf header.
* Since lbuf is crucial data structure we want to avoid operations very close to lbuf.
* so providing a pad of 136 bytes. so lbuf and pad together is 248 bytes.
*
* So the maximum usable lbuf size is 1800 bytes.
*
* These 1800 bytes is utilized for below purposes.
*
* 1. FW operating in mode2 requires 98 bytes for extra headers
* like SNAP, PLCP etc. Whereas FW operating in mode4 requires 70 bytes.
* So in EFI DHD we will consider 98 bytes which fits for chips operating in both mode2 and mode4.
*
* 2. For TPUT tests in EFI user can request a maximum payload of 1500 bytes.
* To add ethernet header and TPUT header etc we are reserving 100bytes. So 1600 bytes are utilized
* for headers and payload.
*
* so 1698(98 + 1600) bytes by are consumed by 1 and 2.
* So we still have 112 bytes which can be utilized
* if FW needs buffer for more headers in future.
*
* --Update-- 13Jul2018 (above comments preserved for history)
* 3. In case of 11ax chips more headroom is required, FW requires a min. of 1920 bytes for Rx
* buffers, or it will trap. Therefore bumping up the size to 1920 bytes. Which leaves
* only 16 bytes pad between data and lbuf header ! Further size increase may not be possible !!
*/
#define DHD_FLOWRING_RX_BUFPOST_PKTSZ 1920
#else
#define DHD_FLOWRING_RX_BUFPOST_PKTSZ 2048
#endif
#endif /* DHD_EFI */
#define DHD_FLOWRING_RX_BUFPOST_PKTSZ_MAX 4096
#define DHD_FLOWRING_TX_BIG_PKT_SIZE (3700u)
#define DHD_FLOW_PRIO_AC_MAP 0
#define DHD_FLOW_PRIO_TID_MAP 1
@@ -81,8 +118,26 @@
#define DHD_IF_ROLE(pub, idx) (((if_flow_lkup_t *)(pub)->if_flow_lkup)[idx].role)
#define DHD_IF_ROLE_AP(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_AP)
#define DHD_IF_ROLE_STA(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_STA)
#define DHD_IF_ROLE_P2PGC(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_P2P_CLIENT)
#define DHD_IF_ROLE_P2PGO(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_P2P_GO)
#define DHD_IF_ROLE_WDS(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_WDS)
#define DHD_IF_ROLE_IBSS(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_IBSS)
#define DHD_IF_ROLE_NAN(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_NAN)
#define DHD_IF_ROLE_GENERIC_STA(pub, idx) \
(DHD_IF_ROLE_STA(pub, idx) || DHD_IF_ROLE_P2PGC(pub, idx) || DHD_IF_ROLE_WDS(pub, idx))
#ifdef DHD_AWDL
#define DHD_IF_ROLE_AWDL(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_AWDL)
#define DHD_IF_ROLE_MULTI_CLIENT(pub, idx) \
(DHD_IF_ROLE_AP(pub, idx) || DHD_IF_ROLE_P2PGO(pub, idx) || DHD_IF_ROLE_AWDL(pub, idx) ||\
DHD_IF_ROLE_NAN(pub, idx))
#else
#define DHD_IF_ROLE_MULTI_CLIENT(pub, idx) \
(DHD_IF_ROLE_AP(pub, idx) || DHD_IF_ROLE_P2PGO(pub, idx) ||\
DHD_IF_ROLE_NAN(pub, idx))
#endif /* DHD_AWDL */
#define DHD_FLOW_RING(dhdp, flowid) \
(flow_ring_node_t *)&(((flow_ring_node_t *)((dhdp)->flow_ring_table))[flowid])
@@ -149,17 +204,17 @@ typedef struct flow_queue {
#define DHD_FLOW_QUEUE_SET_L2CLEN(queue, grandparent_clen_ptr) \
((queue)->l2clen_ptr) = (void *)(grandparent_clen_ptr)
/* see wlfc_proto.h for tx status details */
#define DHD_FLOWRING_MAXSTATUS_MSGS 5
#if defined(BCMDBG)
#define DHD_FLOWRING_TXSTATUS_CNT_UPDATE(bus, flowid, txstatus) \
dhd_bus_flow_ring_cnt_update(bus, flowid, txstatus)
#else
#define DHD_FLOWRING_TXSTATUS_CNT_UPDATE(bus, flowid, txstatus)
#endif /* BCMDBG */
/* Pkttag not compatible with PROP_TXSTATUS or WLFC */
typedef struct dhd_pkttag_fr {
uint16 flowid;
uint16 ifid;
int dataoff;
dmaaddr_t physaddr;
uint32 pa_len;
} dhd_pkttag_fr_t;
#define DHD_PKTTAG_SET_IFID(tag, idx) ((tag)->ifid = (uint16)(idx))
@@ -169,13 +224,23 @@ typedef struct dhd_pkttag_fr {
#define DHD_PKTTAG_PA(tag) ((tag)->physaddr)
#define DHD_PKTTAG_PA_LEN(tag) ((tag)->pa_len)
/** each flow ring is dedicated to a tid/sa/da combination */
typedef struct flow_info {
uint8 tid;
uint8 ifindex;
char sa[ETHER_ADDR_LEN];
char da[ETHER_ADDR_LEN];
uchar sa[ETHER_ADDR_LEN];
uchar da[ETHER_ADDR_LEN];
#if defined(BCMDBG)
uint32 tx_status[DHD_MAX_TX_STATUS_MSGS];
#endif
#ifdef TX_STATUS_LATENCY_STATS
/* total number of tx_status received on this flowid */
uint64 num_tx_status;
/* cumulative tx_status latency for this flowid */
uint64 cum_tx_status_latency;
/* num tx packets sent on this flowring */
uint64 num_tx_pkts;
#endif /* TX_STATUS_LATENCY_STATS */
} flow_info_t;
/** a flow ring is used for outbound (towards antenna) 802.3 packets */
@@ -207,7 +272,9 @@ typedef struct flow_ring_node {
/* counter to decide if this particlur flow is stuck or not */
uint32 stuck_count;
#endif /* DEVICE_TX_STUCK_DETECT */
#ifdef DHD_HP2P
bool hp2p_ring;
#endif /* DHD_HP2P */
} flow_ring_node_t;
typedef flow_ring_node_t flow_ring_table_t;
@@ -246,12 +313,15 @@ extern void dhd_flow_queue_reinsert(dhd_pub_t *dhdp, flow_queue_t *queue, void *
extern void dhd_flow_ring_config_thresholds(dhd_pub_t *dhdp, uint16 flowid,
int queue_budget, int cumm_threshold, void *cumm_ctr,
int l2cumm_threshold, void *l2cumm_ctr);
extern int dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_flow_rings);
extern int dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_h2d_rings);
extern void dhd_flow_rings_deinit(dhd_pub_t *dhdp);
extern int dhd_flowid_update(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio,
void *pktbuf);
extern int dhd_flowid_debug_create(dhd_pub_t *dhdp, uint8 ifindex,
uint8 prio, char *sa, char *da, uint16 *flowid);
extern int dhd_flowid_find_by_ifidx(dhd_pub_t *dhdp, uint8 ifidex, uint16 flowid);
extern void dhd_flowid_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid);
@@ -270,6 +340,11 @@ extern int dhd_update_interface_link_status(dhd_pub_t *dhdp, uint8 ifindex,
uint8 status);
extern int dhd_flow_prio_map(dhd_pub_t *dhd, uint8 *map, bool set);
extern int dhd_update_flow_prio_map(dhd_pub_t *dhdp, uint8 map);
extern uint32 dhd_active_tx_flowring_bkpq_len(dhd_pub_t *dhdp);
#ifdef DHD_AWDL
/* DHD handler for awdl peer op IOVAR */
extern void dhd_awdl_peer_op(dhd_pub_t *dhdp, uint8 ifindex,
void *buf, uint32 buflen);
#endif /* DHD_AWDL */
extern uint8 dhd_flow_rings_ifindex2role(dhd_pub_t *dhdp, uint8 ifindex);
#endif /* _dhd_flowrings_h_ */

View File

@@ -0,0 +1,563 @@
/*
* Firmware trace handling on the DHD side. Kernel thread reads the trace data and writes
* to the file and implements various utility functions.
*
* Broadcom Proprietary and Confidential. Copyright (C) 2020,
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
* the contents of this file may not be disclosed to third parties,
* copied or duplicated in any form, in whole or in part, without
* the prior written permission of Broadcom.
*
*
* <<Broadcom-WL-IPTag/Proprietary:>>
*
* $Id$
*/
#ifdef BCMINTERNAL
#ifdef DHD_FWTRACE
#include <typedefs.h>
#include <osl.h>
#include <bcmutils.h>
#include <bcmendian.h>
#include <dngl_stats.h>
#include <dhd.h>
#include <dhd_proto.h>
#include <dhd_dbg.h>
#include <dhd_debug.h>
#include <dhd_fwtrace.h>
static int fwtrace_write_to_file(uint8 *buf, uint16 buf_len, dhd_pub_t *dhdp);
static int fwtrace_close_file(dhd_pub_t *dhdp);
static int fwtrace_open_file(uint32 fw_trace_enabled, dhd_pub_t *dhdp);
static fwtrace_buf_t *fwtrace_get_trace_data_ptr(dhd_pub_t *dhdp);
static void fwtrace_free_trace_buf(dhd_pub_t *dhdp);
typedef struct fwtrace_info {
struct file *fw_trace_fp;
int file_index;
int part_index;
int trace_buf_index;
int trace_buf_count;
uint16 overflow_counter;
char trace_file[TRACE_FILE_NAME_LEN];
fwtrace_buf_t *trace_data_ptr;
uint16 prev_seq;
uint32 fwtrace_enable; /* Enable firmware tracing and the
* trace file management.
*/
struct mutex fwtrace_lock; /* Synchronization between the
* ioctl and the kernel thread.
*/
dhd_dma_buf_t fwtrace_buf; /* firmware trace buffer */
} fwtrace_info_t;
int
dhd_fwtrace_attach(dhd_pub_t *dhdp)
{
fwtrace_info_t *fwtrace_info;
/* Allocate prot structure */
if (!(fwtrace_info = (fwtrace_info_t *)VMALLOCZ(dhdp->osh, sizeof(*fwtrace_info)))) {
DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
return (BCME_NOMEM);
}
bzero(fwtrace_info, sizeof(*fwtrace_info));
dhdp->fwtrace_info = fwtrace_info;
mutex_init(&dhdp->fwtrace_info->fwtrace_lock);
DHD_INFO(("allocated DHD fwtrace\n"));
return BCME_OK;
}
int
dhd_fwtrace_detach(dhd_pub_t *dhdp)
{
fwtrace_info_t *fwtrace_info;
DHD_TRACE(("%s: %d\n", __FUNCTION__, __LINE__));
if (!dhdp) {
return BCME_OK;
}
if (!dhdp->fwtrace_info) {
return BCME_OK;
}
fwtrace_info = dhdp->fwtrace_info;
dhd_dma_buf_free(dhdp, &dhdp->fwtrace_info->fwtrace_buf);
/* close the file if valid */
if (!(IS_ERR_OR_NULL(dhdp->fwtrace_info->fw_trace_fp))) {
(void) filp_close(dhdp->fwtrace_info->fw_trace_fp, 0);
}
mutex_destroy(&dhdp->fwtrace_info->fwtrace_lock);
VMFREE(dhdp->osh, fwtrace_info, sizeof(*fwtrace_info));
dhdp->fwtrace_info = NULL;
DHD_INFO(("Deallocated DHD fwtrace_info\n"));
return (BCME_OK);
}
uint16
get_fw_trace_overflow_counter(dhd_pub_t *dhdp)
{
return (dhdp->fwtrace_info->overflow_counter);
}
void
process_fw_trace_data(dhd_pub_t *dhdp)
{
fwtrace_info_t *fwtrace_info = dhdp->fwtrace_info;
uint16 length;
uint16 incoming_seq;
uint32 trace_buf_index = fwtrace_info->trace_buf_index;
fwtrace_buf_t * trace_buf;
fwtrace_buf_t * curr_buf;
mutex_lock(&fwtrace_info->fwtrace_lock);
if (fwtrace_info->fw_trace_fp == NULL) {
goto done;
}
if ((trace_buf = fwtrace_get_trace_data_ptr(dhdp)) == NULL) {
goto done;
}
do {
curr_buf = trace_buf + trace_buf_index;
length = curr_buf->info.length;
/* If the incoming length is 0, means nothing is updated by the firmware */
if (length == 0) {
break;
}
incoming_seq = curr_buf->info.seq_num;
if (((uint16)(fwtrace_info->prev_seq + 1) != incoming_seq) &&
length != sizeof(*curr_buf)) {
DHD_ERROR(("*** invalid trace len idx = %u, length = %u, "
"cur seq = %u, in-seq = %u \n",
trace_buf_index, length,
fwtrace_info->prev_seq, incoming_seq));
break;
}
DHD_TRACE(("*** TRACE BUS: IDX:%d, in-seq:%d(prev-%d), ptr:%p(%llu), len:%d\n",
trace_buf_index, incoming_seq, fwtrace_info->prev_seq,
curr_buf, (uint64)curr_buf, length));
/* Write trace data to a file */
if (fwtrace_write_to_file((uint8 *) curr_buf, length, dhdp) != BCME_OK) {
DHD_ERROR(("*** fwtrace_write_to_file has failed \n"));
break;
}
/* Reset length after consuming the fwtrace data */
curr_buf->info.length = 0;
if ((fwtrace_info->prev_seq + 1) != incoming_seq) {
DHD_ERROR(("*** seq mismatch, index = %u, length = %u, "
"cur seq = %u, in-seq = %u \n",
trace_buf_index, length,
fwtrace_info->prev_seq, incoming_seq));
}
fwtrace_info->prev_seq = incoming_seq;
trace_buf_index++;
trace_buf_index &= (fwtrace_info->trace_buf_count - 1u);
fwtrace_info->trace_buf_index = trace_buf_index;
} while (true);
done:
mutex_unlock(&fwtrace_info->fwtrace_lock);
return;
}
/*
* Write the incoming trace data to a file. The maximum file size is 1MB. After that
* the trace data is saved into a new file.
*/
static int
fwtrace_write_to_file(uint8 *buf, uint16 buf_len, dhd_pub_t *dhdp)
{
fwtrace_info_t *fwtrace_info = dhdp->fwtrace_info;
int ret_val = BCME_OK;
int ret_val_1 = 0;
mm_segment_t old_fs;
loff_t pos = 0;
struct kstat stat;
int error;
/* Change to KERNEL_DS address limit */
old_fs = get_fs();
set_fs(KERNEL_DS);
if (buf == NULL) {
ret_val = BCME_ERROR;
goto done;
}
if (IS_ERR_OR_NULL(fwtrace_info->fw_trace_fp)) {
ret_val = BCME_ERROR;
goto done;
}
//
// Get the file size
// if the size + buf_len > TRACE_FILE_SIZE, then write to a different file.
//
error = vfs_stat(fwtrace_info->trace_file, &stat);
if (error) {
DHD_ERROR(("vfs_stat has failed with error code = %d\n", error));
goto done;
}
if ((int) stat.size + buf_len > TRACE_FILE_SIZE) {
fwtrace_close_file(dhdp);
(fwtrace_info->part_index)++;
fwtrace_open_file(TRUE, dhdp);
}
pos = fwtrace_info->fw_trace_fp->f_pos;
/* Write buf to file */
ret_val_1 = vfs_write(fwtrace_info->fw_trace_fp,
(char *) buf, (uint32) buf_len, &pos);
if (ret_val_1 < 0) {
DHD_ERROR(("write file error, err = %d\n", ret_val_1));
ret_val = BCME_ERROR;
goto done;
}
fwtrace_info->fw_trace_fp->f_pos = pos;
/* Sync file from filesystem to physical media */
ret_val_1 = vfs_fsync(fwtrace_info->fw_trace_fp, 0);
if (ret_val_1 < 0) {
DHD_ERROR(("sync file error, error = %d\n", ret_val_1));
ret_val = BCME_ERROR;
goto done;
}
done:
/* restore previous address limit */
set_fs(old_fs);
return (ret_val);
}
/*
* Start the trace, gets called from the ioctl handler.
*/
int
fw_trace_start(dhd_pub_t *dhdp, uint32 fw_trace_enabled)
{
int ret_val = BCME_OK;
(dhdp->fwtrace_info->file_index)++;
dhdp->fwtrace_info->part_index = 1;
dhdp->fwtrace_info->trace_buf_index = 0;
mutex_lock(&dhdp->fwtrace_info->fwtrace_lock);
ret_val = fwtrace_open_file(fw_trace_enabled, dhdp);
if (ret_val == BCME_OK) {
dhdp->fwtrace_info->fwtrace_enable = fw_trace_enabled;
}
mutex_unlock(&dhdp->fwtrace_info->fwtrace_lock);
return (ret_val);
}
/*
* Stop the trace collection and close the file descriptor.
*/
int
fw_trace_stop(dhd_pub_t *dhdp)
{
int ret_val = BCME_OK;
/* Check to see if there is any trace data */
process_fw_trace_data(dhdp);
mutex_lock(&dhdp->fwtrace_info->fwtrace_lock); /* acquire lock */
/* flush the trace buffer */
ret_val = fwtrace_close_file(dhdp);
/* free the trace buffer */
fwtrace_free_trace_buf(dhdp);
mutex_unlock(&dhdp->fwtrace_info->fwtrace_lock); /* release the lock */
return (ret_val);
}
/*
* The trace file format is: fw_trace_w_part_x_y_z
* where w is the file index, x is the part index,
* y is in seconds and z is in milliseconds
*
* fw_trace_1_part_1_1539298163209110
* fw_trace_1_part_2_1539298194739003 etc.
*
*/
static int
fwtrace_open_file(uint32 fw_trace_enabled, dhd_pub_t *dhdp)
{
fwtrace_info_t *fwtrace_info = dhdp->fwtrace_info;
int ret_val = BCME_OK;
uint32 file_mode;
char ts_str[DEBUG_DUMP_TIME_BUF_LEN];
if (fw_trace_enabled) {
if (!(IS_ERR_OR_NULL(fwtrace_info->fw_trace_fp))) {
(void) filp_close(fwtrace_info->fw_trace_fp, 0);
}
DHD_INFO((" *** Creating the trace file \n"));
file_mode = O_CREAT | O_WRONLY | O_SYNC;
clear_debug_dump_time(ts_str);
get_debug_dump_time(ts_str);
snprintf(fwtrace_info->trace_file,
sizeof(fwtrace_info->trace_file),
"%sfw_trace_%d_part_%d_%x_%s",
DHD_COMMON_DUMP_PATH, fwtrace_info->file_index,
fwtrace_info->part_index,
dhd_bus_get_bp_base(dhdp),
ts_str);
fwtrace_info->fw_trace_fp =
filp_open(fwtrace_info->trace_file, file_mode, 0664);
if (IS_ERR(fwtrace_info->fw_trace_fp)) {
DHD_ERROR(("Unable to create the fw trace file file: %s\n",
fwtrace_info->trace_file));
ret_val = BCME_ERROR;
goto done;
}
}
done:
return (ret_val);
}
static int
fwtrace_close_file(dhd_pub_t *dhdp)
{
int ret_val = BCME_OK;
if (!(IS_ERR_OR_NULL(dhdp->fwtrace_info->fw_trace_fp))) {
(void) filp_close(dhdp->fwtrace_info->fw_trace_fp, 0);
}
dhdp->fwtrace_info->fw_trace_fp = NULL;
return (ret_val);
}
#define FWTRACE_HADDR_PARAMS_SIZE 256u
#define FW_TRACE_FLUSH 0x8u /* bit 3 */
static int send_fw_trace_val(dhd_pub_t *dhdp, int val);
/*
* Initialize FWTRACE.
* Allocate trace buffer and open trace file.
*/
int
fwtrace_init(dhd_pub_t *dhdp)
{
int ret_val = BCME_OK;
fwtrace_hostaddr_info_t host_buf_info;
if (dhdp->fwtrace_info->fwtrace_buf.va != NULL) {
/* Already initialized */
goto done;
}
ret_val = fwtrace_get_haddr(dhdp, &host_buf_info);
if (ret_val != BCME_OK) {
goto done;
}
DHD_INFO(("dhd_get_trace_haddr: addr = %llx, len = %u\n",
host_buf_info.haddr.u64, host_buf_info.num_bufs));
/* Initialize and setup the file */
ret_val = fw_trace_start(dhdp, TRUE);
done:
return ret_val;
}
/*
* Process the fwtrace set command to enable/disable firmware tracing.
* Always, enable preceeds with disable.
*/
int
handle_set_fwtrace(dhd_pub_t *dhdp, uint32 val)
{
int ret, ret_val = BCME_OK;
/* On set, consider only lower two bytes for now */
dhdp->fwtrace_info->fwtrace_enable = (val & 0xFFFF);
if (val & FW_TRACE_FLUSH) { /* only flush the trace buffer */
if ((ret_val = send_fw_trace_val(dhdp, val)) != BCME_OK) {
goto done;
}
} else if (val == 0) { /* disable the tracing */
/* Disable the trace in the firmware */
if ((ret_val = send_fw_trace_val(dhdp, val)) != BCME_OK) {
goto done;
}
/* cleanup in the driver */
fw_trace_stop(dhdp);
} else { /* enable the tracing */
fwtrace_hostaddr_info_t haddr_info;
ret_val = fwtrace_init(dhdp);
if (ret_val != BCME_OK) {
goto done;
}
if ((ret_val = fwtrace_get_haddr(dhdp, &haddr_info)) != BCME_OK) {
DHD_ERROR(("%s: set dhd_iovar has failed for "
"fw_trace_haddr, "
"ret=%d\n", __FUNCTION__, ret_val));
goto done;
}
ret = dhd_iovar(dhdp, 0, "dngl:fwtrace_haddr",
(char *) &haddr_info, sizeof(haddr_info),
NULL, 0, TRUE);
if (ret < 0) {
DHD_ERROR(("%s: set dhd_iovar has failed for "
"fwtrace_haddr, "
"ret=%d\n", __FUNCTION__, ret));
ret_val = BCME_NOMEM;
goto done;
}
/* Finaly, enable the trace in the firmware */
if ((ret_val = send_fw_trace_val(dhdp, val)) != BCME_OK) {
goto done;
}
}
done:
return (ret_val);
}
/*
* Send dngl:fwtrace IOVAR to the firmware.
*/
static int
send_fw_trace_val(dhd_pub_t *dhdp, int val)
{
int ret_val = BCME_OK;
if ((ret_val = dhd_iovar(dhdp, 0, "dngl:fwtrace", (char *)&val, sizeof(val),
NULL, 0, TRUE)) < 0) {
DHD_ERROR(("%s: set dhd_iovar has failed fwtrace, "
"ret=%d\n", __FUNCTION__, ret_val));
}
return (ret_val);
}
/*
* Returns the virual address for the firmware trace buffer.
* DHD monitors this buffer for an update from the firmware.
*/
static fwtrace_buf_t *
fwtrace_get_trace_data_ptr(dhd_pub_t *dhdp)
{
return ((fwtrace_buf_t *) dhdp->fwtrace_info->fwtrace_buf.va);
}
int
fwtrace_get_haddr(dhd_pub_t *dhdp, fwtrace_hostaddr_info_t *haddr_info)
{
int ret_val = BCME_NOMEM;
int num_host_buffers = FWTRACE_NUM_HOST_BUFFERS;
if (haddr_info == NULL) {
ret_val = BCME_BADARG;
goto done;
}
if (dhdp->fwtrace_info->fwtrace_buf.va != NULL) {
/* Use the existing buffer and send to the firmware */
haddr_info->haddr.u64 = HTOL64(*(uint64 *)
&dhdp->fwtrace_info->fwtrace_buf.pa);
haddr_info->num_bufs = dhdp->fwtrace_info->trace_buf_count;
haddr_info->buf_len = sizeof(fwtrace_buf_t);
ret_val = BCME_OK;
goto done;
}
do {
/* Initialize firmware trace buffer */
if (dhd_dma_buf_alloc(dhdp, &dhdp->fwtrace_info->fwtrace_buf,
sizeof(fwtrace_buf_t) * num_host_buffers) == BCME_OK) {
dhdp->fwtrace_info->trace_buf_count = num_host_buffers;
ret_val = BCME_OK;
break;
}
DHD_ERROR(("%s: Allocing %d buffers of size %lu bytes failed\n",
__FUNCTION__, num_host_buffers,
sizeof(fwtrace_buf_t) * num_host_buffers));
/* Retry with smaller numbers */
num_host_buffers >>= 1;
} while (num_host_buffers > 0);
haddr_info->haddr.u64 = HTOL64(*(uint64 *)&dhdp->fwtrace_info->fwtrace_buf.pa);
haddr_info->num_bufs = num_host_buffers;
haddr_info->buf_len = sizeof(fwtrace_buf_t);
DHD_INFO(("Firmware trace buffer, host address = %llx, count = %u \n",
haddr_info->haddr.u64,
haddr_info->num_bufs));
done:
return (ret_val);
}
/*
* Frees the host buffer.
*/
static void
fwtrace_free_trace_buf(dhd_pub_t *dhdp)
{
dhd_dma_buf_free(dhdp, &dhdp->fwtrace_info->fwtrace_buf);
return;
}
#endif /* DHD_FWTRACE */
#endif /* BCMINTERNAL */

View File

@@ -0,0 +1,55 @@
/*
* Data structures required for the firmware tracing support on Linux.
*
* Broadcom Proprietary and Confidential. Copyright (C) 2020,
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
* the contents of this file may not be disclosed to third parties,
* copied or duplicated in any form, in whole or in part, without
* the prior written permission of Broadcom.
*
*
* <<Broadcom-WL-IPTag/Proprietary:>>
*
* $Id$
*/
#ifndef _DHD_FWTRACE_H
#define _DHD_FWTRACE_H
#ifdef BCMINTERNAL
#ifdef DHD_FWTRACE /* firmware tracing */
#include <dngl_stats.h>
#include <dhd.h>
#include <dhd_proto.h>
#include <dhd_dbg.h>
#include <dhd_debug.h>
#include <dhd_fwtrace.h>
#include <linux/mutex.h>
#include <bcm_fwtrace.h>
#define TRACE_FILE_NAME_LEN 128u /* bytes */
#define TRACE_FILE_SIZE (1024u * 1024u) /* Trace file size is 1 MB */
/* Prototypes */
void dhd_event_logtrace_enqueue_fwtrace(dhd_pub_t *dhdp);
int dhd_fwtrace_attach(dhd_pub_t *dhdinfo);
int dhd_fwtrace_detach(dhd_pub_t *dhdinfo);
void process_fw_trace_data(dhd_pub_t *dhdp);
uint32 dhd_bus_get_bp_base(dhd_pub_t *dhdp);
int fwtrace_init(dhd_pub_t *dhdp);
int fw_trace_start(dhd_pub_t *dhdp, uint32 fw_trace_enabled);
int fw_trace_stop(dhd_pub_t *dhdp);
int handle_set_fwtrace(dhd_pub_t *dhdp, uint32 val);
uint16 get_fw_trace_overflow_counter(dhd_pub_t *dhdp);
int fwtrace_get_haddr(dhd_pub_t *dhdp, fwtrace_hostaddr_info_t *haddr_info);
#endif /* DHD_FWTRACE */
#endif /* BCMINTERNAL */
#endif /* _DHD_FWTRACE_H */

View File

@@ -4,11 +4,6 @@
#include <linux/gpio.h>
#include <linux/rfkill-wlan.h>
#ifdef CUSTOMER_HW_PLATFORM
#include <plat/sdhci.h>
#define sdmmc_channel sdmmc_device_mmc0
#endif /* CUSTOMER_HW_PLATFORM */
#if defined(BUS_POWER_RESTORE) && defined(BCMSDIO)
#include <linux/mmc/core.h>
#include <linux/mmc/card.h>
@@ -20,6 +15,19 @@
extern void *dhd_wlan_mem_prealloc(int section, unsigned long size);
#endif /* CONFIG_DHD_USE_STATIC_BUF */
#ifdef BCMDHD_DTS
/* This is sample code in dts file.
bcmdhd {
compatible = "android,bcmdhd_wlan";
gpio_wl_reg_on = <&gpio GPIOH_4 GPIO_ACTIVE_HIGH>;
gpio_wl_host_wake = <&gpio GPIOZ_15 GPIO_ACTIVE_HIGH>;
};
*/
#define DHD_DT_COMPAT_ENTRY "android,bcmdhd_wlan"
#define GPIO_WL_REG_ON_PROPNAME "gpio_wl_reg_on"
#define GPIO_WL_HOST_WAKE_PROPNAME "gpio_wl_host_wake"
#endif
static int gpio_wl_reg_on = -1; // WL_REG_ON is input pin of WLAN module
#ifdef CUSTOMER_OOB
static int gpio_wl_host_wake = -1; // WL_HOST_WAKE is output pin of WLAN module
@@ -136,18 +144,29 @@ static int dhd_wlan_set_carddetect(int present)
return err;
}
static int dhd_wlan_get_mac_addr(unsigned char *buf)
static int dhd_wlan_get_mac_addr(unsigned char *buf
#ifdef CUSTOM_MULTI_MAC
, char *name
#endif
)
{
int err = 0;
printf("======== %s ========\n", __FUNCTION__);
#ifdef CUSTOM_MULTI_MAC
if (!strcmp("wlan1", name)) {
#ifdef EXAMPLE_GET_MAC
/* EXAMPLE code */
{
struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}};
bcopy((char *)&ea_example, buf, sizeof(struct ether_addr));
}
#endif /* EXAMPLE_GET_MAC */
} else
#endif /* CUSTOM_MULTI_MAC */
{
#ifdef EXAMPLE_GET_MAC
struct ether_addr ea_example = {{0x02, 0x11, 0x22, 0x33, 0x44, 0x55}};
bcopy((char *)&ea_example, buf, sizeof(struct ether_addr));
#endif /* EXAMPLE_GET_MAC */
}
err = rockchip_wifi_mac_addr(buf);
#ifdef EXAMPLE_GET_MAC_VER2
/* EXAMPLE code */
@@ -164,6 +183,8 @@ static int dhd_wlan_get_mac_addr(unsigned char *buf)
}
#endif /* EXAMPLE_GET_MAC_VER2 */
printf("======== %s err=%d ========\n", __FUNCTION__, err);
return err;
}
@@ -238,20 +259,38 @@ struct wifi_platform_data dhd_wlan_control = {
int dhd_wlan_init_gpio(void)
{
#ifdef BCMDHD_DTS
char *wlan_node = DHD_DT_COMPAT_ENTRY;
struct device_node *root_node = NULL;
#endif
int err = 0;
#ifdef CUSTOMER_OOB
int host_oob_irq = -1;
uint host_oob_irq_flags = 0;
#endif
#ifdef HW_OOB
int irq_flags = -1;
#endif
/* Please check your schematic and fill right GPIO number which connected to
* WL_REG_ON and WL_HOST_WAKE.
*/
gpio_wl_reg_on = -1;
#ifdef BCMDHD_DTS
root_node = of_find_compatible_node(NULL, NULL, wlan_node);
if (root_node) {
printf("======== Get GPIO from DTS ========\n");
gpio_wl_reg_on = of_get_named_gpio(root_node, GPIO_WL_REG_ON_PROPNAME, 0);
#ifdef CUSTOMER_OOB
gpio_wl_host_wake = -1;
gpio_wl_host_wake = of_get_named_gpio(root_node, GPIO_WL_HOST_WAKE_PROPNAME, 0);
#endif
} else
#endif
{
gpio_wl_reg_on = -1;
#ifdef CUSTOMER_OOB
gpio_wl_host_wake = -1;
#endif
}
if (gpio_wl_reg_on >= 0) {
err = gpio_request(gpio_wl_reg_on, "WL_REG_ON");

147
drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_ip.c Normal file → Executable file
View File

@@ -1,14 +1,14 @@
/*
* IP Packet Parser Module.
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,15 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_ip.c 700317 2017-05-18 15:13:29Z $
* $Id$
*/
#include <typedefs.h>
#include <osl.h>
@@ -38,12 +34,13 @@
#include <dhd_dbg.h>
#include <dhd_ip.h>
#include <dhd_config.h>
#ifdef DHDTCPACK_SUPPRESS
#if defined(DHDTCPACK_SUPPRESS) || defined(DHDTCPSYNC_FLOOD_BLK)
#include <dhd_bus.h>
#include <dhd_proto.h>
#include <bcmtcp.h>
#endif /* DHDTCPACK_SUPPRESS */
#endif /* DHDTCPACK_SUPPRESS || DHDTCPSYNC_FLOOD_BLK */
/* special values */
/* 802.3 llc/snap header */
@@ -127,7 +124,11 @@ typedef struct {
int ifidx;
uint8 supp_cnt;
dhd_pub_t *dhdp;
#ifndef TCPACK_SUPPRESS_HOLD_HRT
timer_list_compat_t timer;
#else
struct tasklet_hrtimer timer;
#endif /* TCPACK_SUPPRESS_HOLD_HRT */
} tcpack_info_t;
typedef struct _tdata_psh_info_t {
@@ -209,6 +210,7 @@ _tdata_psh_info_pool_deq(tcpack_sup_module_t *tcpack_sup_mod)
return tdata_psh_info;
}
#ifdef BCMSDIO
static int _tdata_psh_info_pool_init(dhd_pub_t *dhdp,
tcpack_sup_module_t *tcpack_sup_mod)
{
@@ -282,43 +284,59 @@ static void _tdata_psh_info_pool_deinit(dhd_pub_t *dhdp,
ASSERT(i == TCPDATA_PSH_INFO_MAXNUM);
MFREE(dhdp->osh, tcpack_sup_mod->tdata_psh_info_pool,
sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM);
tcpack_sup_mod->tdata_psh_info_pool = NULL;
return;
}
#endif /* BCMSDIO */
#ifdef BCMPCIE
#ifndef TCPACK_SUPPRESS_HOLD_HRT
static void dhd_tcpack_send(ulong data)
#else
static enum hrtimer_restart dhd_tcpack_send(struct hrtimer *timer)
#endif /* TCPACK_SUPPRESS_HOLD_HRT */
{
tcpack_sup_module_t *tcpack_sup_mod;
tcpack_info_t *cur_tbl = (tcpack_info_t *)data;
tcpack_info_t *cur_tbl;
dhd_pub_t *dhdp;
int ifidx;
void* pkt;
unsigned long flags;
#ifndef TCPACK_SUPPRESS_HOLD_HRT
cur_tbl = (tcpack_info_t *)data;
#else
cur_tbl = container_of(timer, tcpack_info_t, timer.timer);
#endif /* TCPACK_SUPPRESS_HOLD_HRT */
if (!cur_tbl) {
return;
goto done;
}
dhdp = cur_tbl->dhdp;
if (!dhdp) {
return;
goto done;
}
flags = dhd_os_tcpacklock(dhdp);
if (unlikely(dhdp->tcpack_sup_mode != TCPACK_SUP_HOLD)) {
dhd_os_tcpackunlock(dhdp, flags);
goto done;
}
tcpack_sup_mod = dhdp->tcpack_sup_module;
if (!tcpack_sup_mod) {
DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n",
__FUNCTION__, __LINE__));
dhd_os_tcpackunlock(dhdp, flags);
return;
goto done;
}
pkt = cur_tbl->pkt_in_q;
ifidx = cur_tbl->ifidx;
if (!pkt) {
dhd_os_tcpackunlock(dhdp, flags);
return;
goto done;
}
cur_tbl->pkt_in_q = NULL;
cur_tbl->pkt_ether_hdr = NULL;
@@ -332,7 +350,15 @@ static void dhd_tcpack_send(ulong data)
dhd_os_tcpackunlock(dhdp, flags);
dhd_sendpkt(dhdp, ifidx, pkt);
done:
#ifndef TCPACK_SUPPRESS_HOLD_HRT
return;
#else
return HRTIMER_NORESTART;
#endif /* TCPACK_SUPPRESS_HOLD_HRT */
}
#endif /* BCMPCIE */
int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode)
{
@@ -347,7 +373,6 @@ int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode)
tcpack_sup_module = dhdp->tcpack_sup_module;
prev_mode = dhdp->tcpack_sup_mode;
/* Check a new mode */
if (prev_mode == mode) {
DHD_ERROR(("%s %d: already set to %d\n", __FUNCTION__, __LINE__, mode));
goto exit;
@@ -387,6 +412,7 @@ int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode)
}
bzero(tcpack_sup_module, sizeof(tcpack_sup_module_t));
break;
#ifdef BCMSDIO
case TCPACK_SUP_DELAYTX:
if (tcpack_sup_module) {
/* We won't need tdata_psh_info pool and
@@ -410,6 +436,7 @@ int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode)
goto exit;
}
break;
#endif /* BCMSDIO */
}
/* Update a new mode */
@@ -428,7 +455,11 @@ int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode)
for (i = 0; i < TCPACK_INFO_MAXNUM; i++) {
tcpack_info_t *tcpack_info_tbl =
&tcpack_sup_module->tcpack_info_tbl[i];
#ifndef TCPACK_SUPPRESS_HOLD_HRT
del_timer(&tcpack_info_tbl->timer);
#else
hrtimer_cancel(&tcpack_info_tbl->timer.timer);
#endif /* TCPACK_SUPPRESS_HOLD_HRT */
if (tcpack_info_tbl->pkt_in_q) {
PKTFREE(dhdp->osh,
tcpack_info_tbl->pkt_in_q, TRUE);
@@ -443,6 +474,7 @@ int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode)
__FUNCTION__, __LINE__));
}
break;
#ifdef BCMSDIO
case TCPACK_SUP_REPLACE:
/* There is nothing to configure for this mode */
break;
@@ -457,16 +489,25 @@ int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode)
dhd_bus_set_dotxinrx(dhdp->bus, FALSE);
}
break;
#endif /* BCMSDIO */
#ifdef BCMPCIE
case TCPACK_SUP_HOLD:
dhdp->tcpack_sup_ratio = CUSTOM_TCPACK_SUPP_RATIO;
dhdp->tcpack_sup_delay = CUSTOM_TCPACK_DELAY_TIME;
dhdp->tcpack_sup_ratio = dhdp->conf->tcpack_sup_ratio;
dhdp->tcpack_sup_delay = dhdp->conf->tcpack_sup_delay;
for (i = 0; i < TCPACK_INFO_MAXNUM; i++) {
tcpack_info_t *tcpack_info_tbl =
&tcpack_sup_module->tcpack_info_tbl[i];
tcpack_info_tbl->dhdp = dhdp;
init_timer_compat(&tcpack_info_tbl->timer, dhd_tcpack_send, tcpack_info_tbl);
#ifndef TCPACK_SUPPRESS_HOLD_HRT
init_timer_compat(&tcpack_info_tbl->timer, dhd_tcpack_send,
tcpack_info_tbl);
#else
tasklet_hrtimer_init(&tcpack_info_tbl->timer,
dhd_tcpack_send, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
#endif /* TCPACK_SUPPRESS_HOLD_HRT */
}
break;
#endif /* BCMPCIE */
}
exit:
@@ -513,7 +554,11 @@ dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp)
if (dhdp->tcpack_sup_mode == TCPACK_SUP_HOLD) {
for (i = 0; i < TCPACK_INFO_MAXNUM; i++) {
#ifndef TCPACK_SUPPRESS_HOLD_HRT
del_timer_sync(&tcpack_sup_mod->tcpack_info_tbl[i].timer);
#else
hrtimer_cancel(&tcpack_sup_mod->tcpack_info_tbl[i].timer.timer);
#endif /* TCPACK_SUPPRESS_HOLD_HRT */
}
}
@@ -683,7 +728,6 @@ dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt)
bool set_dotxinrx = TRUE;
unsigned long flags;
if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF)
goto exit;
@@ -1286,7 +1330,11 @@ dhd_tcpack_hold(dhd_pub_t *dhdp, void *pkt, int ifidx)
dhd_os_tcpackunlock(dhdp, flags);
if (!hold) {
#ifndef TCPACK_SUPPRESS_HOLD_HRT
del_timer_sync(&tcpack_info_tbl[i].timer);
#else
hrtimer_cancel(&tcpack_sup_mod->tcpack_info_tbl[i].timer.timer);
#endif /* TCPACK_SUPPRESS_HOLD_HRT */
}
goto exit;
}
@@ -1303,8 +1351,14 @@ dhd_tcpack_hold(dhd_pub_t *dhdp, void *pkt, int ifidx)
tcpack_info_tbl[free_slot].pkt_ether_hdr = new_ether_hdr;
tcpack_info_tbl[free_slot].ifidx = ifidx;
tcpack_info_tbl[free_slot].supp_cnt = 1;
#ifndef TCPACK_SUPPRESS_HOLD_HRT
mod_timer(&tcpack_sup_mod->tcpack_info_tbl[free_slot].timer,
jiffies + msecs_to_jiffies(dhdp->tcpack_sup_delay));
#else
tasklet_hrtimer_start(&tcpack_sup_mod->tcpack_info_tbl[free_slot].timer,
ktime_set(0, dhdp->tcpack_sup_delay*1000000),
HRTIMER_MODE_REL);
#endif /* TCPACK_SUPPRESS_HOLD_HRT */
tcpack_sup_mod->tcpack_info_cnt++;
} else {
DHD_TRACE(("%s %d: No empty tcp ack info tbl\n",
@@ -1316,3 +1370,54 @@ exit:
return hold;
}
#endif /* DHDTCPACK_SUPPRESS */
#ifdef DHDTCPSYNC_FLOOD_BLK
tcp_hdr_flag_t
dhd_tcpdata_get_flag(dhd_pub_t *dhdp, void *pkt)
{
uint8 *ether_hdr; /* Ethernet header of the new packet */
uint16 ether_type; /* Ethernet type of the new packet */
uint8 *ip_hdr; /* IP header of the new packet */
uint8 *tcp_hdr; /* TCP header of the new packet */
uint32 ip_hdr_len; /* IP header length of the new packet */
uint32 cur_framelen;
uint8 flags;
ether_hdr = PKTDATA(dhdp->osh, pkt);
cur_framelen = PKTLEN(dhdp->osh, pkt);
ether_type = ether_hdr[12] << 8 | ether_hdr[13];
if (ether_type != ETHER_TYPE_IP) {
DHD_TRACE(("%s %d: Not a IP packet 0x%x\n",
__FUNCTION__, __LINE__, ether_type));
return FLAG_OTHERS;
}
ip_hdr = ether_hdr + ETHER_HDR_LEN;
cur_framelen -= ETHER_HDR_LEN;
if (cur_framelen < IPV4_MIN_HEADER_LEN) {
return FLAG_OTHERS;
}
ip_hdr_len = IPV4_HLEN(ip_hdr);
if (IP_VER(ip_hdr) != IP_VER_4 || IPV4_PROT(ip_hdr) != IP_PROT_TCP) {
DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n",
__FUNCTION__, __LINE__, IP_VER(ip_hdr), IPV4_PROT(ip_hdr)));
return FLAG_OTHERS;
}
tcp_hdr = ip_hdr + ip_hdr_len;
flags = (uint8)tcp_hdr[TCP_FLAGS_OFFSET];
if (flags & TCP_FLAG_SYN) {
if (flags & TCP_FLAG_ACK) {
return FLAG_SYNCACK;
}
return FLAG_SYNC;
}
return FLAG_OTHERS;
}
#endif /* DHDTCPSYNC_FLOOD_BLK */

View File

@@ -3,14 +3,14 @@
*
* Provides type definitions and function prototypes used to parse ip packet.
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -18,25 +18,21 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_ip.h 536854 2015-02-24 13:17:29Z $
* $Id$
*/
#ifndef _dhd_ip_h_
#define _dhd_ip_h_
#ifdef DHDTCPACK_SUPPRESS
#if defined(DHDTCPACK_SUPPRESS) || defined(DHDTCPSYNC_FLOOD_BLK)
#include <dngl_stats.h>
#include <bcmutils.h>
#include <dhd.h>
#endif /* DHDTCPACK_SUPPRESS */
#endif /* DHDTCPACK_SUPPRESS || DHDTCPSYNC_FLOOD_BLK */
typedef enum pkt_frag
{
@@ -48,6 +44,17 @@ typedef enum pkt_frag
extern pkt_frag_t pkt_frag_info(osl_t *osh, void *p);
#ifdef DHDTCPSYNC_FLOOD_BLK
typedef enum tcp_hdr_flags {
FLAG_SYNC,
FLAG_SYNCACK,
FLAG_RST,
FLAG_OTHERS
} tcp_hdr_flag_t;
extern tcp_hdr_flag_t dhd_tcpdata_get_flag(dhd_pub_t *dhdp, void *pkt);
#endif /* DHDTCPSYNC_FLOOD_BLK */
#ifdef DHDTCPACK_SUPPRESS
#define TCPACKSZMIN (ETHER_HDR_LEN + IPV4_MIN_HEADER_LEN + TCP_MIN_HEADER_LEN)
/* Size of MAX possible TCP ACK packet. Extra bytes for IP/TCP option fields */

22789
drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_linux.c Normal file → Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,14 @@
/*
* DHD Linux header file (dhd_linux exports for cfg80211 and other components)
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,15 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_linux.h 699532 2017-05-15 11:00:39Z $
* $Id$
*/
/* wifi platform functions for power, interrupt and pre-alloc, either
@@ -51,6 +47,23 @@
#include <linux/earlysuspend.h>
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */
#ifdef BCMPCIE
#include <bcmmsgbuf.h>
#endif /* BCMPCIE */
#ifdef PCIE_FULL_DONGLE
#include <etd.h>
#endif /* PCIE_FULL_DONGLE */
#ifdef WL_MONITOR
#ifdef HOST_RADIOTAP_CONV
#include <bcmwifi_monitor.h>
#else
#define MAX_RADIOTAP_SIZE 256 /* Maximum size to hold HE Radiotap header format */
#define MAX_MON_PKT_SIZE (4096 + MAX_RADIOTAP_SIZE)
#endif /* HOST_RADIOTAP_CONV */
#endif /* WL_MONITOR */
/* dongle status */
enum wifi_adapter_status {
WIFI_STATUS_POWER_ON = 0,
@@ -81,10 +94,9 @@ typedef struct wifi_adapter_info {
uint slot_num;
wait_queue_head_t status_event;
unsigned long status;
#if defined(BT_OVER_SDIO)
#if defined (BT_OVER_SDIO)
const char *btfw_path;
#endif /* defined (BT_OVER_SDIO) */
#ifdef BUS_POWER_RESTORE
#if defined(BCMSDIO)
struct sdio_func *sdio_func;
#endif /* BCMSDIO */
@@ -92,27 +104,13 @@ typedef struct wifi_adapter_info {
struct pci_dev *pci_dev;
struct pci_saved_state *pci_saved_state;
#endif /* BCMPCIE */
#endif
} wifi_adapter_info_t;
#define WLAN_PLAT_NODFS_FLAG 0x01
#define WLAN_PLAT_AP_FLAG 0x02
struct wifi_platform_data {
#ifdef BUS_POWER_RESTORE
int (*set_power)(int val, wifi_adapter_info_t *adapter);
#if defined(CONFIG_WIFI_CONTROL_FUNC) || defined(CUSTOMER_HW4)
#include <linux/wlan_plat.h>
#else
int (*set_power)(int val);
#endif
int (*set_reset)(int val);
int (*set_carddetect)(int val);
void *(*mem_prealloc)(int section, unsigned long size);
int (*get_mac_addr)(unsigned char *buf);
#ifdef CUSTOM_FORCE_NODFS_FLAG
void *(*get_country_code)(char *ccode, u32 flags);
#else /* defined (CUSTOM_FORCE_NODFS_FLAG) */
void *(*get_country_code)(char *ccode);
#endif
};
#include <dhd_plat.h>
#endif /* CONFIG_WIFI_CONTROL_FUNC */
typedef struct bcmdhd_wifi_platdata {
uint num_adapters;
@@ -134,6 +132,335 @@ typedef struct dhd_sta {
} dhd_sta_t;
typedef dhd_sta_t dhd_sta_pool_t;
#ifdef DHD_4WAYM4_FAIL_DISCONNECT
typedef enum {
NONE_4WAY,
M1_4WAY,
M2_4WAY,
M3_4WAY,
M4_4WAY
} msg_4way_t;
typedef enum {
M3_RXED,
M4_TXFAILED
} msg_4way_state_t;
#define MAX_4WAY_TIMEOUT_MS 2000
#endif /* DHD_4WAYM4_FAIL_DISCONNECT */
#if defined(DHD_LB)
/* Dynamic CPU selection for load balancing. */
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/notifier.h>
#include <linux/workqueue.h>
#include <asm/atomic.h>
/* FIXME: Make this a module param or a sysfs. */
#if !defined(DHD_LB_PRIMARY_CPUS)
#define DHD_LB_PRIMARY_CPUS 0x0 /* Big CPU coreids mask */
#endif
#if !defined(DHD_LB_SECONDARY_CPUS)
#define DHD_LB_SECONDARY_CPUS 0xFE /* Little CPU coreids mask */
#endif
#define HIST_BIN_SIZE 9
#if defined(DHD_LB_TXP)
/* Pkttag not compatible with PROP_TXSTATUS or WLFC */
typedef struct dhd_tx_lb_pkttag_fr {
struct net_device *net;
int ifidx;
} dhd_tx_lb_pkttag_fr_t;
#define DHD_LB_TX_PKTTAG_SET_NETDEV(tag, netdevp) ((tag)->net = netdevp)
#define DHD_LB_TX_PKTTAG_NETDEV(tag) ((tag)->net)
#define DHD_LB_TX_PKTTAG_SET_IFIDX(tag, ifidx) ((tag)->ifidx = ifidx)
#define DHD_LB_TX_PKTTAG_IFIDX(tag) ((tag)->ifidx)
#endif /* DHD_LB_TXP */
#endif /* DHD_LB */
#define FILE_DUMP_MAX_WAIT_TIME 4000
#ifdef IL_BIGENDIAN
#include <bcmendian.h>
#define htod32(i) (bcmswap32(i))
#define htod16(i) (bcmswap16(i))
#define dtoh32(i) (bcmswap32(i))
#define dtoh16(i) (bcmswap16(i))
#define htodchanspec(i) htod16(i)
#define dtohchanspec(i) dtoh16(i)
#else
#define htod32(i) (i)
#define htod16(i) (i)
#define dtoh32(i) (i)
#define dtoh16(i) (i)
#define htodchanspec(i) (i)
#define dtohchanspec(i) (i)
#endif /* IL_BIGENDINA */
#if defined(DHD_TCP_WINSIZE_ADJUST)
#define MIN_TCP_WIN_SIZE 18000
#define WIN_SIZE_SCALE_FACTOR 2
#define MAX_TARGET_PORTS 5
#endif /* DHD_TCP_WINSIZE_ADJUST */
#ifdef BLOCK_IPV6_PACKET
#define HEX_PREF_STR "0x"
#define UNI_FILTER_STR "010000000000"
#define ZERO_ADDR_STR "000000000000"
#define ETHER_TYPE_STR "0000"
#define IPV6_FILTER_STR "20"
#define ZERO_TYPE_STR "00"
#endif /* BLOCK_IPV6_PACKET */
#if defined(OEM_ANDROID) && defined(SOFTAP)
extern bool ap_cfg_running;
extern bool ap_fw_loaded;
#endif
#if defined(OEM_ANDROID) && defined(BCMPCIE)
extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd, int *dtim_period, int *bcn_interval);
#else
extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd);
#endif /* OEM_ANDROID && BCMPCIE */
#ifdef CUSTOMER_HW4
#ifdef MIMO_ANT_SETTING
#ifdef DHD_EXPORT_CNTL_FILE
extern unsigned long antsel;
#endif /* DHD_EXPORT_CNTL_FILE */
extern int dhd_sel_ant_from_file(dhd_pub_t *dhd);
#endif /* MIMO_ANT_SETTING */
#ifdef WRITE_WLANINFO
#define MAX_VERSION_LEN 512
#ifdef DHD_EXPORT_CNTL_FILE
extern char version_info[MAX_VERSION_LEN];
#endif /* DHD_EXPORT_CNTL_FILE */
extern uint32 sec_save_wlinfo(char *firm_ver, char *dhd_ver, char *nvram_p, char *clm_ver);
#endif /* WRITE_WLANINFO */
#ifdef LOGTRACE_FROM_FILE
extern int dhd_logtrace_from_file(dhd_pub_t *dhd);
#ifdef DHD_EXPORT_CNTL_FILE
extern unsigned long logtrace_val;
#endif /* DHD_EXPORT_CNTL_FILE */
#endif /* LOGTRACE_FROM_FILE */
#ifdef GEN_SOFTAP_INFO_FILE
#define SOFTAP_INFO_BUF_SZ 512
#ifdef DHD_EXPORT_CNTL_FILE
extern char softapinfostr[SOFTAP_INFO_BUF_SZ];
#endif /* DHD_EXPORT_CNTL_FILE */
extern uint32 sec_save_softap_info(void);
#endif /* GEN_SOFTAP_INFO_FILE */
#endif /* CUSTOMER_HW4 */
#ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
extern uint32 report_hang_privcmd_err;
#endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
#if defined(SOFTAP_TPUT_ENHANCE)
extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time);
extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int* idle_time);
#endif /* SOFTAP_TPUT_ENHANCE */
#if defined(BCM_ROUTER_DHD)
void traffic_mgmt_pkt_set_prio(dhd_pub_t *dhdp, void * pktbuf);
#endif /* BCM_ROUTER_DHD */
#ifdef DHD_LOG_DUMP
/* 0: DLD_BUF_TYPE_GENERAL, 1: DLD_BUF_TYPE_PRESERVE
* 2: DLD_BUF_TYPE_SPECIAL
*/
#define DLD_BUFFER_NUM 3
#ifndef CUSTOM_LOG_DUMP_BUFSIZE_MB
#define CUSTOM_LOG_DUMP_BUFSIZE_MB 4 /* DHD_LOG_DUMP_BUF_SIZE 4 MB static memory in kernel */
#endif /* CUSTOM_LOG_DUMP_BUFSIZE_MB */
#define LOG_DUMP_TOTAL_BUFSIZE (1024 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB)
/*
* Below are different sections that use the prealloced buffer
* and sum of the sizes of these should not cross LOG_DUMP_TOTAL_BUFSIZE
*/
#ifdef EWP_BCM_TRACE
#define LOG_DUMP_GENERAL_MAX_BUFSIZE (192 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB)
#define LOG_DUMP_BCM_TRACE_MAX_BUFSIZE (64 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB)
#else
#define LOG_DUMP_GENERAL_MAX_BUFSIZE (256 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB)
#define LOG_DUMP_BCM_TRACE_MAX_BUFSIZE 0
#endif /* EWP_BCM_TRACE */
#define LOG_DUMP_PRESERVE_MAX_BUFSIZE (128 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB)
#define LOG_DUMP_ECNTRS_MAX_BUFSIZE (256 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB)
#define LOG_DUMP_RTT_MAX_BUFSIZE (256 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB)
#define LOG_DUMP_FILTER_MAX_BUFSIZE (128 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB)
#if LOG_DUMP_TOTAL_BUFSIZE < \
(LOG_DUMP_GENERAL_MAX_BUFSIZE + LOG_DUMP_PRESERVE_MAX_BUFSIZE + \
LOG_DUMP_ECNTRS_MAX_BUFSIZE + LOG_DUMP_RTT_MAX_BUFSIZE + \
LOG_DUMP_BCM_TRACE_MAX_BUFSIZE + LOG_DUMP_FILTER_MAX_BUFSIZE)
#error "LOG_DUMP_TOTAL_BUFSIZE is lesser than sum of all rings"
#endif
/* Special buffer is allocated as separately in prealloc */
#define LOG_DUMP_SPECIAL_MAX_BUFSIZE (8 * 1024)
#define LOG_DUMP_MAX_FILESIZE (8 *1024 * 1024) /* 8 MB default */
#ifdef CONFIG_LOG_BUF_SHIFT
/* 15% of kernel log buf size, if for example klog buf size is 512KB
* 15% of 512KB ~= 80KB
*/
#define LOG_DUMP_KERNEL_TAIL_FLUSH_SIZE \
(15 * ((1 << CONFIG_LOG_BUF_SHIFT)/100))
#endif /* CONFIG_LOG_BUF_SHIFT */
#define LOG_DUMP_COOKIE_BUFSIZE 1024u
typedef struct {
char *hdr_str;
log_dump_section_type_t sec_type;
} dld_hdr_t;
#define DHD_PRINT_BUF_NAME_LEN 30
void dhd_get_debug_dump_len(void *handle, struct sk_buff *skb, void *event_info, u8 event);
void cfgvendor_log_dump_len(dhd_pub_t *dhdp, log_dump_type_t *type, struct sk_buff *skb);
#endif /* DHD_LOG_DUMP */
typedef struct dhd_if_event {
struct list_head list;
wl_event_data_if_t event;
char name[IFNAMSIZ+1];
uint8 mac[ETHER_ADDR_LEN];
} dhd_if_event_t;
/* Interface control information */
typedef struct dhd_if {
struct dhd_info *info; /* back pointer to dhd_info */
/* OS/stack specifics */
struct net_device *net;
int idx; /* iface idx in dongle */
uint subunit; /* subunit */
uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */
bool set_macaddress;
bool set_multicast;
uint8 bssidx; /* bsscfg index for the interface */
bool attached; /* Delayed attachment when unset */
bool txflowcontrol; /* Per interface flow control indicator */
char name[IFNAMSIZ+1]; /* linux interface name */
char dngl_name[IFNAMSIZ+1]; /* corresponding dongle interface name */
struct net_device_stats stats;
#ifdef DHD_WMF
dhd_wmf_t wmf; /* per bsscfg wmf setting */
bool wmf_psta_disable; /* enable/disable MC pkt to each mac
* of MC group behind PSTA
*/
#endif /* DHD_WMF */
#ifdef PCIE_FULL_DONGLE
struct list_head sta_list; /* sll of associated stations */
spinlock_t sta_list_lock; /* lock for manipulating sll */
#endif /* PCIE_FULL_DONGLE */
uint32 ap_isolate; /* ap-isolation settings */
#ifdef DHD_L2_FILTER
bool parp_enable;
bool parp_discard;
bool parp_allnode;
arp_table_t *phnd_arp_table;
/* for Per BSS modification */
bool dhcp_unicast;
bool block_ping;
bool grat_arp;
bool block_tdls;
#endif /* DHD_L2_FILTER */
#if (defined(BCM_ROUTER_DHD) && defined(QOS_MAP_SET))
uint8 *qosmap_up_table; /* user priority table, size is UP_TABLE_MAX */
bool qosmap_up_table_enable; /* flag set only when app want to set additional UP */
#endif /* BCM_ROUTER_DHD && QOS_MAP_SET */
#ifdef DHD_MCAST_REGEN
bool mcast_regen_bss_enable;
#endif
bool rx_pkt_chainable; /* set all rx packet to chainable config by default */
cumm_ctr_t cumm_ctr; /* cummulative queue length of child flowrings */
#ifdef BCM_ROUTER_DHD
bool primsta_dwds; /* DWDS status of primary sta interface */
#endif /* BCM_ROUTER_DHD */
uint8 tx_paths_active;
bool del_in_progress;
bool static_if; /* used to avoid some operations on static_if */
#ifdef DHD_4WAYM4_FAIL_DISCONNECT
struct delayed_work m4state_work;
atomic_t m4state;
#endif /* DHD_4WAYM4_FAIL_DISCONNECT */
#ifdef DHDTCPSYNC_FLOOD_BLK
uint32 tsync_rcvd;
uint32 tsyncack_txed;
u64 last_sync;
struct work_struct blk_tsfl_work;
uint32 tsync_per_sec;
bool disconnect_tsync_flood;
#endif /* DHDTCPSYNC_FLOOD_BLK */
#ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
bool recv_reassoc_evt;
bool post_roam_evt;
#endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
#ifdef WLEASYMESH
uint8 _1905_al_ucast[ETHER_ADDR_LEN];
uint8 _1905_al_mcast[ETHER_ADDR_LEN];
#endif /* WLEASYMESH */
} dhd_if_t;
struct ipv6_work_info_t {
uint8 if_idx;
char ipv6_addr[IPV6_ADDR_LEN];
unsigned long event;
};
typedef struct dhd_dump {
uint8 *buf;
int bufsize;
uint8 *hscb_buf;
int hscb_bufsize;
} dhd_dump_t;
#ifdef DNGL_AXI_ERROR_LOGGING
typedef struct dhd_axi_error_dump {
ulong fault_address;
uint32 axid;
struct hnd_ext_trap_axi_error_v1 etd_axi_error_v1;
} dhd_axi_error_dump_t;
#endif /* DNGL_AXI_ERROR_LOGGING */
#ifdef BCM_ROUTER_DHD
typedef struct dhd_write_file {
char file_path[64];
uint32 file_flags;
uint8 *buf;
int bufsize;
} dhd_write_file_t;
#endif
#ifdef DHD_PCIE_NATIVE_RUNTIMEPM
struct dhd_rx_tx_work {
struct work_struct work;
struct sk_buff *skb;
struct net_device *net;
struct dhd_pub *pub;
};
#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
#ifdef FILTER_IE
#define FILTER_IE_PATH "/vendor/etc/wifi/filter_ie"
#define FILTER_IE_BUFSZ 1024 /* ioc buffsize for FILTER_IE */
#define FILE_BLOCK_READ_SIZE 256
#define WL_FILTER_IE_IOV_HDR_SIZE OFFSETOF(wl_filter_ie_iov_v1_t, tlvs)
#endif /* FILTER_IE */
#define NULL_CHECK(p, s, err) \
do { \
if (!(p)) { \
printk("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \
err = BCME_ERROR; \
return err; \
} \
} while (0)
int dhd_wifi_platform_register_drv(void);
void dhd_wifi_platform_unregister_drv(void);
wifi_adapter_info_t* dhd_wifi_platform_attach_adapter(uint32 bus_type,
@@ -143,7 +470,11 @@ wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_n
int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long msec);
int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present);
int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr);
int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf);
int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf, char *name);
#ifdef DHD_COREDUMP
int wifi_platform_set_coredump(wifi_adapter_info_t *adapter, const char *buf, int buf_len,
const char *info);
#endif /* DHD_COREDUMP */
#ifdef CUSTOM_COUNTRY_CODE
void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode,
u32 flags);
@@ -155,7 +486,9 @@ void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter);
int dhd_get_fw_mode(struct dhd_info *dhdinfo);
bool dhd_update_fw_nv_path(struct dhd_info *dhdinfo);
#ifdef BCM_ROUTER_DHD
void dhd_update_dpsta_interface_for_sta(dhd_pub_t* dhdp, int ifidx, void* event_data);
#endif /* BCM_ROUTER_DHD */
#ifdef DHD_WMF
dhd_wmf_t* dhd_wmf_conf(dhd_pub_t *dhdp, uint32 idx);
int dhd_get_wmf_psta_disable(dhd_pub_t *dhdp, uint32 idx);
@@ -163,25 +496,23 @@ int dhd_set_wmf_psta_disable(dhd_pub_t *dhdp, uint32 idx, int val);
void dhd_update_psta_interface_for_sta(dhd_pub_t *dhdp, char* ifname,
void* mac_addr, void* event_data);
#endif /* DHD_WMF */
#if defined(BT_OVER_SDIO)
#if defined (BT_OVER_SDIO)
int dhd_net_bus_get(struct net_device *dev);
int dhd_net_bus_put(struct net_device *dev);
#endif /* BT_OVER_SDIO */
#ifdef HOFFLOAD_MODULES
extern void dhd_free_module_memory(struct dhd_bus *bus, struct module_metadata *hmem);
extern void* dhd_alloc_module_memory(struct dhd_bus *bus, uint32_t size,
struct module_metadata *hmem);
#endif /* HOFFLOAD_MODULES */
#if defined(WLADPS) || defined(WLADPS_PRIVATE_CMD)
#define ADPS_ENABLE 1
#define ADPS_DISABLE 0
typedef struct bcm_iov_buf {
uint16 version;
uint16 len;
uint16 id;
uint16 data[1];
} bcm_iov_buf_t;
int dhd_enable_adps(dhd_pub_t *dhd, uint8 on);
#endif /* WLADPS || WLADPS_PRIVATE_CMD */
#ifdef DHDTCPSYNC_FLOOD_BLK
extern void dhd_reset_tcpsync_info_by_ifp(dhd_if_t *ifp);
extern void dhd_reset_tcpsync_info_by_dev(struct net_device *dev);
#endif /* DHDTCPSYNC_FLOOD_BLK */
#ifdef PCIE_FULL_DONGLE
extern void dhd_net_del_flowrings_sta(dhd_pub_t * dhd, struct net_device * ndev);
#endif /* PCIE_FULL_DONGLE */
int dhd_get_fw_capabilities(dhd_pub_t * dhd);
#endif /* __DHD_LINUX_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Packet dump helper functions
*
* Copyright (C) 1999-2019, Broadcom.
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -18,14 +17,10 @@
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_linux_pktdump.c 820929 2019-05-21 14:09:11Z $
* $Id$
*/
#include <typedefs.h>
@@ -44,9 +39,10 @@
#include <bcmicmp.h>
#include <dhd_linux_pktdump.h>
#include <dhd_config.h>
#include <wl_android.h>
#define DHD_PKTDUMP(arg) DHD_ERROR(arg)
#define DHD_PKTDUMP_MEM(arg) DHD_ERROR(arg)
#define DHD_PKTDUMP(arg) printk arg
#define DHD_PKTDUMP_MEM(arg) printk arg
#define PACKED_STRUCT __attribute__ ((packed))
#define EAPOL_HDR_LEN 4
@@ -162,6 +158,7 @@ typedef struct pkt_cnt_log {
#define PKT_CNT_RSN_VALID(rsn) \
(((rsn) > (PKT_CNT_RSN_INVALID)) && ((rsn) < (PKT_CNT_RSN_MAX)))
#ifdef DHD_PKTDUMP_ROAM
static const char pkt_cnt_msg[][20] = {
"INVALID",
"ROAM_SUCCESS",
@@ -169,6 +166,7 @@ static const char pkt_cnt_msg[][20] = {
"CONNECT_SUCCESS",
"INVALID"
};
#endif
static const char tx_pktfate[][30] = {
"TX_PKT_FATE_ACKED", /* 0: WLFC_CTL_PKTFLAG_DISCARD */
@@ -202,12 +200,12 @@ static const char tx_pktfate[][30] = {
do { \
if (dump_msg_level & DUMP_EAPOL_VAL) { \
if (tx) { \
DHD_PKTDUMP(("[dhd-%s] 802_1X " x " [TX] : (%s) %s (%s)"TXFATE_FMT"\n", \
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] 802_1X " x " [TX] : (%s) %s (%s)"TXFATE_FMT"\n", \
ifname, ## args, \
tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf, \
TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
} else { \
DHD_PKTDUMP(("[dhd-%s] 802_1X " x " [RX] : (%s) %s (%s)\n", \
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] 802_1X " x " [RX] : (%s) %s (%s)\n", \
ifname, ## args, \
tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf)); \
} \
@@ -218,12 +216,12 @@ static const char tx_pktfate[][30] = {
do { \
if (dump_msg_level & DUMP_EAPOL_VAL) { \
if (tx) { \
DHD_PKTDUMP(("[dhd-%s] 802_1X " x " [TX] : (%s) %s (%s)"DBGREPLAY TXFATE_FMT"\n", \
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] 802_1X " x " [TX] : (%s) %s (%s)"DBGREPLAY TXFATE_FMT"\n", \
ifname, ## args, \
tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf, \
REPLAY_FMT(eap_key), TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
} else { \
DHD_PKTDUMP(("[dhd-%s] 802_1X " x " [RX] : (%s) %s (%s)"DBGREPLAY"\n", \
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] 802_1X " x " [RX] : (%s) %s (%s)"DBGREPLAY"\n", \
ifname, ## args, \
tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf, \
REPLAY_FMT(eap_key))); \
@@ -235,14 +233,14 @@ static const char tx_pktfate[][30] = {
do { \
if (dump_msg_level & DUMP_EAPOL_VAL) { \
if (tx) { \
DHD_PKTDUMP(("[dhd-%s] 802_1X " x " [TX] : (%s) %s (%s) " \
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] 802_1X " x " [TX] : (%s) %s (%s) " \
"ver %d, type %d"TXFATE_FMT"\n", \
ifname, ## args, \
tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf, \
eapol_hdr->version, eapol_hdr->type, \
TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
} else { \
DHD_PKTDUMP(("[dhd-%s] 802_1X " x " [RX] : (%s) %s (%s) " \
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] 802_1X " x " [RX] : (%s) %s (%s) " \
"ver %d, type %d\n", \
ifname, ## args, \
tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf, \
@@ -255,7 +253,7 @@ static const char tx_pktfate[][30] = {
do { \
if (dump_msg_level & DUMP_EAPOL_VAL) { \
if (tx) { \
DHD_PKTDUMP(("[dhd-%s] 802_1X " x " [TX] : (%s) %s (%s) " \
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] 802_1X " x " [TX] : (%s) %s (%s) " \
"ver %d type %d keytype %d keyinfo 0x%02X"TXFATE_FMT"\n", \
ifname, ## args, \
tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf, \
@@ -263,7 +261,7 @@ static const char tx_pktfate[][30] = {
(uint32)hton16(eap_key->key_info), \
TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
} else { \
DHD_PKTDUMP(("[dhd-%s] 802_1X " x " [RX] : (%s) %s (%s) " \
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] 802_1X " x " [RX] : (%s) %s (%s) " \
"ver %d type %d keytype %d keyinfo 0x%02X\n", \
ifname, ## args, \
tx?seabuf:deabuf, tx?"->":"<-", tx?deabuf:seabuf, \
@@ -273,6 +271,8 @@ static const char tx_pktfate[][30] = {
} \
} while (0)
#define UDP_PORT_DNS 53 /* UDP DNS port */
/* EAPOL header */
typedef struct eapol_header {
struct ether_header eth; /* 802.3/Ethernet header */
@@ -315,6 +315,11 @@ typedef struct eapol_key_hdr {
uint8 data[WPA_KEY_DATA_LEN]; /* Key data */
} PACKED_STRUCT eapol_key_hdr_t;
typedef struct hdr_fmt {
struct ipv4_hdr iph;
struct bcmudp_hdr udph;
} PACKED_STRUCT hdr_fmt_t;
msg_eapol_t
dhd_is_4way_msg(uint8 *pktdata)
{
@@ -331,7 +336,7 @@ dhd_is_4way_msg(uint8 *pktdata)
eapol_hdr = (eapol_header_t *)pktdata;
eap_key = (eapol_key_hdr_t *)(eapol_hdr->body);
if (eap_key->type != EAPOL_WPA2_KEY) {
if (eap_key->type != EAPOL_WPA2_KEY && eap_key->type != EAPOL_WPA_KEY) {
return type;
}
@@ -344,20 +349,54 @@ dhd_is_4way_msg(uint8 *pktdata)
sec = !!(key_info & KEYINFO_SECURE_MASK);
install = !!(key_info & KEYINFO_INSTALL_MASK);
if (pair && !install && ack && !mic && !sec && !kerr && !req) {
type = EAPOL_4WAY_M1;
} else if (pair && !install && !ack && mic && !sec && !kerr && !req) {
type = EAPOL_4WAY_M2;
} else if (pair && ack && mic && sec && !kerr && !req) {
type = EAPOL_4WAY_M3;
} else if (pair && !install && !ack && mic && sec && !req && !kerr) {
type = EAPOL_4WAY_M4;
} else if (!pair && !install && ack && mic && sec && !req && !kerr) {
type = EAPOL_GROUPKEY_M1;
} else if (!pair && !install && !ack && mic && sec && !req && !kerr) {
type = EAPOL_GROUPKEY_M2;
} else {
if (eap_key->type == EAPOL_WPA2_KEY) {
if (pair && !install && ack && !mic && !sec && !kerr && !req) {
type = EAPOL_4WAY_M1;
} else if (pair && !install && !ack && mic && !sec && !kerr && !req) {
type = EAPOL_4WAY_M2;
} else if (pair && ack && mic && sec && !kerr && !req) {
type = EAPOL_4WAY_M3;
} else if (pair && !install && !ack && mic && sec && !req && !kerr) {
type = EAPOL_4WAY_M4;
} else if (!pair && !install && ack && mic && sec && !req && !kerr) {
type = EAPOL_GROUPKEY_M1;
} else if (!pair && !install && !ack && mic && sec && !req && !kerr) {
type = EAPOL_GROUPKEY_M2;
} else {
type = EAPOL_OTHER;
if (dump_msg_level & DUMP_EAPOL_VAL) {
printf("WPA2: key_info=0x%x, pair=%d, ack=%d, mic=%d, sec=%d, kerr=%d, req=%d\n",
key_info, pair, ack, mic, sec, kerr, req);
}
}
}
else if (eap_key->type == EAPOL_WPA_KEY) {
if (pair && !install && ack && !mic && !sec && !kerr && !req) {
type = EAPOL_4WAY_M1;
} else if (pair && !install && !ack && mic && !sec && !kerr && !req && eap_key->data_len) {
type = EAPOL_4WAY_M2;
} else if (pair && install && ack && mic && !sec && !kerr && !req) {
type = EAPOL_4WAY_M3;
} else if (pair && !install && !ack && mic && !sec && !req && !kerr) {
type = EAPOL_4WAY_M4;
} else if (!pair && !install && ack && mic && sec && !req && !kerr) {
type = EAPOL_GROUPKEY_M1;
} else if (!pair && !install && !ack && mic && sec && !req && !kerr) {
type = EAPOL_GROUPKEY_M2;
} else {
type = EAPOL_OTHER;
if (dump_msg_level & DUMP_EAPOL_VAL) {
printf("WPA: key_info=0x%x, pair=%d, ack=%d, mic=%d, sec=%d, kerr=%d, req=%d\n",
key_info, pair, ack, mic, sec, kerr, req);
}
}
}
else {
type = EAPOL_OTHER;
if (dump_msg_level & DUMP_EAPOL_VAL) {
printf("OTHER: key_info=0x%x, pair=%d, ack=%d, mic=%d, sec=%d, kerr=%d, req=%d\n",
key_info, pair, ack, mic, sec, kerr, req);
}
}
return type;
@@ -374,19 +413,31 @@ dhd_dump_pkt(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, uint32 pktlen,
return;
}
#if defined(BCMPCIE) && defined(DHD_PKT_LOGGING)
if (tx && !pkthash && !pktfate) {
return;
}
#endif /* BCMPCIE && DHD_PKT_LOGGING */
eh = (struct ether_header *)pktdata;
ether_type = ntoh16(eh->ether_type);
if (ether_type == ETHER_TYPE_802_1X) {
dhd_dump_eapol_message(dhdp, ifidx, pktdata, pktlen,
tx, pkthash, pktfate);
}
if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
dhd_dhcp_dump(dhdp, ifidx, pktdata, tx, pkthash, pktfate);
dhd_icmp_dump(dhdp, ifidx, pktdata, tx, pkthash, pktfate);
dhd_dns_dump(dhdp, ifidx, pktdata, tx, pkthash, pktfate);
if (ether_type == ETHER_TYPE_IP) {
if (dhd_check_dhcp(pktdata)) {
dhd_dhcp_dump(dhdp, ifidx, pktdata, tx, pkthash, pktfate);
} else if (dhd_check_icmp(pktdata)) {
dhd_icmp_dump(dhdp, ifidx, pktdata, tx, pkthash, pktfate);
} else if (dhd_check_dns(pktdata)) {
dhd_dns_dump(dhdp, ifidx, pktdata, tx, pkthash, pktfate);
}
}
if (ntoh16(eh->ether_type) == ETHER_TYPE_ARP) {
dhd_arp_dump(dhdp, ifidx, pktdata, tx, pkthash, pktfate);
if (ether_type == ETHER_TYPE_ARP) {
if (dhd_check_arp(pktdata, ether_type)) {
dhd_arp_dump(dhdp, ifidx, pktdata, tx, pkthash, pktfate);
}
}
dhd_trx_pkt_dump(dhdp, ifidx, pktdata, pktlen, tx);
}
@@ -622,42 +673,58 @@ dhd_dump_wsc_message(dhd_pub_t *dhd, int ifidx, uint8 *pktdata,
if (msg && msglen) {
switch (*msg) {
case WSC_MSG_M1:
dhd->conf->eapol_status = EAPOL_STATUS_WPS_M1;
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WPS_M1);
#endif
DHD_STATLOG_DATA(dhd, ST(WPS_M1), ifidx, tx, cond);
EAP_PRINT("EAP Packet, WPS M1");
break;
case WSC_MSG_M2:
dhd->conf->eapol_status = EAPOL_STATUS_WPS_M2;
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WPS_M2);
#endif
DHD_STATLOG_DATA(dhd, ST(WPS_M2), ifidx, tx, cond);
EAP_PRINT("EAP Packet, WPS M2");
break;
case WSC_MSG_M3:
dhd->conf->eapol_status = EAPOL_STATUS_WPS_M3;
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WPS_M3);
#endif
DHD_STATLOG_DATA(dhd, ST(WPS_M3), ifidx, tx, cond);
EAP_PRINT("EAP Packet, WPS M3");
break;
case WSC_MSG_M4:
dhd->conf->eapol_status = EAPOL_STATUS_WPS_M4;
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WPS_M4);
#endif
DHD_STATLOG_DATA(dhd, ST(WPS_M4), ifidx, tx, cond);
EAP_PRINT("EAP Packet, WPS M4");
break;
case WSC_MSG_M5:
dhd->conf->eapol_status = EAPOL_STATUS_WPS_M5;
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WPS_M5);
#endif
DHD_STATLOG_DATA(dhd, ST(WPS_M5), ifidx, tx, cond);
EAP_PRINT("EAP Packet, WPS M5");
break;
case WSC_MSG_M6:
dhd->conf->eapol_status = EAPOL_STATUS_WPS_M6;
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WPS_M6);
#endif
DHD_STATLOG_DATA(dhd, ST(WPS_M6), ifidx, tx, cond);
EAP_PRINT("EAP Packet, WPS M6");
break;
case WSC_MSG_M7:
dhd->conf->eapol_status = EAPOL_STATUS_WPS_M7;
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WPS_M7);
#endif
DHD_STATLOG_DATA(dhd, ST(WPS_M7), ifidx, tx, cond);
EAP_PRINT("EAP Packet, WPS M7");
break;
case WSC_MSG_M8:
dhd->conf->eapol_status = EAPOL_STATUS_WPS_M8;
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WPS_M8);
#endif
DHD_STATLOG_DATA(dhd, ST(WPS_M8), ifidx, tx, cond);
EAP_PRINT("EAP Packet, WPS M8");
break;
@@ -666,11 +733,15 @@ dhd_dump_wsc_message(dhd_pub_t *dhd, int ifidx, uint8 *pktdata,
}
}
} else if (eap_wsc->opcode == WSC_OPCODE_START) {
dhd->conf->eapol_status = EAPOL_STATUS_WSC_START;
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WSC_START);
#endif
DHD_STATLOG_DATA(dhd, ST(WSC_START), ifidx, tx, cond);
EAP_PRINT("EAP Packet, WSC Start");
} else if (eap_wsc->opcode == WSC_OPCODE_DONE) {
dhd->conf->eapol_status = EAPOL_STATUS_WSC_DONE;
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_WSC_DONE);
#endif
DHD_STATLOG_DATA(dhd, ST(WSC_DONE), ifidx, tx, cond);
EAP_PRINT("EAP Packet, WSC Done");
}
@@ -706,11 +777,15 @@ dhd_dump_eap_packet(dhd_pub_t *dhd, int ifidx, uint8 *pktdata,
switch (eap_hdr->type) {
case EAP_TYPE_IDENT:
if (isreq) {
dhd->conf->eapol_status = EAPOL_STATUS_REQID;
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_REQID);
#endif
DHD_STATLOG_DATA(dhd, ST(EAP_REQ_IDENTITY), ifidx, tx, cond);
EAP_PRINT("EAP Packet, Request, Identity");
} else {
dhd->conf->eapol_status = EAPOL_STATUS_RSPID;
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_RSPID);
#endif
DHD_STATLOG_DATA(dhd, ST(EAP_RESP_IDENTITY), ifidx, tx, cond);
EAP_PRINT("EAP Packet, Response, Identity");
}
@@ -829,37 +904,51 @@ dhd_dump_eapol_4way_message(dhd_pub_t *dhd, int ifidx, uint8 *pktdata, bool tx,
eap_key = (eapol_key_hdr_t *)(eapol_hdr->body);
cond = (tx && pktfate) ? FALSE : TRUE;
if (eap_key->type != EAPOL_WPA2_KEY) {
EAP_PRINT_OTHER("NON EAPOL_WPA2_KEY");
if (eap_key->type != EAPOL_WPA2_KEY && eap_key->type != EAPOL_WPA_KEY) {
EAP_PRINT_OTHER("NON EAPOL_WPA2_KEY %d", eap_key->type);
return;
}
switch (type) {
case EAPOL_4WAY_M1:
dhd->conf->eapol_status = EAPOL_STATUS_4WAY_M1;
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_4WAY_M1);
#endif
DHD_STATLOG_DATA(dhd, ST(EAPOL_M1), ifidx, tx, cond);
EAP_PRINT("EAPOL Packet, 4-way handshake, M1");
break;
case EAPOL_4WAY_M2:
dhd->conf->eapol_status = EAPOL_STATUS_4WAY_M2;
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_4WAY_M2);
#endif
DHD_STATLOG_DATA(dhd, ST(EAPOL_M2), ifidx, tx, cond);
EAP_PRINT("EAPOL Packet, 4-way handshake, M2");
break;
case EAPOL_4WAY_M3:
dhd->conf->eapol_status = EAPOL_STATUS_4WAY_M3;
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_4WAY_M3);
#endif
DHD_STATLOG_DATA(dhd, ST(EAPOL_M3), ifidx, tx, cond);
EAP_PRINT("EAPOL Packet, 4-way handshake, M3");
break;
case EAPOL_4WAY_M4:
dhd->conf->eapol_status = EAPOL_STATUS_4WAY_M4;
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_4WAY_M4);
#endif
DHD_STATLOG_DATA(dhd, ST(EAPOL_M4), ifidx, tx, cond);
EAP_PRINT("EAPOL Packet, 4-way handshake, M4");
break;
case EAPOL_GROUPKEY_M1:
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_GROUPKEY_M1);
#endif
DHD_STATLOG_DATA(dhd, ST(EAPOL_GROUPKEY_M1), ifidx, tx, cond);
EAP_PRINT_REPLAY("EAPOL Packet, GROUP Key handshake, M1");
break;
case EAPOL_GROUPKEY_M2:
#ifdef WL_EXT_IAPSTA
wl_ext_update_eapol_status(dhd, ifidx, EAPOL_STATUS_GROUPKEY_M2);
#endif
DHD_STATLOG_DATA(dhd, ST(EAPOL_GROUPKEY_M2), ifidx, tx, cond);
EAP_PRINT_REPLAY("EAPOL Packet, GROUP Key handshake, M2");
if (ifidx == 0 && tx && pktfate) {
@@ -868,7 +957,7 @@ dhd_dump_eapol_4way_message(dhd_pub_t *dhd, int ifidx, uint8 *pktdata, bool tx,
break;
default:
DHD_STATLOG_DATA(dhd, ST(8021X_OTHER), ifidx, tx, cond);
EAP_PRINT_OTHER("OTHER 4WAY");
EAP_PRINT_OTHER("OTHER 4WAY type=%d", type);
break;
}
}
@@ -911,6 +1000,47 @@ dhd_dump_eapol_message(dhd_pub_t *dhd, int ifidx, uint8 *pktdata,
}
#endif /* DHD_8021X_DUMP */
bool
dhd_check_ip_prot(uint8 *pktdata, uint16 ether_type)
{
hdr_fmt_t *b = (hdr_fmt_t *)&pktdata[ETHER_HDR_LEN];
struct ipv4_hdr *iph = &b->iph;
/* check IP header */
if ((ether_type != ETHER_TYPE_IP) ||
(IPV4_HLEN(iph) < IPV4_HLEN_MIN) ||
(IP_VER(iph) != IP_VER_4)) {
return FALSE;
}
return TRUE;
}
bool
dhd_check_dhcp(uint8 *pktdata)
{
hdr_fmt_t *b = (hdr_fmt_t *)&pktdata[ETHER_HDR_LEN];
struct ipv4_hdr *iph = &b->iph;
if (IPV4_PROT(iph) != IP_PROT_UDP) {
return FALSE;
}
/* check UDP port for bootp (67, 68) */
if (b->udph.src_port != htons(DHCP_PORT_SERVER) &&
b->udph.src_port != htons(DHCP_PORT_CLIENT) &&
b->udph.dst_port != htons(DHCP_PORT_SERVER) &&
b->udph.dst_port != htons(DHCP_PORT_CLIENT)) {
return FALSE;
}
/* check header length */
if (ntohs(iph->tot_len) < ntohs(b->udph.len) + sizeof(struct bcmudp_hdr)) {
return FALSE;
}
return TRUE;
}
#ifdef DHD_DHCP_DUMP
#define BOOTP_CHADDR_LEN 16
#define BOOTP_SNAME_LEN 64
@@ -930,12 +1060,12 @@ dhd_dump_eapol_message(dhd_pub_t *dhd, int ifidx, uint8 *pktdata,
#define DHCP_PRINT(str) \
do { \
if (tx) { \
DHD_PKTDUMP(("[dhd-%s] " str " %8s[%8s] [TX] : %s(%s) %s %s(%s)"TXFATE_FMT"\n", \
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] " str " %8s[%8s] [TX] : %s(%s) %s %s(%s)"TXFATE_FMT"\n", \
ifname, typestr, opstr, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, \
TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
} else { \
DHD_PKTDUMP(("[dhd-%s] " str " %8s[%8s] [RX] : %s(%s) %s %s(%s)\n", \
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] " str " %8s[%8s] [RX] : %s(%s) %s %s(%s)\n", \
ifname, typestr, opstr, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf)); \
} \
@@ -969,11 +1099,13 @@ static char dhcp_types[][10] = {
"NA", "DISCOVER", "OFFER", "REQUEST", "DECLINE", "ACK", "NAK", "RELEASE", "INFORM"
};
#ifdef DHD_STATUS_LOGGING
static const int dhcp_types_stat[9] = {
ST(INVALID), ST(DHCP_DISCOVER), ST(DHCP_OFFER), ST(DHCP_REQUEST),
ST(DHCP_DECLINE), ST(DHCP_ACK), ST(DHCP_NAK), ST(DHCP_RELEASE),
ST(DHCP_INFORM)
};
#endif /* DHD_STATUS_LOGGING */
void
dhd_dhcp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
@@ -991,26 +1123,6 @@ dhd_dhcp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
if (!(dump_msg_level & DUMP_DHCP_VAL))
return;
/* check IP header */
if ((IPV4_HLEN(iph) < IPV4_HLEN_MIN) ||
IP_VER(iph) != IP_VER_4 ||
IPV4_PROT(iph) != IP_PROT_UDP) {
return;
}
/* check UDP port for bootp (67, 68) */
if (b->udph.src_port != htons(DHCP_PORT_SERVER) &&
b->udph.src_port != htons(DHCP_PORT_CLIENT) &&
b->udph.dst_port != htons(DHCP_PORT_SERVER) &&
b->udph.dst_port != htons(DHCP_PORT_CLIENT)) {
return;
}
/* check header length */
if (ntohs(iph->tot_len) < ntohs(b->udph.len) + sizeof(struct bcmudp_hdr)) {
return;
}
bcm_ip_ntoa((struct ipv4_addr *)iph->src_ip, sabuf);
bcm_ip_ntoa((struct ipv4_addr *)iph->dst_ip, dabuf);
bcm_ether_ntoa((struct ether_addr *)pktdata, deabuf);
@@ -1051,6 +1163,23 @@ dhd_dhcp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
}
#endif /* DHD_DHCP_DUMP */
bool
dhd_check_icmp(uint8 *pktdata)
{
uint8 *pkt = (uint8 *)&pktdata[ETHER_HDR_LEN];
struct ipv4_hdr *iph = (struct ipv4_hdr *)pkt;
if (IPV4_PROT(iph) != IP_PROT_ICMP) {
return FALSE;
}
/* check header length */
if (ntohs(iph->tot_len) - IPV4_HLEN(iph) < sizeof(struct bcmicmp_hdr)) {
return FALSE;
}
return TRUE;
}
#ifdef DHD_ICMP_DUMP
#define ICMP_TYPE_DEST_UNREACH 3
#define ICMP_ECHO_SEQ_OFFSET 6
@@ -1058,12 +1187,12 @@ dhd_dhcp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
#define ICMP_PING_PRINT(str) \
do { \
if (tx) { \
DHD_PKTDUMP_MEM(("[dhd-%s] "str " [TX] : %s(%s) %s %s(%s) SEQNUM=%d" \
DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] "str " [TX] : %s(%s) %s %s(%s) SEQNUM=%d" \
TXFATE_FMT"\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, seqnum, \
TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
} else { \
DHD_PKTDUMP_MEM(("[dhd-%s] "str " [RX] : %s(%s) %s %s(%s) SEQNUM=%d\n", \
DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] "str " [RX] : %s(%s) %s %s(%s) SEQNUM=%d\n", \
ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, seqnum)); \
} \
@@ -1072,12 +1201,12 @@ dhd_dhcp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
#define ICMP_PRINT(str) \
do { \
if (tx) { \
DHD_PKTDUMP_MEM(("[dhd-%s] "str " [TX] : %s(%s) %s %s(%s) TYPE=%d, CODE=%d" \
DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] "str " [TX] : %s(%s) %s %s(%s) TYPE=%d, CODE=%d" \
TXFATE_FMT "\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, type, code, \
TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
} else { \
DHD_PKTDUMP_MEM(("[dhd-%s] "str " [RX] : %s(%s) %s %s(%s) TYPE=%d," \
DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] "str " [RX] : %s(%s) %s %s(%s) TYPE=%d," \
" CODE=%d\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, type, code)); \
} \
@@ -1100,18 +1229,6 @@ dhd_icmp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
if (!(dump_msg_level & DUMP_ICMP_VAL))
return;
/* check IP header */
if ((IPV4_HLEN(iph) < IPV4_HLEN_MIN) ||
IP_VER(iph) != IP_VER_4 ||
IPV4_PROT(iph) != IP_PROT_ICMP) {
return;
}
/* check header length */
if (ntohs(iph->tot_len) - IPV4_HLEN(iph) < sizeof(struct bcmicmp_hdr)) {
return;
}
ifname = dhd_ifname(dhdp, ifidx);
cond = (tx && pktfate) ? FALSE : TRUE;
icmph = (struct bcmicmp_hdr *)((uint8 *)pkt + sizeof(struct ipv4_hdr));
@@ -1140,23 +1257,48 @@ dhd_icmp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
}
#endif /* DHD_ICMP_DUMP */
bool
dhd_check_arp(uint8 *pktdata, uint16 ether_type)
{
uint8 *pkt = (uint8 *)&pktdata[ETHER_HDR_LEN];
struct bcmarp *arph = (struct bcmarp *)pkt;
/* validation check */
if ((ether_type != ETHER_TYPE_ARP) ||
(arph->htype != hton16(HTYPE_ETHERNET)) ||
(arph->hlen != ETHER_ADDR_LEN) ||
(arph->plen != 4)) {
return FALSE;
}
return TRUE;
}
#ifdef DHD_ARP_DUMP
#ifdef BOARD_HIKEY
/* On Hikey, due to continuous ARP prints
* DPC not scheduled. Hence rate limit the prints.
*/
#define DHD_PKTDUMP_ARP DHD_ERROR_RLMT
#else
#define DHD_PKTDUMP_ARP DHD_PKTDUMP
#endif /* BOARD_HIKEY */
#define ARP_PRINT(str) \
do { \
if (tx) { \
if (dump_enabled && pktfate && !TX_FATE_ACKED(pktfate)) { \
DHD_PKTDUMP(("[dhd-%s] "str " [TX] : %s(%s) %s %s(%s)"TXFATE_FMT"\n", \
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] "str " [TX] : %s(%s) %s %s(%s)"TXFATE_FMT"\n", \
ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, \
TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
} else { \
DHD_PKTDUMP_MEM(("[dhd-%s] "str " [TX] : %s(%s) %s %s(%s)"TXFATE_FMT"\n", \
DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] "str " [TX] : %s(%s) %s %s(%s)"TXFATE_FMT"\n", \
ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, \
TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
} \
} else { \
DHD_PKTDUMP_MEM(("[dhd-%s] "str " [RX] : %s(%s) %s %s(%s)\n", \
DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] "str " [RX] : %s(%s) %s %s(%s)\n", \
ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf)); \
} \
@@ -1166,18 +1308,18 @@ dhd_icmp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
do { \
if (tx) { \
if (dump_enabled && pktfate && !TX_FATE_ACKED(pktfate)) { \
DHD_PKTDUMP(("[dhd-%s] "str " [TX] : %s(%s) %s %s(%s) op_code=%d" \
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] "str " [TX] : %s(%s) %s %s(%s) op_code=%d" \
TXFATE_FMT "\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, opcode, \
TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
} else { \
DHD_PKTDUMP_MEM(("[dhd-%s] "str " [TX] : %s(%s) %s %s(%s) op_code=%d" \
DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] "str " [TX] : %s(%s) %s %s(%s) op_code=%d" \
TXFATE_FMT "\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, opcode, \
TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
} \
} else { \
DHD_PKTDUMP_MEM(("[dhd-%s] "str " [RX] : %s(%s) %s %s(%s) op_code=%d\n", \
DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] "str " [RX] : %s(%s) %s %s(%s) op_code=%d\n", \
ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, opcode)); \
} \
@@ -1199,13 +1341,6 @@ dhd_arp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
if (!(dump_msg_level & DUMP_ARP_VAL))
return;
/* validation check */
if (arph->htype != hton16(HTYPE_ETHERNET) ||
arph->hlen != ETHER_ADDR_LEN ||
arph->plen != 4) {
return;
}
ifname = dhd_ifname(dhdp, ifidx);
opcode = ntoh16(arph->oper);
cond = (tx && pktfate) ? FALSE : TRUE;
@@ -1230,6 +1365,30 @@ dhd_arp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
}
#endif /* DHD_ARP_DUMP */
bool
dhd_check_dns(uint8 *pktdata)
{
hdr_fmt_t *dnsh = (hdr_fmt_t *)&pktdata[ETHER_HDR_LEN];
struct ipv4_hdr *iph = &dnsh->iph;
if (IPV4_PROT(iph) != IP_PROT_UDP) {
return FALSE;
}
/* check UDP port for DNS */
if (dnsh->udph.src_port != hton16(UDP_PORT_DNS) &&
dnsh->udph.dst_port != hton16(UDP_PORT_DNS)) {
return FALSE;
}
/* check header length */
if (ntoh16(iph->tot_len) < (ntoh16(dnsh->udph.len) +
sizeof(struct bcmudp_hdr))) {
return FALSE;
}
return TRUE;
}
#ifdef DHD_DNS_DUMP
typedef struct dns_fmt {
struct ipv4_hdr iph;
@@ -1242,7 +1401,6 @@ typedef struct dns_fmt {
uint16 arcount;
} PACKED_STRUCT dns_fmt_t;
#define UDP_PORT_DNS 53
#define DNS_QR_LOC 15
#define DNS_OPCODE_LOC 11
#define DNS_RCODE_LOC 0
@@ -1265,18 +1423,18 @@ static const char dns_opcode_types[][11] = {
do { \
if (tx) { \
if (dump_enabled && pktfate && !TX_FATE_ACKED(pktfate)) { \
DHD_PKTDUMP(("[dhd-%s] " str " [TX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s" \
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] " str " [TX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s" \
TXFATE_FMT "\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, \
id, DNSOPCODE(opcode), TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
} else { \
DHD_PKTDUMP_MEM(("[dhd-%s] " str " [TX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s" \
DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] " str " [TX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s" \
TXFATE_FMT "\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, \
id, DNSOPCODE(opcode), TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
} \
} else { \
DHD_PKTDUMP_MEM(("[dhd-%s] " str " [RX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s\n", \
DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] " str " [RX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s\n", \
ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, tx?"->":"<-", \
tx?dabuf:sabuf, tx?deabuf:seabuf, id, DNSOPCODE(opcode))); \
} \
@@ -1286,18 +1444,18 @@ static const char dns_opcode_types[][11] = {
do { \
if (tx) { \
if (dump_enabled && pktfate && !TX_FATE_ACKED(pktfate)) { \
DHD_PKTDUMP(("[dhd-%s] " str " [TX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s RCODE:%d" \
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] " str " [TX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s RCODE:%d" \
TXFATE_FMT "\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, id, DNSOPCODE(opcode), \
GET_DNS_RCODE(flags), TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
} else { \
DHD_PKTDUMP_MEM(("[dhd-%s] " str " [TX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s RCODE:%d" \
DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] " str " [TX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s RCODE:%d" \
TXFATE_FMT "\n", ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, id, DNSOPCODE(opcode), \
GET_DNS_RCODE(flags), TX_PKTHASH(pkthash), TX_FATE(pktfate))); \
} \
} else { \
DHD_PKTDUMP_MEM(("[dhd-%s] " str " [RX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s RCODE:%d\n", \
DHD_PKTDUMP_MEM((DHD_LOG_PREFIX "[%s] " str " [RX] : %s(%s) %s %s(%s) ID:0x%04X OPCODE:%s RCODE:%d\n", \
ifname, tx?sabuf:dabuf, tx?seabuf:deabuf, \
tx?"->":"<-", tx?dabuf:sabuf, tx?deabuf:seabuf, \
id, DNSOPCODE(opcode), GET_DNS_RCODE(flags))); \
@@ -1320,25 +1478,6 @@ dhd_dns_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
if (!(dump_msg_level & DUMP_DNS_VAL))
return;
/* check IP header */
if ((IPV4_HLEN(iph) < IPV4_HLEN_MIN) ||
IP_VER(iph) != IP_VER_4 ||
IPV4_PROT(iph) != IP_PROT_UDP) {
return;
}
/* check UDP port for DNS */
if (dnsh->udph.src_port != hton16(UDP_PORT_DNS) &&
dnsh->udph.dst_port != hton16(UDP_PORT_DNS)) {
return;
}
/* check header length */
if (ntoh16(iph->tot_len) < (ntoh16(dnsh->udph.len) +
sizeof(struct bcmudp_hdr))) {
return;
}
ifname = dhd_ifname(dhdp, ifidx);
cond = (tx && pktfate) ? FALSE : TRUE;
dump_enabled = dhd_dump_pkt_enabled(dhdp);
@@ -1412,13 +1551,13 @@ dhd_trx_pkt_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, uint32 pktlen, bool
if (protocol != ETHER_TYPE_BRCM) {
if (pktdata[0] == 0xFF) {
DHD_PKTDUMP(("[dhd-%s] %s BROADCAST DUMP - %s\n",
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] %s BROADCAST DUMP - %s\n",
dhd_ifname(dhdp, ifidx), tx?"TX":"RX", pkttype));
} else if (pktdata[0] & 1) {
DHD_PKTDUMP(("[dhd-%s] %s MULTICAST DUMP " MACDBG " - %s\n",
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] %s MULTICAST DUMP " MACDBG " - %s\n",
dhd_ifname(dhdp, ifidx), tx?"TX":"RX", MAC2STRDBG(pktdata), pkttype));
} else {
DHD_PKTDUMP(("[dhd-%s] %s DUMP - %s\n",
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] %s DUMP - %s\n",
dhd_ifname(dhdp, ifidx), tx?"TX":"RX", pkttype));
}
#ifdef DHD_RX_FULL_DUMP
@@ -1426,7 +1565,7 @@ dhd_trx_pkt_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, uint32 pktlen, bool
#endif /* DHD_RX_FULL_DUMP */
}
else {
DHD_PKTDUMP(("[dhd-%s] %s DUMP - %s\n",
DHD_PKTDUMP((DHD_LOG_PREFIX "[%s] %s DUMP - %s\n",
dhd_ifname(dhdp, ifidx), tx?"TX":"RX", pkttype));
}
}

View File

@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Header file for the Packet dump helper functions
*
* Copyright (C) 1999-2019, Broadcom.
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -18,14 +17,10 @@
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_linux_pktdump.h 820929 2019-05-21 14:09:11Z $
* $Id$
*/
#ifndef __DHD_LINUX_PKTDUMP_H_
@@ -52,10 +47,18 @@ typedef enum pkt_cnt_rsn {
PKT_CNT_RSN_MAX = 4
} pkt_cnt_rsn_t;
enum pkt_type {
PKT_TYPE_DATA = 0,
PKT_TYPE_DHCP = 1,
PKT_TYPE_ICMP = 2,
PKT_TYPE_DNS = 3,
PKT_TYPE_ARP = 4,
PKT_TYPE_EAP = 5
};
extern msg_eapol_t dhd_is_4way_msg(uint8 *pktdata);
extern void dhd_dump_pkt(dhd_pub_t *dhd, int ifidx, uint8 *pktdata,
uint32 pktlen, bool tx, uint32 *pkthash, uint16 *pktfate);
#ifdef DHD_PKTDUMP_ROAM
extern void dhd_dump_mod_pkt_timer(dhd_pub_t *dhdp, uint16 rsn);
extern void dhd_dump_pkt_init(dhd_pub_t *dhdp);
@@ -121,5 +124,9 @@ extern void dhd_dump_eapol_message(dhd_pub_t *dhd, int ifidx,
static INLINE void dhd_dump_eapol_message(dhd_pub_t *dhd, int ifidx,
uint8 *pktdata, uint32 pktlen, bool tx, uint32 *pkthash, uint16 *pktfate) { }
#endif /* DHD_8021X_DUMP */
extern bool dhd_check_ip_prot(uint8 *pktdata, uint16 ether_type);
extern bool dhd_check_arp(uint8 *pktdata, uint16 ether_type);
extern bool dhd_check_dhcp(uint8 *pktdata);
extern bool dhd_check_icmp(uint8 *pktdata);
extern bool dhd_check_dns(uint8 *pktdata);
#endif /* __DHD_LINUX_PKTDUMP_H_ */

View File

@@ -1,14 +1,14 @@
/*
* Linux platform device for DHD WLAN adapter
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,15 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_linux_platdev.c 662397 2016-09-29 10:15:08Z $
* $Id$
*/
#include <typedefs.h>
#include <linux/kernel.h>
@@ -38,9 +34,16 @@
#include <dhd.h>
#include <dhd_bus.h>
#include <dhd_linux.h>
#if defined(OEM_ANDROID)
#include <wl_android.h>
#if defined(CONFIG_WIFI_CONTROL_FUNC)
#endif
#if defined(CONFIG_WIFI_CONTROL_FUNC) || defined(CUSTOMER_HW4)
#include <linux/wlan_plat.h>
#else
#include <dhd_plat.h>
#endif /* CONFIG_WIFI_CONTROL_FUNC */
#ifdef BCMDBUS
#include <dbus.h>
#endif
#ifdef CONFIG_DTS
#include<linux/regulator/consumer.h>
@@ -56,15 +59,23 @@ extern void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter);
#define WIFI_PLAT_NAME2 "bcm4329_wlan"
#define WIFI_PLAT_EXT "bcmdhd_wifi_platform"
#ifdef DHD_WIFI_SHUTDOWN
extern void wifi_plat_dev_drv_shutdown(struct platform_device *pdev);
#endif
#ifdef CONFIG_DTS
struct regulator *wifi_regulator = NULL;
extern struct wifi_platform_data dhd_wlan_control;
#endif /* CONFIG_DTS */
bool cfg_multichip = FALSE;
bcmdhd_wifi_platdata_t *dhd_wifi_platdata = NULL;
static int wifi_plat_dev_probe_ret = 0;
static bool is_power_on = FALSE;
/* XXX Some Qualcomm based CUSTOMER_HW4 platforms are using platform
* device structure even if the Kernel uses device tree structure.
* Therefore, the CONFIG_ARCH_MSM condition is temporarly remained
* to support in this case.
*/
#if !defined(CONFIG_DTS)
#if defined(DHD_OF_SUPPORT)
static bool dts_enabled = TRUE;
@@ -88,12 +99,25 @@ static int dhd_wifi_platform_load(void);
extern void* wl_cfg80211_get_dhdp(struct net_device *dev);
#ifdef BCMDHD_MODULAR
//extern int dhd_wlan_init(void);
//extern int dhd_wlan_deinit(void);
#ifdef WBRC
extern int wbrc_init(void);
extern void wbrc_exit(void);
#endif /* WBRC */
#endif /* BCMDHD_MODULAR */
#ifdef ENABLE_4335BT_WAR
extern int bcm_bt_lock(int cookie);
extern void bcm_bt_unlock(int cookie);
static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */
#endif /* ENABLE_4335BT_WAR */
#ifdef BCM4335_XTAL_WAR
extern bool check_bcm4335_rev(void);
#endif /* BCM4335_XTAL_WAR */
wifi_adapter_info_t* dhd_wifi_platform_attach_adapter(uint32 bus_type,
uint32 bus_num, uint32 slot_num, unsigned long status)
{
@@ -217,7 +241,7 @@ int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long
}
plat_data = adapter->wifi_plat_data;
DHD_ERROR(("%s = %d\n", __FUNCTION__, on));
DHD_ERROR(("%s = %d, delay: %lu msec\n", __FUNCTION__, on, msec));
if (plat_data->set_power) {
#ifdef ENABLE_4335BT_WAR
if (on) {
@@ -276,7 +300,8 @@ int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_presen
}
int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf)
int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf,
char *name)
{
struct wifi_platform_data *plat_data;
@@ -285,11 +310,32 @@ int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf)
return -EINVAL;
plat_data = adapter->wifi_plat_data;
if (plat_data->get_mac_addr) {
#ifdef CUSTOM_MULTI_MAC
return plat_data->get_mac_addr(buf, name);
#else
return plat_data->get_mac_addr(buf);
#endif
}
return -EOPNOTSUPP;
}
#ifdef DHD_COREDUMP
int wifi_platform_set_coredump(wifi_adapter_info_t *adapter, const char *buf,
int buf_len, const char *info)
{
struct wifi_platform_data *plat_data;
DHD_ERROR(("%s\n", __FUNCTION__));
if (!buf || !adapter || !adapter->wifi_plat_data)
return -EINVAL;
plat_data = adapter->wifi_plat_data;
if (plat_data->set_coredump) {
return plat_data->set_coredump(buf, buf_len, info);
}
return -EOPNOTSUPP;
}
#endif /* DHD_COREDUMP */
void *
#ifdef CUSTOM_COUNTRY_CODE
wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, u32 flags)
@@ -333,8 +379,11 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev)
ASSERT(dhd_wifi_platdata != NULL);
ASSERT(dhd_wifi_platdata->num_adapters == 1);
adapter = &dhd_wifi_platdata->adapters[0];
#if defined(CONFIG_WIFI_CONTROL_FUNC)
adapter->wifi_plat_data = (struct wifi_platform_data *)(pdev->dev.platform_data);
#else
adapter->wifi_plat_data = (void *)&dhd_wlan_control;
// adapter->wifi_plat_data = (struct wifi_platform_data *)(pdev->dev.platform_data);
#endif
resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq");
if (resource == NULL)
@@ -438,6 +487,9 @@ static struct platform_driver wifi_platform_dev_driver = {
.remove = wifi_plat_dev_drv_remove,
.suspend = wifi_plat_dev_drv_suspend,
.resume = wifi_plat_dev_drv_resume,
#ifdef DHD_WIFI_SHUTDOWN
.shutdown = wifi_plat_dev_drv_shutdown,
#endif /* DHD_WIFI_SHUTDOWN */
.driver = {
.name = WIFI_PLAT_NAME,
#ifdef CONFIG_DTS
@@ -451,22 +503,25 @@ static struct platform_driver wifi_platform_dev_driver_legacy = {
.remove = wifi_plat_dev_drv_remove,
.suspend = wifi_plat_dev_drv_suspend,
.resume = wifi_plat_dev_drv_resume,
#ifdef DHD_WIFI_SHUTDOWN
.shutdown = wifi_plat_dev_drv_shutdown,
#endif /* DHD_WIFI_SHUTDOWN */
.driver = {
.name = WIFI_PLAT_NAME2,
}
};
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
static int wifi_platdev_match(struct device *dev, const void *data)
#else
static int wifi_platdev_match(struct device *dev, void *data)
#endif /* LINUX_VER >= 5.3.0 */
{
char *name = (char*)data;
#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
const struct platform_device *pdev = to_platform_device(dev);
#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
const struct platform_device *pdev;
GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
pdev = to_platform_device(dev);
GCC_DIAGNOSTIC_POP();
if (strcmp(pdev->name, name) == 0) {
DHD_ERROR(("found wifi platform device %s\n", name));
@@ -488,6 +543,13 @@ static int wifi_ctrlfunc_register_drv(void)
dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match);
#endif
#ifdef BCMDHD_MODULAR
// dhd_wlan_init();
#ifdef WBRC
wbrc_init();
#endif /* WBRC */
#endif /* BCMDHD_MODULAR */
#if !defined(CONFIG_DTS) && !defined(CUSTOMER_HW)
if (!dts_enabled) {
if (dev1 == NULL && dev2 == NULL) {
@@ -555,7 +617,6 @@ static int wifi_ctrlfunc_register_drv(void)
}
#endif /* !defined(CONFIG_DTS) */
#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW)
wifi_plat_dev_probe_ret = platform_driver_register(&wifi_platform_dev_driver);
#endif /* CONFIG_DTS */
@@ -596,6 +657,13 @@ void wifi_ctrlfunc_unregister_drv(void)
}
wifi_platform_bus_enumerate(adapter, FALSE);
}
#ifdef BCMDHD_MODULAR
// dhd_wlan_deinit();
#ifdef WBRC
wbrc_exit();
#endif /* WBRC */
#endif /* BCMDHD_MODULAR */
#endif /* !defined(CONFIG_DTS) */
#if defined(CUSTOMER_HW)
@@ -692,9 +760,14 @@ static int dhd_wifi_platform_load_pcie(void)
BCM_REFERENCE(adapter);
if (dhd_wifi_platdata == NULL) {
/* XXX For x86 Bringup PC or BRIX */
err = dhd_bus_register();
} else {
#ifdef DHD_SUPPORT_HDM
if (dhd_download_fw_on_driverload || hdm_trigger_init) {
#else
if (dhd_download_fw_on_driverload) {
#endif /* DHD_SUPPORT_HDM */
/* power up all adapters */
for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
int retry = POWERUP_MAX_RETRY;
@@ -765,7 +838,6 @@ static int dhd_wifi_platform_load_pcie(void)
}
#endif /* BCMPCIE */
void dhd_wifi_platform_unregister_drv(void)
{
#ifndef CUSTOMER_HW
@@ -779,9 +851,9 @@ void dhd_wifi_platform_unregister_drv(void)
extern int dhd_watchdog_prio;
extern int dhd_dpc_prio;
extern uint dhd_deferred_tx;
#if defined(BCMLXSDMMC) || defined(BCMDBUS)
#if defined(OEM_ANDROID) && (defined(BCMLXSDMMC) || defined(BCMDBUS))
extern struct semaphore dhd_registration_sem;
#endif
#endif /* defined(OEM_ANDROID) && defined(BCMLXSDMMC) */
#ifdef BCMSDIO
static int dhd_wifi_platform_load_sdio(void)
@@ -800,19 +872,19 @@ static int dhd_wifi_platform_load_sdio(void)
!(dhd_watchdog_prio >= 0 && dhd_dpc_prio >= 0 && dhd_deferred_tx))
return -EINVAL;
#if defined(BCMLXSDMMC) && !defined(DHD_PRELOAD)
#if defined(OEM_ANDROID) && defined(BCMLXSDMMC) && !defined(DHD_PRELOAD)
sema_init(&dhd_registration_sem, 0);
#endif
if (dhd_wifi_platdata == NULL) {
DHD_ERROR(("DHD wifi platform data is required for Android build\n"));
DHD_ERROR(("DHD registeing bus directly\n"));
DHD_ERROR(("DHD registering bus directly\n"));
/* x86 bring-up PC needs no power-up operations */
err = dhd_bus_register();
return err;
}
#if defined(BCMLXSDMMC) && !defined(DHD_PRELOAD)
#if defined(OEM_ANDROID) && defined(BCMLXSDMMC) && !defined(DHD_PRELOAD)
/* power up all adapters */
for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
bool chip_up = FALSE;
@@ -837,6 +909,7 @@ static int dhd_wifi_platform_load_sdio(void)
}
err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY);
if (err) {
DHD_ERROR(("%s: wifi pwr on error ! \n", __FUNCTION__));
dhd_bus_unreg_sdio_notify();
/* WL_REG_ON state unknown, Power off forcely */
wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY);
@@ -895,7 +968,7 @@ fail:
#else
/* x86 bring-up PC needs no power-up operations */
err = dhd_bus_register();
#endif
#endif /* defined(OEM_ANDROID) && defined(BCMLXSDMMC) */
return err;
}
@@ -917,6 +990,19 @@ static int dhd_wifi_platform_load_usb(void)
enum wifi_adapter_status wait_status;
#endif
#if !defined(DHD_PRELOAD)
/* power down all adapters */
for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
adapter = &dhd_wifi_platdata->adapters[i];
wifi_platform_set_power(adapter, FALSE, 0);
if (err) {
DHD_ERROR(("failed to wifi_platform_set_power on %s\n", adapter->name));
goto exit;
}
}
OSL_SLEEP(200);
#endif
err = dhd_bus_register();
if (err) {
DHD_ERROR(("%s: usb_register failed\n", __FUNCTION__));
@@ -979,7 +1065,9 @@ static int dhd_wifi_platform_load()
int err = 0;
printf("%s: Enter\n", __FUNCTION__);
#if defined(OEM_ANDROID)
wl_android_init();
#endif /* OEM_ANDROID */
if ((err = dhd_wifi_platform_load_usb()))
goto end;
@@ -989,12 +1077,14 @@ static int dhd_wifi_platform_load()
err = dhd_wifi_platform_load_pcie();
end:
#if defined(OEM_ANDROID)
if (err)
wl_android_exit();
#if !defined(MULTIPLE_SUPPLICANT)
else
wl_android_post_init();
#endif
#endif /* OEM_ANDROID */
return err;
}

View File

@@ -1,8 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* DHD Linux header file - contains private structure definition of the Linux specific layer
*
* Copyright (C) 1999-2019, Broadcom.
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -18,14 +17,10 @@
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_linux_priv.h 815919 2019-04-22 09:06:50Z $
* $Id$
*/
#ifndef __DHD_LINUX_PRIV_H__
@@ -39,9 +34,13 @@
#endif /* SHOW_LOGTRACE */
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#ifdef CONFIG_COMPAT
#include <linux/compat.h>
#endif /* CONFIG COMPAT */
#ifdef CONFIG_HAS_WAKELOCK
#include <linux/pm_wakeup.h>
#endif /* CONFIG_HAS_WAKELOCK */
#include <dngl_stats.h>
#include <dhd.h>
#include <dhd_dbg.h>
@@ -54,6 +53,10 @@
#include <dhd_flowring.h>
#endif /* PCIE_FULL_DONGLE */
#ifdef DHD_QOS_ON_SOCK_FLOW
struct dhd_sock_qos_info;
#endif /* DHD_QOS_ON_SOCK_FLOW */
/*
* Do not include this header except for the dhd_linux.c dhd_linux_sysfs.c
* Local private structure (extension of pub)
@@ -63,11 +66,10 @@ typedef struct dhd_info {
wl_iw_t iw; /* wireless extensions state (must be first) */
#endif /* defined(WL_WIRELESS_EXT) */
dhd_pub_t pub;
/* for supporting multiple interfaces.
* static_ifs hold the net ifaces without valid FW IF
*/
/* for supporting multiple interfaces.
* static_ifs hold the net ifaces without valid FW IF
*/
dhd_if_t *iflist[DHD_MAX_IFS + DHD_MAX_STATIC_IFS];
wifi_adapter_info_t *adapter; /* adapter information, interrupt, fw path etc. */
char fw_path[PATH_MAX]; /* path to firmware image */
char nv_path[PATH_MAX]; /* path to nvram vars file */
@@ -87,16 +89,24 @@ typedef struct dhd_info {
#ifdef BCMDBUS
ulong wlfc_lock_flags;
ulong wlfc_pub_lock_flags;
#endif /* BCMDBUS */
#endif
#endif /* PROP_TXSTATUS */
wait_queue_head_t ioctl_resp_wait;
wait_queue_head_t d3ack_wait;
wait_queue_head_t dhd_bus_busy_state_wait;
wait_queue_head_t dmaxfer_wait;
#ifdef BT_OVER_PCIE
wait_queue_head_t quiesce_wait;
#endif /* BT_OVER_PCIE */
uint32 default_wd_interval;
timer_list_compat_t timer;
bool wd_timer_valid;
#ifdef DHD_PCIE_RUNTIMEPM
timer_list_compat_t rpm_timer;
bool rpm_timer_valid;
tsk_ctl_t thr_rpm_ctl;
#endif /* DHD_PCIE_RUNTIMEPM */
struct tasklet_struct tasklet;
spinlock_t sdlock;
spinlock_t txqlock;
@@ -116,21 +126,23 @@ typedef struct dhd_info {
/* Wakelocks */
#if defined(CONFIG_HAS_WAKELOCK)
struct wake_lock wl_wifi; /* Wifi wakelock */
struct wake_lock wl_rxwake; /* Wifi rx wakelock */
struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */
struct wake_lock wl_wdwake; /* Wifi wd wakelock */
struct wake_lock wl_evtwake; /* Wifi event wakelock */
struct wake_lock wl_pmwake; /* Wifi pm handler wakelock */
struct wake_lock wl_txflwake; /* Wifi tx flow wakelock */
struct wakeup_source wl_wifi; /* Wifi wakelock */
struct wakeup_source wl_rxwake; /* Wifi rx wakelock */
struct wakeup_source wl_ctrlwake; /* Wifi ctrl wakelock */
struct wakeup_source wl_wdwake; /* Wifi wd wakelock */
struct wakeup_source wl_evtwake; /* Wifi event wakelock */
struct wakeup_source wl_pmwake; /* Wifi pm handler wakelock */
struct wakeup_source wl_txflwake; /* Wifi tx flow wakelock */
#ifdef BCMPCIE_OOB_HOST_WAKE
struct wake_lock wl_intrwake; /* Host wakeup wakelock */
struct wakeup_source wl_intrwake; /* Host wakeup wakelock */
#endif /* BCMPCIE_OOB_HOST_WAKE */
#ifdef DHD_USE_SCAN_WAKELOCK
struct wake_lock wl_scanwake; /* Wifi scan wakelock */
struct wakeup_source wl_scanwake; /* Wifi scan wakelock */
#endif /* DHD_USE_SCAN_WAKELOCK */
struct wakeup_source wl_nanwake; /* NAN wakelock */
#endif /* CONFIG_HAS_WAKELOCK */
#if defined(OEM_ANDROID)
/* net_device interface lock, prevent race conditions among net_dev interface
* calls and wifi_on or wifi_off
*/
@@ -139,6 +151,7 @@ typedef struct dhd_info {
#if defined(PKT_FILTER_SUPPORT) && defined(APF)
struct mutex dhd_apf_mutex;
#endif /* PKT_FILTER_SUPPORT && APF */
#endif /* OEM_ANDROID */
spinlock_t wakelock_spinlock;
spinlock_t wakelock_evt_spinlock;
uint32 wakelock_counter;
@@ -175,10 +188,14 @@ typedef struct dhd_info {
#endif /* FIX_BUS_MIN_CLOCK */
#endif /* FIX_CPU_MIN_CLOCK */
void *dhd_deferred_wq;
#if (defined(BCM_ROUTER_DHD) && defined(HNDCTF))
ctf_t *cih; /* ctf instance handle */
ctf_brc_hot_t *brc_hot; /* hot ctf bridge cache entry */
#endif /* BCM_ROUTER_DHD && HNDCTF */
#ifdef DEBUG_CPU_FREQ
struct notifier_block freq_trans;
int __percpu *new_freq;
#endif // endif
#endif
unsigned int unit;
struct notifier_block pm_notifier;
#ifdef DHD_PSTA
@@ -189,14 +206,22 @@ typedef struct dhd_info {
#endif /* DHD_WET */
#ifdef DHD_DEBUG
dhd_dump_t *dump;
struct timer_list join_timer;
timer_list_compat_t join_timer;
u32 join_timeout_val;
bool join_timer_active;
uint scan_time_count;
struct timer_list scan_timer;
timer_list_compat_t scan_timer;
bool scan_timer_active;
#endif // endif
#endif
struct delayed_work dhd_dpc_dispatcher_work;
/* CPU on which the DHD DPC is running */
atomic_t dpc_cpu;
atomic_t prev_dpc_cpu;
#if defined(DHD_LB)
#if defined(DHD_LB_HOST_CTRL)
bool permitted_primary_cpu;
#endif /* DHD_LB_HOST_CTRL */
/* CPU Load Balance dynamic CPU selection */
/* Variable that tracks the currect CPUs available for candidacy */
@@ -208,14 +233,6 @@ typedef struct dhd_info {
struct notifier_block cpu_notifier;
/* Tasklet to handle Tx Completion packet freeing */
struct tasklet_struct tx_compl_tasklet;
atomic_t tx_compl_cpu;
/* Tasklet to handle RxBuf Post during Rx completion */
struct tasklet_struct rx_compl_tasklet;
atomic_t rx_compl_cpu;
/* Napi struct for handling rx packet sendup. Packets are removed from
* H2D RxCompl ring and placed into rx_pend_queue. rx_pend_queue is then
* appended to rx_napi_queue (w/ lock) and the rx_napi_struct is scheduled
@@ -223,19 +240,23 @@ typedef struct dhd_info {
*/
struct sk_buff_head rx_pend_queue ____cacheline_aligned;
struct sk_buff_head rx_napi_queue ____cacheline_aligned;
struct sk_buff_head rx_process_queue ____cacheline_aligned;
struct napi_struct rx_napi_struct ____cacheline_aligned;
atomic_t rx_napi_cpu; /* cpu on which the napi is dispatched */
struct net_device *rx_napi_netdev; /* netdev of primary interface */
struct work_struct rx_napi_dispatcher_work;
struct work_struct tx_compl_dispatcher_work;
struct work_struct tx_compl_dispatcher_work;
struct work_struct tx_dispatcher_work;
struct work_struct rx_compl_dispatcher_work;
struct work_struct rx_compl_dispatcher_work;
/* Number of times DPC Tasklet ran */
uint32 dhd_dpc_cnt;
/* Number of times NAPI processing got scheduled */
uint32 napi_sched_cnt;
/* NAPI latency stats */
uint64 *napi_latency;
uint64 napi_schedule_time;
/* Number of times NAPI processing ran on each available core */
uint32 *napi_percpu_run_cnt;
/* Number of times RX Completions got scheduled */
@@ -297,7 +318,6 @@ typedef struct dhd_info {
*/
struct sk_buff_head tx_pend_queue ____cacheline_aligned;
/* Control RXP in runtime, enable by default */
/* cpu on which the DHD Tx is happenning */
atomic_t tx_cpu;
@@ -326,6 +346,8 @@ typedef struct dhd_info {
uint32 *napi_rx_hist[HIST_BIN_SIZE];
uint32 *txc_hist[HIST_BIN_SIZE];
uint32 *rxc_hist[HIST_BIN_SIZE];
struct kobject dhd_lb_kobj;
bool dhd_lb_candidacy_override;
#endif /* DHD_LB */
#if defined(DNGL_AXI_ERROR_LOGGING) && defined(DHD_USE_WQ_FOR_DNGL_AXI_ERROR)
struct work_struct axi_error_dispatcher_work;
@@ -338,11 +360,26 @@ typedef struct dhd_info {
#endif /* DHD_USE_KTHREAD_FOR_LOGTRACE */
#endif /* SHOW_LOGTRACE */
#ifdef BTLOG
struct work_struct bt_log_dispatcher_work;
#endif /* SHOW_LOGTRACE */
#ifdef EWP_EDL
struct delayed_work edl_dispatcher_work;
#endif
#if defined(WLAN_ACCEL_BOOT)
int fs_check_retry;
struct delayed_work wl_accel_work;
bool wl_accel_force_reg_on;
bool wl_accel_boot_on_done;
#endif
#if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW)
#if defined(BCMDBUS)
struct task_struct *fw_download_task;
struct semaphore fw_download_lock;
#endif /* BCMDBUS */
#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */
struct kobject dhd_kobj;
struct kobject dhd_conf_file_kobj;
struct timer_list timesync_timer;
timer_list_compat_t timesync_timer;
#if defined(BT_OVER_SDIO)
char btfw_path[PATH_MAX];
#endif /* defined (BT_OVER_SDIO) */
@@ -351,30 +388,67 @@ typedef struct dhd_info {
struct sk_buff *monitor_skb;
uint monitor_len;
uint monitor_type; /* monitor pseudo device */
#ifdef HOST_RADIOTAP_CONV
monitor_info_t *monitor_info;
uint host_radiotap_conv;
#endif /* HOST_RADIOTAP_CONV */
#endif /* WL_MONITOR */
#if defined(BT_OVER_SDIO)
#if defined (BT_OVER_SDIO)
struct mutex bus_user_lock; /* lock for sdio bus apis shared between WLAN & BT */
int bus_user_count; /* User counts of sdio bus shared between WLAN & BT */
#endif /* BT_OVER_SDIO */
#ifdef SHOW_LOGTRACE
struct sk_buff_head evt_trace_queue ____cacheline_aligned;
#endif // endif
#endif
#ifdef DHD_PCIE_NATIVE_RUNTIMEPM
struct workqueue_struct *tx_wq;
struct workqueue_struct *rx_wq;
#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
#ifdef BTLOG
struct sk_buff_head bt_log_queue ____cacheline_aligned;
#endif /* BTLOG */
#ifdef PCIE_INB_DW
wait_queue_head_t ds_exit_wait;
#endif /* PCIE_INB_DW */
#ifdef DHD_DEBUG_UART
bool duart_execute;
#endif /* DHD_DEBUG_UART */
#ifdef BT_OVER_PCIE
struct mutex quiesce_flr_lock;
struct mutex quiesce_lock;
enum dhd_bus_quiesce_state dhd_quiesce_state;
#endif /* BT_OVER_PCIE */
struct mutex logdump_lock;
#if defined(GDB_PROXY) && defined(PCIE_FULL_DONGLE) && defined(BCMINTERNAL)
/* Root directory for GDB Proxy's (proc)fs files, used by first (default) interface */
struct proc_dir_entry *gdb_proxy_fs_root;
/* Name of procfs root directory */
char gdb_proxy_fs_root_name[100];
#endif /* defined(GDB_PROXY) && defined(PCIE_FULL_DONGLE) && defined(BCMINTERNAL) */
#if defined(DHD_MQ) && defined(DHD_MQ_STATS)
uint64 pktcnt_qac_histo[MQ_MAX_QUEUES][AC_COUNT];
uint64 pktcnt_per_ac[AC_COUNT];
uint64 cpu_qstats[MQ_MAX_QUEUES][MQ_MAX_CPUS];
#endif /* DHD_MQ && DHD_MQ_STATS */
/* indicates mem_dump was scheduled as work queue or called directly */
bool scheduled_memdump;
#ifdef DHD_PKTTS
bool latency; /* pktts enab flag */
pktts_flow_t config[PKTTS_CONFIG_MAX]; /* pktts user config */
#endif /* DHD_PKTTS */
struct work_struct dhd_hang_process_work;
#ifdef DHD_HP2P
spinlock_t hp2p_lock;
#endif /* DHD_HP2P */
#ifdef DHD_QOS_ON_SOCK_FLOW
struct dhd_sock_qos_info *psk_qos;
#endif
} dhd_info_t;
#ifdef WL_MONITOR
#define MONPKT_EXTRA_LEN 48u
#endif /* WL_MONITOR */
extern int dhd_sysfs_init(dhd_info_t *dhd);
extern void dhd_sysfs_exit(dhd_info_t *dhd);
extern void dhd_dbg_ring_proc_create(dhd_pub_t *dhdp);
@@ -382,6 +456,7 @@ extern void dhd_dbg_ring_proc_destroy(dhd_pub_t *dhdp);
int __dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf);
void dhd_dpc_tasklet_dispatcher_work(struct work_struct * work);
#if defined(DHD_LB)
#if defined(DHD_LB_TXP)
int dhd_lb_sendpkt(dhd_info_t *dhd, struct net_device *net, int ifidx, void *skb);
@@ -393,9 +468,10 @@ void dhd_lb_tx_handler(unsigned long data);
#if defined(DHD_LB_RXP)
int dhd_napi_poll(struct napi_struct *napi, int budget);
void dhd_rx_napi_dispatcher_fn(struct work_struct * work);
void dhd_rx_napi_dispatcher_work(struct work_struct * work);
void dhd_lb_rx_napi_dispatch(dhd_pub_t *dhdp);
void dhd_lb_rx_pkt_enqueue(dhd_pub_t *dhdp, void *pkt, int ifidx);
unsigned long dhd_read_lb_rxp(dhd_pub_t *dhdp);
#endif /* DHD_LB_RXP */
void dhd_lb_set_default_cpus(dhd_info_t *dhd);
@@ -413,20 +489,28 @@ int dhd_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcp
int dhd_register_cpuhp_callback(dhd_info_t *dhd);
int dhd_unregister_cpuhp_callback(dhd_info_t *dhd);
#if defined(DHD_LB_TXC)
void dhd_lb_tx_compl_dispatch(dhd_pub_t *dhdp);
#endif /* DHD_LB_TXC */
#if defined(DHD_LB_RXC)
void dhd_lb_rx_compl_dispatch(dhd_pub_t *dhdp);
void dhd_rx_compl_dispatcher_fn(struct work_struct * work);
#endif /* DHD_LB_RXC */
#endif /* DHD_LB */
#if defined(DHD_LB_IRQSET) || defined(DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON)
#if defined(DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON)
void dhd_irq_set_affinity(dhd_pub_t *dhdp, const struct cpumask *cpumask);
#endif /* DHD_LB_IRQSET || DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON */
#endif /* DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON */
#ifdef DHD_SSSR_DUMP
extern uint sssr_enab;
extern uint fis_enab;
#endif /* DHD_SSSR_DUMP */
#ifdef CONFIG_HAS_WAKELOCK
enum {
WAKE_LOCK_SUSPEND, /* Prevent suspend */
WAKE_LOCK_TYPE_COUNT
};
#define dhd_wake_lock_init(wakeup_source, type, name) wakeup_source_add(wakeup_source)
#define dhd_wake_lock_destroy(wakeup_source) wakeup_source_remove(wakeup_source)
#define dhd_wake_lock(wakeup_source) __pm_stay_awake(wakeup_source)
#define dhd_wake_unlock(wakeup_source) __pm_relax(wakeup_source)
#define dhd_wake_lock_active(wakeup_source) ((wakeup_source)->active)
#define dhd_wake_lock_timeout(wakeup_source, timeout) \
__pm_wakeup_event(wakeup_source, jiffies_to_msecs(timeout))
#endif /* CONFIG_HAS_WAKELOCK */
#endif /* __DHD_LINUX_PRIV_H__ */

View File

@@ -1,14 +1,14 @@
/*
* Expose some of the kernel scheduler routines
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,15 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_linux_sched.c 514727 2014-11-12 03:02:48Z $
* $Id$
*/
#include <linux/kernel.h>
#include <linux/module.h>
@@ -35,17 +31,17 @@
int setScheduler(struct task_struct *p, int policy, struct sched_param *param)
{
int rc = 0;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0))
sched_set_fifo_low(p);
#else
rc = sched_setscheduler(p, policy, param);
#endif /* LinuxVer */
#endif
return rc;
}
int get_scheduler_policy(struct task_struct *p)
{
int rc = SCHED_NORMAL;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
rc = p->policy;
#endif /* LinuxVer */
return rc;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,118 @@
/*
* Header file for DHD TPA (Traffic Pattern Analyzer)
*
* Provides type definitions and function prototypes to call into
* DHD's QOS on Socket Flow module.
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id$
*
*/
#ifndef _DHD_LINUX_TPA_H_
#define _DHD_LINUX_TPA_H_
struct dhd_sock_flow_info;
#if defined(DHD_QOS_ON_SOCK_FLOW)
#define QOS_SAMPLING_INTVL_MS 100
/* Feature Enabed original implementation */
int dhd_init_sock_flows_buf(dhd_info_t *dhd, uint watchdog_ms);
int dhd_deinit_sock_flows_buf(dhd_info_t *dhd);
void dhd_update_sock_flows(dhd_info_t *dhd, struct sk_buff *skb);
void dhd_analyze_sock_flows(dhd_info_t *dhd, uint32 watchdog_ms);
/* sysfs call backs */
unsigned long dhd_sock_qos_get_status(dhd_info_t *dhd);
void dhd_sock_qos_set_status(dhd_info_t *dhd, unsigned long on_off);
ssize_t dhd_sock_qos_show_stats(dhd_info_t *dhd, char *buf, ssize_t sz);
void dhd_sock_qos_clear_stats(dhd_info_t *dhd);
unsigned long dhd_sock_qos_get_force_upgrade(dhd_info_t *dhd);
void dhd_sock_qos_set_force_upgrade(dhd_info_t *dhd, unsigned long force_upgrade);
int dhd_sock_qos_get_numfl_upgrd_thresh(dhd_info_t *dhd);
void dhd_sock_qos_set_numfl_upgrd_thresh(dhd_info_t *dhd, int upgrade_thresh);
void dhd_sock_qos_get_avgpktsize_thresh(dhd_info_t *dhd,
unsigned long *avgpktsize_low,
unsigned long *avgpktsize_high);
void dhd_sock_qos_set_avgpktsize_thresh(dhd_info_t *dhd,
unsigned long avgpktsize_low,
unsigned long avgpktsize_high);
void dhd_sock_qos_get_numpkts_thresh(dhd_info_t *dhd,
unsigned long *numpkts_low,
unsigned long *numpkts_high);
void dhd_sock_qos_set_numpkts_thresh(dhd_info_t *dhd,
unsigned long numpkts_low,
unsigned long numpkts_high);
void dhd_sock_qos_get_detectcnt_thresh(dhd_info_t *dhd,
unsigned char *detectcnt_inc,
unsigned char *detectcnt_dec);
void dhd_sock_qos_set_detectcnt_thresh(dhd_info_t *dhd,
unsigned char detectcnt_inc,
unsigned char detectcnt_dec);
int dhd_sock_qos_get_detectcnt_upgrd_thresh(dhd_info_t *dhd);
void dhd_sock_qos_set_detectcnt_upgrd_thresh(dhd_info_t *dhd,
unsigned char detect_upgrd_thresh);
int dhd_sock_qos_get_maxfl(dhd_info_t *dhd);
void dhd_sock_qos_set_maxfl(dhd_info_t *dhd, unsigned int maxfl);
/* Update from Bus Layer */
void dhd_sock_qos_update_bus_flowid(dhd_info_t *dhd, void *pktbuf,
uint32 bus_flow_id);
#else
/* Feature Disabled dummy implementations */
inline int dhd_init_sock_flows_buf(dhd_info_t *dhd, uint watchdog_ms)
{
BCM_REFERENCE(dhd);
return BCME_UNSUPPORTED;
}
inline int dhd_deinit_sock_flows_buf(dhd_info_t *dhd)
{
BCM_REFERENCE(dhd);
return BCME_UNSUPPORTED;
}
inline void dhd_update_sock_flows(dhd_info_t *dhd, struct sk_buff *skb)
{
BCM_REFERENCE(dhd);
BCM_REFERENCE(skb);
return;
}
inline void dhd_analyze_sock_flows(dhd_info_t *dhd, uint32 watchdog_ms)
{
BCM_REFERENCE(dhd);
BCM_REFERENCE(dhd_watchdog_ms);
return;
}
inline void dhd_sock_qos_update_bus_flowid(dhd_info_t *dhd, void *pktbuf,
uint32 bus_flow_id)
{
BCM_REFERENCE(dhd);
BCM_REFERENCE(pktbuf);
BCM_REFERENCE(bus_flow_id);
}
#endif /* End of !DHD_QOS_ON_SOCK_FLOW */
#endif /* _DHD_LINUX_TPA_H_ */

View File

@@ -2,14 +2,14 @@
* Broadcom Dongle Host Driver (DHD), Generic work queue framework
* Generic interface to handle dhd deferred work events
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -17,15 +17,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_linux_wq.c 641330 2016-06-02 06:55:00Z $
* $Id$
*/
#include <linux/init.h>
@@ -46,6 +42,11 @@
#include <dhd_dbg.h>
#include <dhd_linux_wq.h>
/*
* XXX: always make sure that the size of this structure is aligned to
* the power of 2 (2^n) i.e, if any new variable has to be added then
* modify the padding accordingly
*/
typedef struct dhd_deferred_event {
u8 event; /* holds the event */
void *event_data; /* holds event specific data */
@@ -71,28 +72,25 @@ struct dhd_deferred_wq {
struct work_struct deferred_work; /* should be the first member */
struct kfifo *prio_fifo;
struct kfifo *work_fifo;
u8 *prio_fifo_buf;
u8 *work_fifo_buf;
spinlock_t work_lock;
void *dhd_info; /* review: does it require */
struct kfifo *work_fifo;
u8 *prio_fifo_buf;
u8 *work_fifo_buf;
spinlock_t work_lock;
void *dhd_info; /* review: does it require */
u32 event_skip_mask;
};
static inline struct kfifo*
dhd_kfifo_init(u8 *buf, int size, spinlock_t *lock)
{
struct kfifo *fifo;
gfp_t flags = CAN_SLEEP() ? GFP_KERNEL : GFP_ATOMIC;
gfp_t flags = CAN_SLEEP()? GFP_KERNEL : GFP_ATOMIC;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33))
fifo = kfifo_init(buf, size, flags, lock);
#else
fifo = (struct kfifo *)kzalloc(sizeof(struct kfifo), flags);
if (!fifo) {
return NULL;
}
kfifo_init(fifo, buf, size);
#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */
return fifo;
}
@@ -100,10 +98,7 @@ static inline void
dhd_kfifo_free(struct kfifo *fifo)
{
kfifo_free(fifo);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31))
/* FC11 releases the fifo memory */
kfree(fifo);
#endif
}
/* deferred work functions */
@@ -112,10 +107,10 @@ static void dhd_deferred_work_handler(struct work_struct *data);
void*
dhd_deferred_work_init(void *dhd_info)
{
struct dhd_deferred_wq *work = NULL;
u8* buf;
unsigned long fifo_size = 0;
gfp_t flags = CAN_SLEEP() ? GFP_KERNEL : GFP_ATOMIC;
struct dhd_deferred_wq *work = NULL;
u8* buf;
unsigned long fifo_size = 0;
gfp_t flags = CAN_SLEEP()? GFP_KERNEL : GFP_ATOMIC;
if (!dhd_info) {
DHD_ERROR(("%s: dhd info not initialized\n", __FUNCTION__));
@@ -170,6 +165,7 @@ dhd_deferred_work_init(void *dhd_info)
}
work->dhd_info = dhd_info;
work->event_skip_mask = 0;
DHD_ERROR(("%s: work queue initialized\n", __FUNCTION__));
return work;
@@ -186,7 +182,6 @@ dhd_deferred_work_deinit(void *work)
{
struct dhd_deferred_wq *deferred_work = work;
if (!deferred_work) {
DHD_ERROR(("%s: deferred work has been freed already\n",
__FUNCTION__));
@@ -256,6 +251,12 @@ dhd_deferred_schedule_work(void *workq, void *event_data, u8 event,
return DHD_WQ_STS_UNKNOWN_PRIORITY;
}
if ((deferred_wq->event_skip_mask & (1 << event))) {
DHD_ERROR(("%s: Skip event requested. Mask = 0x%x\n",
__FUNCTION__, deferred_wq->event_skip_mask));
return DHD_WQ_STS_EVENT_SKIPPED;
}
/*
* default element size is 1, which can be changed
* using kfifo_esize(). Older kernel(FC11) doesn't support
@@ -363,6 +364,12 @@ dhd_deferred_work_handler(struct work_struct *work)
continue;
}
/*
* XXX: don't do NULL check for 'work_event.event_data'
* as for some events like DHD_WQ_WORK_DHD_LOG_DUMP the
* event data is always NULL even though rest of the
* event parameters are valid
*/
if (work_event.event_handler) {
work_event.event_handler(deferred_work->dhd_info,
@@ -377,3 +384,22 @@ dhd_deferred_work_handler(struct work_struct *work)
return;
}
void
dhd_deferred_work_set_skip(void *work, u8 event, bool set)
{
struct dhd_deferred_wq *deferred_wq = (struct dhd_deferred_wq *)work;
if (!deferred_wq || !event || (event >= DHD_MAX_WQ_EVENTS)) {
DHD_ERROR(("%s: Invalid!!\n", __FUNCTION__));
return;
}
if (set) {
/* Set */
deferred_wq->event_skip_mask |= (1 << event);
} else {
/* Clear */
deferred_wq->event_skip_mask &= ~(1 << event);
}
}

View File

@@ -2,14 +2,14 @@
* Broadcom Dongle Host Driver (DHD), Generic work queue framework
* Generic interface to handle dhd deferred work events
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -17,15 +17,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_linux_wq.h 704361 2017-06-13 08:50:38Z $
* $Id$
*/
#ifndef _dhd_linux_wq_h_
#define _dhd_linux_wq_h_
@@ -39,14 +35,24 @@ enum _wq_event {
DHD_WQ_WORK_SET_MCAST_LIST,
DHD_WQ_WORK_IPV6_NDO,
DHD_WQ_WORK_HANG_MSG,
DHD_WQ_WORK_SOC_RAM_DUMP,
DHD_WQ_WORK_DHD_LOG_DUMP,
DHD_WQ_WORK_PKTLOG_DUMP,
DHD_WQ_WORK_INFORM_DHD_MON,
DHD_WQ_WORK_EVENT_LOGTRACE,
DHD_WQ_WORK_DMA_LB_MEM_REL,
DHD_WQ_WORK_NATOE_EVENT,
DHD_WQ_WORK_NATOE_IOCTL,
DHD_WQ_WORK_MACDBG,
DHD_WQ_WORK_DEBUG_UART_DUMP,
DHD_WQ_WORK_SSSR_DUMP,
DHD_WQ_WORK_PKTLOG_DUMP,
DHD_WQ_WORK_GET_BIGDATA_AP,
DHD_WQ_WORK_SOC_RAM_DUMP,
DHD_WQ_WORK_SOC_RAM_COLLECT,
#ifdef DHD_ERPOM
DHD_WQ_WORK_ERROR_RECOVERY,
#endif /* DHD_ERPOM */
DHD_WQ_WORK_H2D_CONSOLE_TIME_STAMP_MATCH,
DHD_WQ_WORK_AXI_ERROR_DUMP,
DHD_WQ_WORK_CTO_RECOVERY,
#ifdef DHD_UPDATE_INTF_MAC
DHD_WQ_WORK_IF_UPDATE,
#endif /* DHD_UPDATE_INTF_MAC */
@@ -71,6 +77,7 @@ enum wq_priority {
#define DHD_WQ_STS_SCHED_FAILED -3
#define DHD_WQ_STS_UNKNOWN_EVENT -4
#define DHD_WQ_STS_UNKNOWN_PRIORITY -5
#define DHD_WQ_STS_EVENT_SKIPPED -6
typedef void (*event_handler_t)(void *handle, void *event_data, u8 event);
@@ -78,4 +85,5 @@ void *dhd_deferred_work_init(void *dhd);
void dhd_deferred_work_deinit(void *workq);
int dhd_deferred_schedule_work(void *workq, void *event_data, u8 event,
event_handler_t evt_handler, u8 priority);
void dhd_deferred_work_set_skip(void *work, u8 event, bool set);
#endif /* _dhd_linux_wq_h_ */

View File

@@ -0,0 +1,746 @@
/* D11 macdbg functions for Broadcom 802.11abgn
* Networking Adapter Device Drivers.
*
* Broadcom Proprietary and Confidential. Copyright (C) 2020,
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
* the contents of this file may not be disclosed to third parties,
* copied or duplicated in any form, in whole or in part, without
* the prior written permission of Broadcom.
*
*
* <<Broadcom-WL-IPTag/Proprietary:>>
*
* $Id: dhd_macdbg.c 670412 2016-11-15 20:01:18Z shinuk $
*/
#ifdef BCMDBG
#include <typedefs.h>
#include <osl.h>
#include <bcmutils.h>
#include <dhd_dbg.h>
#include <dhd_macdbg.h>
#include "d11reglist_proto.h"
#include "dhdioctl.h"
#include <sdiovar.h>
#ifdef BCMDBUS
#include <dbus.h>
#define BUS_IOVAR_OP(a, b, c, d, e, f, g) dbus_iovar_op(a->dbus, b, c, d, e, f, g)
#else
#include <dhd_bus.h>
#define BUS_IOVAR_OP dhd_bus_iovar_op
#endif
typedef struct _macdbg_info_t {
dhd_pub_t *dhdp;
d11regs_list_t *pd11regs;
uint16 d11regs_sz;
d11regs_list_t *pd11regs_x;
uint16 d11regsx_sz;
svmp_list_t *psvmpmems;
uint16 svmpmems_sz;
} macdbg_info_t;
#define SVMPLIST_HARDCODE
int
dhd_macdbg_attach(dhd_pub_t *dhdp)
{
macdbg_info_t *macdbg_info = MALLOCZ(dhdp->osh, sizeof(*macdbg_info));
#ifdef SVMPLIST_HARDCODE
svmp_list_t svmpmems[] = {
{0x20000, 256},
{0x21e10, 16},
{0x20300, 16},
{0x20700, 16},
{0x20b00, 16},
{0x20be0, 16},
{0x20bff, 16},
{0xc000, 32},
{0xe000, 32},
{0x10000, 0x8000},
{0x18000, 0x8000}
};
#endif /* SVMPLIST_HARDCODE */
if (macdbg_info == NULL) {
return BCME_NOMEM;
}
dhdp->macdbg_info = macdbg_info;
macdbg_info->dhdp = dhdp;
#ifdef SVMPLIST_HARDCODE
macdbg_info->psvmpmems = MALLOCZ(dhdp->osh, sizeof(svmpmems));
if (macdbg_info->psvmpmems == NULL) {
return BCME_NOMEM;
}
macdbg_info->svmpmems_sz = ARRAYSIZE(svmpmems);
memcpy(macdbg_info->psvmpmems, svmpmems, sizeof(svmpmems));
DHD_ERROR(("%s: psvmpmems %p svmpmems_sz %d\n",
__FUNCTION__, macdbg_info->psvmpmems, macdbg_info->svmpmems_sz));
#endif
return BCME_OK;
}
void
dhd_macdbg_detach(dhd_pub_t *dhdp)
{
macdbg_info_t *macdbg_info = dhdp->macdbg_info;
ASSERT(macdbg_info);
if (macdbg_info->pd11regs) {
ASSERT(macdbg_info->d11regs_sz > 0);
MFREE(dhdp->osh, macdbg_info->pd11regs,
(macdbg_info->d11regs_sz * sizeof(macdbg_info->pd11regs[0])));
macdbg_info->d11regs_sz = 0;
}
if (macdbg_info->pd11regs_x) {
ASSERT(macdbg_info->d11regsx_sz > 0);
MFREE(dhdp->osh, macdbg_info->pd11regs_x,
(macdbg_info->d11regsx_sz * sizeof(macdbg_info->pd11regs_x[0])));
macdbg_info->d11regsx_sz = 0;
}
if (macdbg_info->psvmpmems) {
ASSERT(macdbg_info->svmpmems_sz > 0);
MFREE(dhdp->osh, macdbg_info->psvmpmems,
(macdbg_info->svmpmems_sz * sizeof(macdbg_info->psvmpmems[0])));
macdbg_info->svmpmems_sz = 0;
}
MFREE(dhdp->osh, macdbg_info, sizeof(*macdbg_info));
}
void
dhd_macdbg_event_handler(dhd_pub_t *dhdp, uint32 reason,
uint8 *event_data, uint32 datalen)
{
d11regs_list_t *pd11regs;
macdbg_info_t *macdbg_info = dhdp->macdbg_info;
uint d11regs_sz;
DHD_TRACE(("%s: reason %d datalen %d\n", __FUNCTION__, reason, datalen));
switch (reason) {
case WLC_E_MACDBG_LIST_PSMX:
/* Fall through */
case WLC_E_MACDBG_LIST_PSM:
pd11regs = MALLOCZ(dhdp->osh, datalen);
if (pd11regs == NULL) {
DHD_ERROR(("%s: NOMEM for len %d\n", __FUNCTION__, datalen));
return;
}
memcpy(pd11regs, event_data, datalen);
d11regs_sz = datalen / sizeof(pd11regs[0]);
DHD_ERROR(("%s: d11regs %p d11regs_sz %d\n",
__FUNCTION__, pd11regs, d11regs_sz));
if (reason == WLC_E_MACDBG_LIST_PSM) {
macdbg_info->pd11regs = pd11regs;
macdbg_info->d11regs_sz = (uint16)d11regs_sz;
} else {
macdbg_info->pd11regs_x = pd11regs;
macdbg_info->d11regsx_sz = (uint16)d11regs_sz;
}
break;
case WLC_E_MACDBG_REGALL:
#ifdef LINUX
/* Schedule to work queue as this context could be ISR */
dhd_schedule_macdbg_dump(dhdp);
#else
/* Dump PSMr */
(void) dhd_macdbg_dumpmac(dhdp, NULL, 0, NULL, FALSE);
/* Dump PSMx */
(void) dhd_macdbg_dumpmac(dhdp, NULL, 0, NULL, TRUE);
/* Dump SVMP mems */
(void) dhd_macdbg_dumpsvmp(dhdp, NULL, 0, NULL);
#endif
break;
default:
DHD_ERROR(("%s: Unknown reason %d\n",
__FUNCTION__, reason));
}
return;
}
static uint16
_dhd_get_ihr16(macdbg_info_t *macdbg_info, uint16 addr, struct bcmstrbuf *b, bool verbose)
{
sdreg_t sdreg;
uint16 val;
sdreg.func = 2;
sdreg.offset = (0x1000 | addr);
BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg",
&sdreg, sizeof(sdreg), &val, sizeof(val), IOV_GET);
if (verbose) {
if (b) {
bcm_bprintf(b, "DEBUG: IHR16: read 0x%08x, size 2, value 0x%04x\n",
(addr + 0x18001000), val);
} else {
printf("DEBUG: IHR16: read 0x%08x, size 2, value 0x%04x\n",
(addr + 0x18001000), val);
}
}
return val;
}
static uint32
_dhd_get_ihr32(macdbg_info_t *macdbg_info, uint16 addr, struct bcmstrbuf *b, bool verbose)
{
sdreg_t sdreg;
uint32 val;
sdreg.func = 4;
sdreg.offset = (0x1000 | addr);
BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg",
&sdreg, sizeof(sdreg), &val, sizeof(val), IOV_GET);
if (verbose) {
if (b) {
bcm_bprintf(b, "DEBUG: IHR32: read 0x%08x, size 4, value 0x%08x\n",
(addr + 0x18001000), val);
} else {
printf("DEBUG: IHR32: read 0x%08x, size 4, value 0x%08x\n",
(addr + 0x18001000), val);
}
}
return val;
}
static void
_dhd_set_ihr16(macdbg_info_t *macdbg_info, uint16 addr, uint16 val,
struct bcmstrbuf *b, bool verbose)
{
sdreg_t sdreg;
sdreg.func = 2;
sdreg.offset = (0x1000 | addr);
sdreg.value = val;
if (verbose) {
if (b) {
bcm_bprintf(b, "DEBUG: IHR16: write 0x%08x, size 2, value 0x%04x\n",
(addr + 0x18001000), val);
} else {
printf("DEBUG: IHR16: write 0x%08x, size 2, value 0x%04x\n",
(addr + 0x18001000), val);
}
}
BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg",
NULL, 0, &sdreg, sizeof(sdreg), IOV_SET);
}
static void
_dhd_set_ihr32(macdbg_info_t *macdbg_info, uint16 addr, uint32 val,
struct bcmstrbuf *b, bool verbose)
{
sdreg_t sdreg;
sdreg.func = 4;
sdreg.offset = (0x1000 | addr);
sdreg.value = val;
if (verbose) {
if (b) {
bcm_bprintf(b, "DEBUG: IHR32: write 0x%08x, size 4, value 0x%08x\n",
(addr + 0x18001000), val);
} else {
printf("DEBUG: IHR32: write 0x%08x, size 4, value 0x%08x\n",
(addr + 0x18001000), val);
}
}
BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg",
NULL, 0, &sdreg, sizeof(sdreg), IOV_SET);
}
static uint32
_dhd_get_d11obj32(macdbg_info_t *macdbg_info, uint16 objaddr, uint32 sel,
struct bcmstrbuf *b, bool verbose)
{
uint32 val;
sdreg_t sdreg;
sdreg.func = 4; // 4bytes by default.
sdreg.offset = 0x1160;
if (objaddr == 0xffff) {
if (verbose) {
goto objaddr_read;
} else {
goto objdata_read;
}
}
if (objaddr & 0x3) {
printf("%s: ERROR! Invalid addr 0x%x\n", __FUNCTION__, objaddr);
}
sdreg.value = (sel | (objaddr >> 2));
if (verbose) {
if (b) {
bcm_bprintf(b, "DEBUG: %s: Indirect: write 0x%08x, size %d, value 0x%08x\n",
(sel & 0x00020000) ? "SCR":"SHM",
(sdreg.offset + 0x18000000), sdreg.func, sdreg.value);
} else {
printf("DEBUG: %s: Indirect: write 0x%08x, size %d, value 0x%08x\n",
(sel & 0x00020000) ? "SCR":"SHM",
(sdreg.offset + 0x18000000), sdreg.func, sdreg.value);
}
}
BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg",
NULL, 0, &sdreg, sizeof(sdreg), IOV_SET);
objaddr_read:
/* Give some time to obj addr register */
BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg",
&sdreg, sizeof(sdreg), &val, sizeof(val), IOV_GET);
if (verbose) {
if (b) {
bcm_bprintf(b, "DEBUG: %s: Indirect: Read 0x%08x, size %d, value 0x%08x\n",
(sel & 0x00020000) ? "SCR":"SHM",
(sdreg.offset + 0x18000000), sdreg.func, val);
} else {
printf("DEBUG: %s: Indirect: Read 0x%08x, size %d, value 0x%08x\n",
(sel & 0x00020000) ? "SCR":"SHM",
(sdreg.offset + 0x18000000), sdreg.func, val);
}
}
objdata_read:
sdreg.offset = 0x1164;
BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg",
&sdreg, sizeof(sdreg), &val, sizeof(val), IOV_GET);
if (verbose) {
if (b) {
bcm_bprintf(b, "DEBUG: %s: Indirect: Read 0x%08x, size %d, value 0x%04x\n",
(sel & 0x00020000) ? "SCR":"SHM",
(sdreg.offset + 0x18000000), sdreg.func, val);
} else {
printf("DEBUG: %s: Indirect: Read 0x%08x, size %d, value 0x%04x\n",
(sel & 0x00020000) ? "SCR":"SHM",
(sdreg.offset + 0x18000000), sdreg.func, val);
}
}
return val;
}
static uint16
_dhd_get_d11obj16(macdbg_info_t *macdbg_info, uint16 objaddr,
uint32 sel, d11obj_cache_t *obj_cache, struct bcmstrbuf *b, bool verbose)
{
uint32 val;
if (obj_cache && obj_cache->cache_valid && ((obj_cache->sel ^ sel) & (0xffffff)) == 0) {
if (obj_cache->addr32 == (objaddr & ~0x3)) {
/* XXX: Same objaddr read as the previous one */
if (verbose) {
if (b) {
bcm_bprintf(b, "DEBUG: %s: Read cache value: "
"addr32 0x%04x, sel 0x%08x, value 0x%08x\n",
(sel & 0x00020000) ? "SCR":"SHM",
obj_cache->addr32, obj_cache->sel, obj_cache->val);
} else {
printf("DEBUG: %s: Read cache value: "
"addr32 0x%04x, sel 0x%08x, value 0x%08x\n",
(sel & 0x00020000) ? "SCR":"SHM",
obj_cache->addr32, obj_cache->sel, obj_cache->val);
}
}
val = obj_cache->val;
goto exit;
} else if ((obj_cache->sel & 0x02000000) &&
(obj_cache->addr32 + 4 == (objaddr & ~0x3))) {
/* XXX: objaddr is auto incrementing, so just read objdata */
if (verbose) {
if (b) {
bcm_bprintf(b, "DEBUG: %s: Read objdata only: "
"addr32 0x%04x, sel 0x%08x, value 0x%08x\n",
(sel & 0x00020000) ? "SCR":"SHM",
obj_cache->addr32, obj_cache->sel, obj_cache->val);
} else {
printf("DEBUG: %s: Read objdata only: "
"addr32 0x%04x, sel 0x%08x, value 0x%08x\n",
(sel & 0x00020000) ? "SCR":"SHM",
obj_cache->addr32, obj_cache->sel, obj_cache->val);
}
}
val = _dhd_get_d11obj32(macdbg_info, 0xffff, sel, b, verbose);
goto exit;
}
}
val = _dhd_get_d11obj32(macdbg_info, (objaddr & ~0x2), sel, b, verbose);
exit:
if (obj_cache) {
obj_cache->addr32 = (objaddr & ~0x3);
obj_cache->sel = sel;
obj_cache->val = val;
obj_cache->cache_valid = TRUE;
}
return (uint16)((objaddr & 0x2) ? (val >> 16) : val);
}
static int
_dhd_print_d11reg(macdbg_info_t *macdbg_info, int idx, int type, uint16 addr, struct bcmstrbuf *b,
d11obj_cache_t *obj_cache, bool verbose)
{
const char *regname[D11REG_TYPE_MAX] = D11REGTYPENAME;
uint32 val;
if (type == D11REG_TYPE_IHR32) {
if ((addr & 0x3)) {
printf("%s: ERROR! Invalid addr 0x%x\n", __FUNCTION__, addr);
addr &= ~0x3;
}
val = _dhd_get_ihr32(macdbg_info, addr, b, verbose);
if (b) {
bcm_bprintf(b, "%-3d %s 0x%-4x = 0x%-8x\n",
idx, regname[type], addr, val);
} else {
printf("%-3d %s 0x%-4x = 0x%-8x\n",
idx, regname[type], addr, val);
}
} else {
switch (type) {
case D11REG_TYPE_IHR16: {
if ((addr & 0x1)) {
printf("%s: ERROR! Invalid addr 0x%x\n", __FUNCTION__, addr);
addr &= ~0x1;
}
val = _dhd_get_ihr16(macdbg_info, addr, b, verbose);
break;
}
case D11REG_TYPE_IHRX16:
val = _dhd_get_d11obj16(macdbg_info, (addr - 0x400) << 1, 0x020b0000,
obj_cache, b, verbose);
break;
case D11REG_TYPE_SCR:
val = _dhd_get_d11obj16(macdbg_info, addr << 2, 0x02020000,
obj_cache, b, verbose);
break;
case D11REG_TYPE_SCRX:
val = _dhd_get_d11obj16(macdbg_info, addr << 2, 0x020a0000,
obj_cache, b, verbose);
break;
case D11REG_TYPE_SHM:
val = _dhd_get_d11obj16(macdbg_info, addr, 0x02010000,
obj_cache, b, verbose);
break;
case D11REG_TYPE_SHMX:
val = _dhd_get_d11obj16(macdbg_info, addr, 0x02090000,
obj_cache, b, verbose);
break;
default:
printf("Unrecognized type %d!\n", type);
return 0;
}
if (b) {
bcm_bprintf(b, "%-3d %s 0x%-4x = 0x%-4x\n",
idx, regname[type], addr, val);
} else {
printf("%-3d %s 0x%-4x = 0x%-4x\n",
idx, regname[type], addr, val);
}
}
return 1;
}
static int
_dhd_print_d11regs(macdbg_info_t *macdbg_info, d11regs_list_t *pregs,
int start_idx, struct bcmstrbuf *b, bool verbose)
{
uint16 addr;
int idx = 0;
d11obj_cache_t obj_cache = {0, 0, 0, FALSE};
addr = pregs->addr;
if (pregs->type >= D11REG_TYPE_MAX) {
printf("%s: wrong type %d\n", __FUNCTION__, pregs->type);
return 0;
}
if (pregs->bitmap) {
while (pregs->bitmap) {
if (pregs->bitmap && (pregs->bitmap & 0x1)) {
_dhd_print_d11reg(macdbg_info, (idx + start_idx), pregs->type,
addr, b, &obj_cache, verbose);
idx++;
}
pregs->bitmap = pregs->bitmap >> 1;
addr += pregs->step;
}
} else {
for (; idx < pregs->cnt; idx++) {
_dhd_print_d11reg(macdbg_info, (idx + start_idx), pregs->type,
addr, b, &obj_cache, verbose);
addr += pregs->step;
}
}
return idx;
}
static int
_dhd_pd11regs_bylist(macdbg_info_t *macdbg_info, d11regs_list_t *reglist,
uint16 reglist_sz, struct bcmstrbuf *b)
{
uint i, idx = 0;
if (reglist != NULL && reglist_sz > 0) {
for (i = 0; i < reglist_sz; i++) {
DHD_TRACE(("%s %d %p %d\n", __FUNCTION__, __LINE__,
&reglist[i], reglist_sz));
idx += _dhd_print_d11regs(macdbg_info, &reglist[i], idx, b, FALSE);
}
}
return idx;
}
int
dhd_macdbg_dumpmac(dhd_pub_t *dhdp, char *buf, int buflen,
int *outbuflen, bool dump_x)
{
macdbg_info_t *macdbg_info = dhdp->macdbg_info;
struct bcmstrbuf *b = NULL;
struct bcmstrbuf bcmstrbuf;
uint cnt = 0;
DHD_TRACE(("%s %d %p %d %p %d %p %d\n", __FUNCTION__, __LINE__,
buf, buflen, macdbg_info->pd11regs, macdbg_info->d11regs_sz,
macdbg_info->pd11regs_x, macdbg_info->d11regsx_sz));
if (buf && buflen > 0) {
bcm_binit(&bcmstrbuf, buf, buflen);
b = &bcmstrbuf;
}
if (!dump_x) {
/* Dump PSMr */
cnt += _dhd_pd11regs_bylist(macdbg_info, macdbg_info->pd11regs,
macdbg_info->d11regs_sz, b);
} else {
/* Dump PSMx */
cnt += _dhd_pd11regs_bylist(macdbg_info, macdbg_info->pd11regs_x,
macdbg_info->d11regsx_sz, b);
}
if (b && outbuflen) {
if ((uint)buflen > BCMSTRBUF_LEN(b)) {
*outbuflen = buflen - BCMSTRBUF_LEN(b);
} else {
DHD_ERROR(("%s: buflen insufficient!\n", __FUNCTION__));
*outbuflen = buflen;
/* Do not return buftooshort to allow printing macregs we have got */
}
}
return ((cnt > 0) ? BCME_OK : BCME_UNSUPPORTED);
}
int
dhd_macdbg_pd11regs(dhd_pub_t *dhdp, char *params, int plen, char *buf, int buflen)
{
macdbg_info_t *macdbg_info = dhdp->macdbg_info;
dhd_pd11regs_param *pd11regs = (void *)params;
dhd_pd11regs_buf *pd11regs_buf = (void *)buf;
uint16 start_idx;
bool verbose;
d11regs_list_t reglist;
struct bcmstrbuf *b = NULL;
struct bcmstrbuf bcmstrbuf;
start_idx = pd11regs->start_idx;
verbose = pd11regs->verbose;
memcpy(&reglist, pd11regs->plist, sizeof(reglist));
memset(buf, '\0', buflen);
bcm_binit(&bcmstrbuf, (char *)(pd11regs_buf->pbuf),
(buflen - OFFSETOF(dhd_pd11regs_buf, pbuf)));
b = &bcmstrbuf;
pd11regs_buf->idx = (uint16)_dhd_print_d11regs(macdbg_info, &reglist,
start_idx, b, verbose);
return ((pd11regs_buf->idx > 0) ? BCME_OK : BCME_ERROR);
}
int
dhd_macdbg_reglist(dhd_pub_t *dhdp, char *buf, int buflen)
{
int err, desc_idx = 0;
dhd_maclist_t *maclist = (dhd_maclist_t *)buf;
macdbg_info_t *macdbg_info = dhdp->macdbg_info;
void *xtlvbuf_p = maclist->plist;
uint16 xtlvbuflen = (uint16)buflen;
xtlv_desc_t xtlv_desc[] = {
{0, 0, NULL},
{0, 0, NULL},
{0, 0, NULL},
{0, 0, NULL}
};
if (!macdbg_info->pd11regs) {
err = BCME_NOTFOUND;
goto exit;
}
ASSERT(macdbg_info->d11regs_sz > 0);
xtlv_desc[desc_idx].type = DHD_MACLIST_XTLV_R;
xtlv_desc[desc_idx].len =
macdbg_info->d11regs_sz * (uint16)sizeof(*(macdbg_info->pd11regs));
xtlv_desc[desc_idx].ptr = macdbg_info->pd11regs;
desc_idx++;
if (macdbg_info->pd11regs_x) {
ASSERT(macdbg_info->d11regsx_sz);
xtlv_desc[desc_idx].type = DHD_MACLIST_XTLV_X;
xtlv_desc[desc_idx].len = macdbg_info->d11regsx_sz *
(uint16)sizeof(*(macdbg_info->pd11regs_x));
xtlv_desc[desc_idx].ptr = macdbg_info->pd11regs_x;
desc_idx++;
}
if (macdbg_info->psvmpmems) {
ASSERT(macdbg_info->svmpmems_sz);
xtlv_desc[desc_idx].type = DHD_SVMPLIST_XTLV;
xtlv_desc[desc_idx].len = macdbg_info->svmpmems_sz *
(uint16)sizeof(*(macdbg_info->psvmpmems));
xtlv_desc[desc_idx].ptr = macdbg_info->psvmpmems;
desc_idx++;
}
err = bcm_pack_xtlv_buf_from_mem((uint8 **)&xtlvbuf_p, &xtlvbuflen,
xtlv_desc, BCM_XTLV_OPTION_ALIGN32);
maclist->version = 0; /* No version control for now anyway */
maclist->bytes_len = (buflen - xtlvbuflen);
exit:
return err;
}
static int
_dhd_print_svmps(macdbg_info_t *macdbg_info, svmp_list_t *psvmp,
int start_idx, struct bcmstrbuf *b, bool verbose)
{
int idx;
uint32 addr, mem_id, offset, prev_mem_id, prev_offset;
uint16 cnt, val;
BCM_REFERENCE(start_idx);
/* Set tbl ID and tbl offset. */
_dhd_set_ihr32(macdbg_info, 0x3fc, 0x30000d, b, verbose);
_dhd_set_ihr32(macdbg_info, 0x3fc, 0x8000000e, b, verbose);
addr = psvmp->addr;
cnt = psvmp->cnt;
/* In validate previous mem_id and offset */
prev_mem_id = (uint32)(-1);
prev_offset = (uint32)(-1);
for (idx = 0; idx < cnt; idx++, addr++) {
mem_id = (addr >> 15);
offset = (addr & 0x7fff) >> 1;
if (mem_id != prev_mem_id) {
/* Set mem_id */
_dhd_set_ihr32(macdbg_info, 0x3fc, ((mem_id & 0xffff0000) | 0x10),
b, verbose);
_dhd_set_ihr32(macdbg_info, 0x3fc, ((mem_id << 16) | 0xf),
b, verbose);
}
if (offset != prev_offset) {
/* XXX: Is this needed?
* _dhd_set_ihr32(macdbg_info, 0x3fc, 0x30000d, b, verbose);
*/
/* svmp offset */
_dhd_set_ihr32(macdbg_info, 0x3fc, ((offset << 16) | 0xe),
b, verbose);
}
/* Read hi or lo */
_dhd_set_ihr16(macdbg_info, 0x3fc, ((addr & 0x1) ? 0x10 : 0xf), b, verbose);
val = _dhd_get_ihr16(macdbg_info, 0x3fe, b, verbose);
if (b) {
bcm_bprintf(b, "0x%-4x 0x%-4x\n",
addr, val);
} else {
printf("0x%-4x 0x%-4x\n",
addr, val);
}
prev_mem_id = mem_id;
prev_offset = offset;
}
return idx;
}
static int
_dhd_psvmps_bylist(macdbg_info_t *macdbg_info, svmp_list_t *svmplist,
uint16 svmplist_sz, struct bcmstrbuf *b)
{
uint i, idx = 0;
if (svmplist != NULL && svmplist_sz > 0) {
for (i = 0; i < svmplist_sz; i++) {
DHD_TRACE(("%s %d %p %d\n", __FUNCTION__, __LINE__,
&svmplist[i], svmplist_sz));
idx += _dhd_print_svmps(macdbg_info, &svmplist[i], idx, b, FALSE);
}
}
return idx;
}
int
dhd_macdbg_dumpsvmp(dhd_pub_t *dhdp, char *buf, int buflen,
int *outbuflen)
{
macdbg_info_t *macdbg_info = dhdp->macdbg_info;
struct bcmstrbuf *b = NULL;
struct bcmstrbuf bcmstrbuf;
uint cnt = 0;
DHD_TRACE(("%s %d %p %d %p %d\n", __FUNCTION__, __LINE__,
buf, buflen, macdbg_info->psvmpmems, macdbg_info->svmpmems_sz));
if (buf && buflen > 0) {
bcm_binit(&bcmstrbuf, buf, buflen);
b = &bcmstrbuf;
}
cnt = _dhd_psvmps_bylist(macdbg_info, macdbg_info->psvmpmems,
macdbg_info->svmpmems_sz, b);
if (b && outbuflen) {
if ((uint)buflen > BCMSTRBUF_LEN(b)) {
*outbuflen = buflen - BCMSTRBUF_LEN(b);
} else {
DHD_ERROR(("%s: buflen insufficient!\n", __FUNCTION__));
*outbuflen = buflen;
/* Do not return buftooshort to allow printing macregs we have got */
}
}
return ((cnt > 0) ? BCME_OK : BCME_UNSUPPORTED);
}
int
dhd_macdbg_psvmpmems(dhd_pub_t *dhdp, char *params, int plen, char *buf, int buflen)
{
macdbg_info_t *macdbg_info = dhdp->macdbg_info;
dhd_pd11regs_param *pd11regs = (void *)params;
dhd_pd11regs_buf *pd11regs_buf = (void *)buf;
uint16 start_idx;
bool verbose;
svmp_list_t reglist;
struct bcmstrbuf *b = NULL;
struct bcmstrbuf bcmstrbuf;
start_idx = pd11regs->start_idx;
verbose = pd11regs->verbose;
memcpy(&reglist, pd11regs->plist, sizeof(reglist));
memset(buf, '\0', buflen);
bcm_binit(&bcmstrbuf, (char *)(pd11regs_buf->pbuf),
(buflen - OFFSETOF(dhd_pd11regs_buf, pbuf)));
b = &bcmstrbuf;
pd11regs_buf->idx = (uint16)_dhd_print_svmps(macdbg_info, &reglist,
start_idx, b, verbose);
return ((pd11regs_buf->idx > 0) ? BCME_OK : BCME_ERROR);
}
#endif /* BCMDBG */

View File

@@ -0,0 +1,34 @@
/* D11 macdbg function prototypes for Broadcom 802.11abgn
* Networking Adapter Device Drivers.
*
* Broadcom Proprietary and Confidential. Copyright (C) 2020,
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
* the contents of this file may not be disclosed to third parties,
* copied or duplicated in any form, in whole or in part, without
* the prior written permission of Broadcom.
*
*
* <<Broadcom-WL-IPTag/Proprietary:>>
*
* $Id: dhd_macdbg.h 649388 2016-07-15 22:54:42Z shinuk $
*/
#ifndef _dhd_macdbg_h_
#define _dhd_macdbg_h_
#ifdef BCMDBG
#include <dngl_stats.h>
#include <dhd.h>
extern int dhd_macdbg_attach(dhd_pub_t *dhdp);
extern void dhd_macdbg_detach(dhd_pub_t *dhdp);
extern void dhd_macdbg_event_handler(dhd_pub_t *dhdp, uint32 reason,
uint8 *event_data, uint32 datalen);
extern int dhd_macdbg_dumpmac(dhd_pub_t *dhdp, char *buf, int buflen, int *outbuflen, bool dump_x);
extern int dhd_macdbg_pd11regs(dhd_pub_t *dhdp, char *params, int plen, char *buf, int buflen);
extern int dhd_macdbg_reglist(dhd_pub_t *dhdp, char *buf, int buflen);
extern int dhd_macdbg_dumpsvmp(dhd_pub_t *dhdp, char *buf, int buflen, int *outbuflen);
extern int dhd_macdbg_psvmpmems(dhd_pub_t *dhdp, char *params, int plen, char *buf, int buflen);
#endif /* BCMDBG */
#endif /* _dhd_macdbg_h_ */

View File

@@ -1,16 +1,14 @@
/*
* DHD debugability support
*
* <<Broadcom-WL-IPTag/Open:>>
* Copyright (C) 2020, Broadcom.
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -18,12 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: dhd_mschdbg.c 639872 2016-05-25 05:39:30Z $
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_mschdbg.c 639872 2016-05-25 05:39:30Z sjadhav $
*/
#ifdef SHOW_LOGTRACE
#include <typedefs.h>
@@ -49,13 +46,25 @@ static const char *head_log = "";
for (ii = 0; ii < space; ii += 4) MSCH_EVENT((" ")); \
} \
} while (0)
#ifdef DHD_EFI
#define MSCH_EVENT(args) \
do { \
if (dhd_msg_level & DHD_EVENT_VAL) { \
DHD_LOG_DUMP_WRITE_FW("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE_FW args; \
} \
} while (0)
#else
#define MSCH_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0)
#endif /* DHD_EFI */
static uint64 solt_start_time[4], req_start_time[4], profiler_start_time[4];
static uint32 solt_chanspec[4] = {0, }, req_start[4] = {0, };
static bool lastMessages = FALSE;
#define US_PRE_SEC 1000000
#define DATA_UNIT_FOR_LOG_CNT 4
static void dhd_mschdbg_us_to_sec(uint32 time_h, uint32 time_l, uint32 *sec, uint32 *remain)
{
@@ -194,7 +203,7 @@ dhd_mschdbg_timeslot_profiler_event_data(int sp, int ver, char *title, char *dat
MSCH_EVENT(("0x%08x\n", ntoh32(p->p_timeslot)));
s = (int)(ntoh32(p->state));
if (s > 5) s = 0;
if (s < 0 || s > 5) s = 0;
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("id: %d, state[%d]: %s, chan_ctxt: [0x%08x]\n",
@@ -647,18 +656,30 @@ static void dhd_mschdbg_dump_data(dhd_pub_t *dhdp, void *raw_event_ptr, int type
case WL_MSCH_PROFILER_EVENT_LOG:
{
while (len > 0) {
while (len >= (int)WL_MSCH_EVENT_LOG_HEAD_SIZE) {
msch_event_log_profiler_event_data_t *p =
(msch_event_log_profiler_event_data_t *)data;
/* TODO: How to parse MSCH if extended event tag is present ??? */
prcd_event_log_hdr_t hdr;
int size = WL_MSCH_EVENT_LOG_HEAD_SIZE + p->hdr.count * sizeof(uint32);
if (len < size || size > sizeof(msch_event_log_profiler_event_data_t)) {
break;
}
data += size;
len -= size;
dhd_mschdbg_us_to_sec(p->time_hi, p->time_lo, &s, &ss);
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("%06d.%06d [wl%d]: ", s, ss, p->hdr.tag));
p->hdr.tag = EVENT_LOG_TAG_MSCHPROFILE;
p->hdr.fmt_num = ntoh16(p->hdr.fmt_num);
dhd_dbg_verboselog_printf(dhdp, &p->hdr, raw_event_ptr, p->data);
bzero(&hdr, sizeof(hdr));
hdr.tag = EVENT_LOG_TAG_MSCHPROFILE;
hdr.count = p->hdr.count + 1;
/* exclude LSB 2 bits which indicate binary/non-binary data */
hdr.fmt_num = ntoh16(p->hdr.fmt_num) >> 2;
hdr.fmt_num_raw = ntoh16(p->hdr.fmt_num);
if (ntoh16(p->hdr.fmt_num) == DHD_OW_BI_RAW_EVENT_LOG_FMT) {
hdr.binary_payload = TRUE;
}
dhd_dbg_verboselog_printf(dhdp, &hdr, raw_event_ptr, p->data, 0, 0);
}
lastMessages = TRUE;
break;
@@ -724,23 +745,51 @@ wl_mschdbg_event_handler(dhd_pub_t *dhdp, void *raw_event_ptr, int type, void *d
}
void
wl_mschdbg_verboselog_handler(dhd_pub_t *dhdp, void *raw_event_ptr, int tag, uint32 *log_ptr)
wl_mschdbg_verboselog_handler(dhd_pub_t *dhdp, void *raw_event_ptr, prcd_event_log_hdr_t *plog_hdr,
uint32 *log_ptr)
{
uint32 log_pyld_len;
head_log = "CONSOLE";
if (tag == EVENT_LOG_TAG_MSCHPROFILE) {
if (plog_hdr->count == 0) {
return;
}
log_pyld_len = (plog_hdr->count - 1) * DATA_UNIT_FOR_LOG_CNT;
if (plog_hdr->tag == EVENT_LOG_TAG_MSCHPROFILE) {
msch_event_log_profiler_event_data_t *p =
(msch_event_log_profiler_event_data_t *)log_ptr;
/* TODO: How to parse MSCH if extended event tag is present ??? */
prcd_event_log_hdr_t hdr;
uint32 s, ss;
if (log_pyld_len < OFFSETOF(msch_event_log_profiler_event_data_t, data) ||
log_pyld_len > sizeof(msch_event_log_profiler_event_data_t)) {
return;
}
dhd_mschdbg_us_to_sec(p->time_hi, p->time_lo, &s, &ss);
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("%06d.%06d [wl%d]: ", s, ss, p->hdr.tag));
p->hdr.tag = EVENT_LOG_TAG_MSCHPROFILE;
p->hdr.fmt_num = ntoh16(p->hdr.fmt_num);
dhd_dbg_verboselog_printf(dhdp, &p->hdr, raw_event_ptr, p->data);
bzero(&hdr, sizeof(hdr));
hdr.tag = EVENT_LOG_TAG_MSCHPROFILE;
hdr.count = p->hdr.count + 1;
/* exclude LSB 2 bits which indicate binary/non-binary data */
hdr.fmt_num = ntoh16(p->hdr.fmt_num) >> 2;
hdr.fmt_num_raw = ntoh16(p->hdr.fmt_num);
if (ntoh16(p->hdr.fmt_num) == DHD_OW_BI_RAW_EVENT_LOG_FMT) {
hdr.binary_payload = TRUE;
}
dhd_dbg_verboselog_printf(dhdp, &hdr, raw_event_ptr, p->data, 0, 0);
} else {
msch_collect_tlv_t *p = (msch_collect_tlv_t *)log_ptr;
int type = ntoh16(p->type);
int len = ntoh16(p->size);
if (log_pyld_len < OFFSETOF(msch_collect_tlv_t, value) + len) {
return;
}
dhd_mschdbg_dump_data(dhdp, raw_event_ptr, type, p->value, len);
}
}

View File

@@ -1,16 +1,14 @@
/*
* DHD debugability header file
*
* <<Broadcom-WL-IPTag/Open:>>
* Copyright (C) 2020, Broadcom.
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -18,12 +16,11 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: dhd_mschdbg.h 571265 2015-07-14 20:50:18Z $
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_mschdbg.h 571265 2015-07-14 20:50:18Z eccopark $
*/
#ifndef _dhd_mschdbg_h_
@@ -32,8 +29,8 @@
#ifdef SHOW_LOGTRACE
extern void wl_mschdbg_event_handler(dhd_pub_t *dhdp, void *raw_event_ptr, int type,
void *data, int len);
extern void wl_mschdbg_verboselog_handler(dhd_pub_t *dhdp, void *raw_event_ptr, int tag,
uint32 *log_ptr);
extern void wl_mschdbg_verboselog_handler(dhd_pub_t *dhdp, void *raw_event_ptr,
prcd_event_log_hdr_t *plog_hdr, uint32 *log_ptr);
#endif /* SHOW_LOGTRACE */
#endif /* _dhd_mschdbg_h_ */

File diff suppressed because it is too large Load Diff

12438
drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c Normal file → Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,14 @@
/*
* Linux DHD Bus Module for PCIE
*
* Copyright (C) 1999-2017, Broadcom Corporation
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
@@ -16,23 +16,19 @@
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_pcie.h 707536 2017-06-28 04:23:48Z $
* $Id$
*/
#ifndef dhd_pcie_h
#define dhd_pcie_h
#include <bcmpcie.h>
#include <hnd_cons.h>
#include <dhd_linux.h>
#ifdef SUPPORT_LINKDOWN_RECOVERY
#ifdef CONFIG_ARCH_MSM
#ifdef CONFIG_PCI_MSM
@@ -41,35 +37,22 @@
#include <mach/msm_pcie.h>
#endif /* CONFIG_PCI_MSM */
#endif /* CONFIG_ARCH_MSM */
#ifdef EXYNOS_PCIE_LINKDOWN_RECOVERY
#if defined(CONFIG_SOC_EXYNOS8890) || defined(CONFIG_SOC_EXYNOS8895)
#ifdef CONFIG_ARCH_EXYNOS
#ifndef SUPPORT_EXYNOS7420
#include <linux/exynos-pci-noti.h>
extern int exynos_pcie_register_event(struct exynos_pcie_register_event *reg);
extern int exynos_pcie_deregister_event(struct exynos_pcie_register_event *reg);
#endif /* CONFIG_SOC_EXYNOS8890 || CONFIG_SOC_EXYNOS8895 */
#endif /* EXYNOS_PCIE_LINKDOWN_RECOVERY */
#endif /* !SUPPORT_EXYNOS7420 */
#endif /* CONFIG_ARCH_EXYNOS */
#endif /* SUPPORT_LINKDOWN_RECOVERY */
#ifdef DHD_PCIE_RUNTIMEPM
#include <linux/mutex.h>
#include <linux/wait.h>
#define DEFAULT_DHD_RUNTIME_MS 100
#ifndef CUSTOM_DHD_RUNTIME_MS
#define CUSTOM_DHD_RUNTIME_MS DEFAULT_DHD_RUNTIME_MS
#endif /* CUSTOM_DHD_RUNTIME_MS */
#ifndef MAX_IDLE_COUNT
#define MAX_IDLE_COUNT 16
#endif /* MAX_IDLE_COUNT */
#ifndef MAX_RESUME_WAIT
#define MAX_RESUME_WAIT 100
#endif /* MAX_RESUME_WAIT */
#endif /* DHD_PCIE_RUNTIMEPM */
/* defines */
#define PCIE_SHARED_VERSION PCIE_SHARED_VERSION_7
#define PCMSGBUF_HDRLEN 0
#define DONGLE_REG_MAP_SIZE (32 * 1024)
@@ -87,19 +70,19 @@ extern int exynos_pcie_deregister_event(struct exynos_pcie_register_event *reg);
#define struct_pcie_notify struct msm_pcie_notify
#define struct_pcie_register_event struct msm_pcie_register_event
#endif /* CONFIG_ARCH_MSM */
#ifdef EXYNOS_PCIE_LINKDOWN_RECOVERY
#if defined(CONFIG_SOC_EXYNOS8890) || defined(CONFIG_SOC_EXYNOS8895)
#ifdef CONFIG_ARCH_EXYNOS
#ifndef SUPPORT_EXYNOS7420
#define struct_pcie_notify struct exynos_pcie_notify
#define struct_pcie_register_event struct exynos_pcie_register_event
#endif /* CONFIG_SOC_EXYNOS8890 || CONFIG_SOC_EXYNOS8895 */
#endif /* EXYNOS_PCIE_LINKDOWN_RECOVERY */
#endif /* !SUPPORT_EXYNOS7420 */
#endif /* CONFIG_ARCH_EXYNOS */
#endif /* SUPPORT_LINKDOWN_RECOVERY */
#define MAX_DHD_TX_FLOWS 320
/* user defined data structures */
/* Device console log buffer state */
#define CONSOLE_LINE_MAX 192
#define CONSOLE_LINE_MAX 192u
#define CONSOLE_BUFFER_MAX (8 * 1024)
#ifdef IDLE_TX_FLOW_MGMT
@@ -115,18 +98,24 @@ extern int exynos_pcie_deregister_event(struct exynos_pcie_register_event *reg);
#endif /* DEVICE_TX_STUCK_DETECT */
/* implicit DMA for h2d wr and d2h rd indice from Host memory to TCM */
#define IDMA_ENAB(dhd) ((dhd)->idma_enable)
#define IDMA_ACTIVE(dhd) (((dhd)->idma_enable) && ((dhd)->idma_inited))
#define IDMA_ENAB(dhd) ((dhd) && (dhd)->idma_enable)
#define IDMA_ACTIVE(dhd) ((dhd) && ((dhd)->idma_enable) && ((dhd)->idma_inited))
#define IDMA_DS_ENAB(dhd) ((dhd)->idma_retention_ds)
#define IDMA_DS_ACTIVE(dhd) ((dhd)->bus->dongle_in_ds)
#define IDMA_CAPABLE(bus) (((bus)->sih->buscorerev == 19) || ((bus)->sih->buscorerev >= 23))
/* IFRM (Implicit Flow Ring Manager enable and inited */
#define IFRM_ENAB(dhd) ((dhd)->ifrm_enable)
#define IFRM_ACTIVE(dhd) (((dhd)->ifrm_enable) && ((dhd)->ifrm_inited))
#define IFRM_ENAB(dhd) ((dhd) && (dhd)->ifrm_enable)
#define IFRM_ACTIVE(dhd) ((dhd) && ((dhd)->ifrm_enable) && ((dhd)->ifrm_inited))
/* DAR registers use for h2d doorbell */
#define DAR_ENAB(dhd) ((dhd) && (dhd)->dar_enable)
#define DAR_ACTIVE(dhd) ((dhd) && ((dhd)->dar_enable) && ((dhd)->dar_inited))
/* DAR WAR for revs < 64 */
#define DAR_PWRREQ(bus) (((bus)->_dar_war) && DAR_ACTIVE((bus)->dhd))
/* PCIE CTO Prevention and Recovery */
#define PCIECTO_ENAB(dhd) ((dhd)->cto_enable)
#define PCIECTO_ENAB(bus) ((bus)->cto_enable)
/* Implicit DMA index usage :
* Index 0 for h2d write index transfer
@@ -136,6 +125,8 @@ extern int exynos_pcie_deregister_event(struct exynos_pcie_register_event *reg);
#define IDMA_IDX1 1
#define IDMA_IDX2 2
#define IDMA_IDX3 3
#define DMA_TYPE_SHIFT 4
#define DMA_TYPE_IDMA 1
#define DHDPCIE_CONFIG_HDR_SIZE 16
#define DHDPCIE_CONFIG_CHECK_DELAY_MS 10 /* 10ms */
@@ -157,8 +148,29 @@ typedef struct ring_sh_info {
uint32 ring_mem_addr;
uint32 ring_state_w;
uint32 ring_state_r;
pcie_hwa_db_index_t ring_hwa_db_idx; /* HWA DB index value per ring */
} ring_sh_info_t;
#define MAX_DS_TRACE_SIZE 50
#ifdef DHD_MMIO_TRACE
#define MAX_MMIO_TRACE_SIZE 256
/* Minimum of 250us should be elapsed to add new entry */
#define MIN_MMIO_TRACE_TIME 250
#define DHD_RING_IDX 0x00FF0000
typedef struct _dhd_mmio_trace_t {
uint64 timestamp;
uint32 addr;
uint32 value;
bool set;
} dhd_mmio_trace_t;
#endif /* defined(DHD_MMIO_TRACE) */
typedef struct _dhd_ds_trace_t {
uint64 timestamp;
bool d2h;
uint32 dsval;
#ifdef PCIE_INB_DW
enum dhd_bus_ds_state inbstate;
#endif /* PCIE_INB_DW */
} dhd_ds_trace_t;
#define DEVICE_WAKE_NONE 0
#define DEVICE_WAKE_OOB 1
@@ -168,6 +180,22 @@ typedef struct ring_sh_info {
#define OOB_DW_ENAB(bus) ((bus)->dw_option == DEVICE_WAKE_OOB)
#define NO_DW_ENAB(bus) ((bus)->dw_option == DEVICE_WAKE_NONE)
#define PCIE_PWR_REQ_RELOAD_WAR_ENAB(buscorerev) \
((buscorerev == 66) || (buscorerev == 67) || (buscorerev == 68) || \
(buscorerev == 70) || (buscorerev == 72))
#define PCIE_FASTLPO_ENABLED(buscorerev) \
((buscorerev == 66) || (buscorerev == 67) || (buscorerev == 68) || \
(buscorerev == 70) || (buscorerev == 72))
/*
* HW JIRA - CRWLPCIEGEN2-672
* Producer Index Feature which is used by F1 gets reset on F0 FLR
* fixed in REV68
*/
#define PCIE_ENUM_RESET_WAR_ENAB(buscorerev) \
((buscorerev == 66) || (buscorerev == 67))
struct dhd_bus;
struct dhd_pcie_rev {
@@ -206,14 +234,46 @@ typedef struct dhdpcie_config_save
uint32 bar1_win;
} dhdpcie_config_save_t;
/* The level of bus communication with the dongle */
enum dhd_bus_low_power_state {
DHD_BUS_NO_LOW_POWER_STATE, /* Not in low power state */
DHD_BUS_D3_INFORM_SENT, /* D3 INFORM sent */
DHD_BUS_D3_ACK_RECIEVED, /* D3 ACK recieved */
};
#ifdef DHD_FLOW_RING_STATUS_TRACE
#define FRS_TRACE_SIZE 32 /* frs - flow_ring_status */
typedef struct _dhd_flow_ring_status_trace_t {
uint64 timestamp;
uint16 h2d_ctrl_post_drd;
uint16 h2d_ctrl_post_dwr;
uint16 d2h_ctrl_cpln_drd;
uint16 d2h_ctrl_cpln_dwr;
uint16 h2d_rx_post_drd;
uint16 h2d_rx_post_dwr;
uint16 d2h_rx_cpln_drd;
uint16 d2h_rx_cpln_dwr;
uint16 d2h_tx_cpln_drd;
uint16 d2h_tx_cpln_dwr;
uint16 h2d_info_post_drd;
uint16 h2d_info_post_dwr;
uint16 d2h_info_cpln_drd;
uint16 d2h_info_cpln_dwr;
uint16 d2h_ring_edl_drd;
uint16 d2h_ring_edl_dwr;
} dhd_frs_trace_t;
#endif /* DHD_FLOW_RING_STATUS_TRACE */
/** Instantiated once for each hardware (dongle) instance that this DHD manages */
typedef struct dhd_bus {
dhd_pub_t *dhd;
dhd_pub_t *dhd; /**< pointer to per hardware (dongle) unique instance */
#if !defined(NDIS)
struct pci_dev *rc_dev; /* pci RC device handle */
struct pci_dev *dev; /* pci device handle */
#endif /* !defined(NDIS) */
#ifdef DHD_EFI
void *pcie_dev;
#endif
dll_t flowring_active_list; /* constructed list of tx flowring queues */
#ifdef IDLE_TX_FLOW_MGMT
uint64 active_list_last_process_ts;
@@ -234,16 +294,15 @@ typedef struct dhd_bus {
sbpcieregs_t *reg; /* Registers for PCIE core */
uint armrev; /* CPU core revision */
uint coreid; /* CPU core id */
uint ramrev; /* SOCRAM core revision */
uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */
uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
bool ramsize_adjusted; /* flag to note adjustment, so that
* adjustment routine and file io
* are avoided on D3 cold -> D0
*/
uint32 srmemsize; /* Size of SRMEM */
uint32 bus; /* gSPI or SDIO bus */
uint32 bus_num; /* bus number */
uint32 slot_num; /* slot ID */
uint32 intstatus; /* Intstatus bits (events) pending */
bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
bool fcstate; /* State of dongle flow-control */
@@ -255,6 +314,10 @@ typedef struct dhd_bus {
int processed_nvram_params_len; /* Modified len of NVRAM info */
#endif
#ifdef BCM_ROUTER_DHD
char *nvram_params; /* user specified nvram params. */
int nvram_params_len;
#endif /* BCM_ROUTER_DHD */
struct pktq txq; /* Queue length used for flow-control */
@@ -276,15 +339,24 @@ typedef struct dhd_bus {
*/
uint32 resetinstr;
uint32 dongle_ram_base;
uint32 next_tlv; /* Holds location of next available TLV */
ulong shared_addr;
pciedev_shared_t *pcie_sh;
bool bus_flowctrl;
uint32 dma_rxoffset;
volatile char *regs; /* pci device memory va */
volatile char *tcm; /* pci device memory va */
uint32 bar1_size; /* pci device memory size */
uint32 curr_bar1_win; /* current PCIEBar1Window setting */
osl_t *osh;
uint32 nvram_csm; /* Nvram checksum */
#ifdef BCMINTERNAL
bool msi_sim;
uchar *msi_sim_addr;
dmaaddr_t msi_sim_phys;
dhd_dma_buf_t hostfw_buf; /* Host offload firmware buffer */
uint32 hostfw_base; /* FW assumed base of host offload mem */
uint32 bp_base; /* adjusted bp base of host offload mem */
#endif /* BCMINTERNAL */
uint16 pollrate;
uint16 polltick;
@@ -310,6 +382,9 @@ typedef struct dhd_bus {
/* version 3 shared struct related info end */
uint32 def_intmask;
uint32 d2h_mb_mask;
uint32 pcie_mailbox_mask;
uint32 pcie_mailbox_int;
bool ltrsleep_on_unload;
uint wait_for_d3_ack;
uint16 max_tx_flowrings;
@@ -317,6 +392,7 @@ typedef struct dhd_bus {
uint16 max_completion_rings;
uint16 max_cmn_rings;
uint32 rw_index_sz;
uint32 hwa_db_index_sz;
bool db1_for_mb;
dhd_timeout_t doorbell_timer;
@@ -325,19 +401,19 @@ typedef struct dhd_bus {
bool oob_enabled;
#endif /* PCIE_OOB */
bool irq_registered;
bool d2h_intr_method;
#ifdef SUPPORT_LINKDOWN_RECOVERY
#if defined(CONFIG_ARCH_MSM) || (defined(EXYNOS_PCIE_LINKDOWN_RECOVERY) && \
defined(CONFIG_SOC_EXYNOS8890) || defined(CONFIG_SOC_EXYNOS8895))
#if defined(CONFIG_ARCH_MSM) || (defined(CONFIG_ARCH_EXYNOS) && \
!defined(SUPPORT_EXYNOS7420))
#ifdef CONFIG_ARCH_MSM
uint8 no_cfg_restore;
#endif /* CONFIG_ARCH_MSM */
struct_pcie_register_event pcie_event;
#endif /* CONFIG_ARCH_MSM || (EXYNOS_PCIE_LINKDOWN_RECOVERY &&
* (CONFIG_SOC_EXYNOS8890 || CONFIG_SOC_EXYNOS8895))
*/
#endif /* CONFIG_ARCH_MSM || CONFIG_ARCH_EXYNOS && !SUPPORT_EXYNOS7420 */
bool read_shm_fail;
#endif /* SUPPORT_LINKDOWN_RECOVERY */
int32 idletime; /* Control for activity timeout */
bool rpm_enabled;
#ifdef DHD_PCIE_RUNTIMEPM
int32 idlecount; /* Activity timeout counter */
int32 bus_wake; /* For wake up the bus */
@@ -350,18 +426,77 @@ typedef struct dhd_bus {
uint32 d0_inform_in_use_cnt;
uint8 force_suspend;
uint8 is_linkdown;
uint8 no_bus_init;
#ifdef IDLE_TX_FLOW_MGMT
bool enable_idle_flowring_mgmt;
#endif /* IDLE_TX_FLOW_MGMT */
struct dhd_pcie_rev api;
bool use_mailbox;
bool d3_suspend_pending;
bool use_d0_inform;
void *bus_lp_state_lock;
void *pwr_req_lock;
bool dongle_in_deepsleep;
void *dongle_ds_lock;
bool bar1_switch_enab;
void *bar1_switch_lock;
void *backplane_access_lock;
enum dhd_bus_low_power_state bus_low_power_state;
#ifdef DHD_FLOW_RING_STATUS_TRACE
dhd_frs_trace_t frs_isr_trace[FRS_TRACE_SIZE]; /* frs - flow_ring_status */
dhd_frs_trace_t frs_dpc_trace[FRS_TRACE_SIZE]; /* frs - flow_ring_status */
uint32 frs_isr_count;
uint32 frs_dpc_count;
#endif /* DHD_FLOW_RING_STATUS_TRACE */
#ifdef DHD_MMIO_TRACE
dhd_mmio_trace_t mmio_trace[MAX_MMIO_TRACE_SIZE];
uint32 mmio_trace_count;
#endif /* defined(DHD_MMIO_TRACE) */
dhd_ds_trace_t ds_trace[MAX_DS_TRACE_SIZE];
uint32 ds_trace_count;
uint32 hostready_count; /* Number of hostready issued */
#if defined(PCIE_OOB) || defined(BCMPCIE_OOB_HOST_WAKE)
#if defined(PCIE_OOB) || defined (BCMPCIE_OOB_HOST_WAKE)
bool oob_presuspend;
#endif /* PCIE_OOB || BCMPCIE_OOB_HOST_WAKE */
bool dongle_in_ds;
dhdpcie_config_save_t saved_config;
ulong resume_intr_enable_count;
ulong dpc_intr_enable_count;
ulong isr_intr_disable_count;
ulong suspend_intr_disable_count;
ulong dpc_return_busdown_count;
ulong non_ours_irq_count;
#ifdef BCMPCIE_OOB_HOST_WAKE
ulong oob_intr_count;
ulong oob_intr_enable_count;
ulong oob_intr_disable_count;
uint64 last_oob_irq_isr_time;
uint64 last_oob_irq_thr_time;
uint64 last_oob_irq_enable_time;
uint64 last_oob_irq_disable_time;
#endif /* BCMPCIE_OOB_HOST_WAKE */
uint64 isr_entry_time;
uint64 isr_exit_time;
uint64 isr_sched_dpc_time;
uint64 rpm_sched_dpc_time;
uint64 dpc_entry_time;
uint64 dpc_exit_time;
uint64 resched_dpc_time;
uint64 last_d3_inform_time;
uint64 last_process_ctrlbuf_time;
uint64 last_process_flowring_time;
uint64 last_process_txcpl_time;
uint64 last_process_rxcpl_time;
uint64 last_process_infocpl_time;
uint64 last_process_edl_time;
uint64 last_suspend_start_time;
uint64 last_suspend_end_time;
uint64 last_resume_start_time;
uint64 last_resume_end_time;
uint64 last_non_ours_irq_time;
bool hwa_enabled;
bool idma_enabled;
bool ifrm_enabled;
bool dar_enabled;
uint32 dmaxfer_complete;
uint8 dw_option;
#ifdef PCIE_INB_DW
bool inb_enabled;
@@ -377,23 +512,206 @@ typedef struct dhd_bus {
void *inb_lock; /* Lock to serialize in band device wake activity */
/* # of contexts in the host which currently want a FW transaction */
uint32 host_active_cnt;
bool skip_ds_ack; /* Skip DS-ACK during suspend in progress */
#endif /* PCIE_INB_DW */
dhdpcie_config_save_t saved_config;
ulong resume_intr_enable_count;
ulong dpc_intr_enable_count;
ulong isr_intr_disable_count;
ulong suspend_intr_disable_count;
ulong dpc_return_busdown_count;
bool idma_enabled;
bool ifrm_enabled;
#if defined(PCIE_OOB) || defined(PCIE_INB_DW)
bool ds_enabled;
#endif
#ifdef DHD_PCIE_RUNTIMEPM
bool chk_pm; /* To avoid counting of wake up from Runtime PM */
#endif /* DHD_PCIE_RUNTIMEPM */
#if defined(PCIE_INB_DW)
bool calc_ds_exit_latency;
bool deep_sleep; /* Indicates deep_sleep set or unset by the DHD IOVAR deep_sleep */
uint64 ds_exit_latency;
uint64 ds_exit_ts1;
uint64 ds_exit_ts2;
#endif /* PCIE_INB_DW */
bool _dar_war;
#ifdef GDB_PROXY
/* True if firmware loaded and backplane accessible */
bool gdb_proxy_access_enabled;
/* ID set by last "gdb_proxy_probe" iovar */
uint32 gdb_proxy_last_id;
/* True if firmware was started in bootloader mode */
bool gdb_proxy_bootloader_mode;
#endif /* GDB_PROXY */
uint8 dma_chan;
bool cto_enable; /* enable PCIE CTO Prevention and recovery */
uint32 cto_threshold; /* PCIE CTO timeout threshold */
bool cto_triggered; /* CTO is triggered */
bool intr_enabled; /* ready to receive interrupts from dongle */
int pwr_req_ref;
bool flr_force_fail; /* user intends to simulate flr force fail */
/* Information used to compose the memory map and to write the memory map,
* FW, and FW signature to dongle RAM.
* This information is used by the bootloader.
*/
uint32 ramtop_addr; /* Dongle address of unused space at top of RAM */
uint32 fw_download_addr; /* Dongle address of FW download */
uint32 fw_download_len; /* Length in bytes of FW download */
uint32 fwsig_download_addr; /* Dongle address of FW signature download */
uint32 fwsig_download_len; /* Length in bytes of FW signature download */
uint32 fwstat_download_addr; /* Dongle address of FWS status download */
uint32 fwstat_download_len; /* Length in bytes of FWS status download */
uint32 fw_memmap_download_addr; /* Dongle address of FWS memory-info download */
uint32 fw_memmap_download_len; /* Length in bytes of FWS memory-info download */
char fwsig_filename[DHD_FILENAME_MAX]; /* Name of FW signature file */
char bootloader_filename[DHD_FILENAME_MAX]; /* Name of bootloader image file */
uint32 bootloader_addr; /* Dongle address of bootloader download */
bool force_bt_quiesce; /* send bt_quiesce command to BT driver. */
bool rc_ep_aspm_cap; /* RC and EP ASPM capable */
bool rc_ep_l1ss_cap; /* EC and EP L1SS capable */
#if defined(DHD_H2D_LOG_TIME_SYNC)
ulong dhd_rte_time_sync_count; /* OSL_SYSUPTIME_US() */
#endif /* DHD_H2D_LOG_TIME_SYNC */
#ifdef D2H_MINIDUMP
bool d2h_minidump; /* This flag will be set if Host and FW handshake to collect minidump */
bool d2h_minidump_override; /* Force disable minidump through dhd IOVAR */
#endif /* D2H_MINIDUMP */
#ifdef BCMSLTGT
int xtalfreq; /* Xtal frequency used for htclkratio calculation */
uint32 ilp_tick; /* ILP ticks per second read from pmutimer */
uint32 xtal_ratio; /* xtal ticks per 4 ILP ticks read from pmu_xtalfreq */
#endif /* BCMSLTGT */
#ifdef BT_OVER_PCIE
/* whether the chip is in BT over PCIE mode or not */
bool btop_mode;
#endif /* BT_OVER_PCIE */
uint16 hp2p_txcpl_max_items;
uint16 hp2p_rxcpl_max_items;
/* PCIE coherent status */
uint32 coherent_state;
uint32 inb_dw_deassert_cnt;
uint64 arm_oor_time;
uint64 rd_shared_pass_time;
uint32 hwa_mem_base;
uint32 hwa_mem_size;
} dhd_bus_t;
#ifdef DHD_MSI_SUPPORT
extern uint enable_msi;
#endif /* DHD_MSI_SUPPORT */
enum {
PCIE_INTX = 0,
PCIE_MSI = 1
};
static INLINE bool
__dhd_check_bus_in_lps(dhd_bus_t *bus)
{
bool ret = (bus->bus_low_power_state == DHD_BUS_D3_INFORM_SENT) ||
(bus->bus_low_power_state == DHD_BUS_D3_ACK_RECIEVED);
return ret;
}
static INLINE bool
dhd_check_bus_in_lps(dhd_bus_t *bus)
{
unsigned long flags_bus;
bool ret;
DHD_BUS_LP_STATE_LOCK(bus->bus_lp_state_lock, flags_bus);
ret = __dhd_check_bus_in_lps(bus);
DHD_BUS_LP_STATE_UNLOCK(bus->bus_lp_state_lock, flags_bus);
return ret;
}
static INLINE bool
__dhd_check_bus_lps_d3_acked(dhd_bus_t *bus)
{
bool ret = (bus->bus_low_power_state == DHD_BUS_D3_ACK_RECIEVED);
return ret;
}
static INLINE bool
dhd_check_bus_lps_d3_acked(dhd_bus_t *bus)
{
unsigned long flags_bus;
bool ret;
DHD_BUS_LP_STATE_LOCK(bus->bus_lp_state_lock, flags_bus);
ret = __dhd_check_bus_lps_d3_acked(bus);
DHD_BUS_LP_STATE_UNLOCK(bus->bus_lp_state_lock, flags_bus);
return ret;
}
static INLINE void
__dhd_set_bus_not_in_lps(dhd_bus_t *bus)
{
bus->bus_low_power_state = DHD_BUS_NO_LOW_POWER_STATE;
return;
}
static INLINE void
dhd_set_bus_not_in_lps(dhd_bus_t *bus)
{
unsigned long flags_bus;
DHD_BUS_LP_STATE_LOCK(bus->bus_lp_state_lock, flags_bus);
__dhd_set_bus_not_in_lps(bus);
DHD_BUS_LP_STATE_UNLOCK(bus->bus_lp_state_lock, flags_bus);
return;
}
static INLINE void
__dhd_set_bus_lps_d3_informed(dhd_bus_t *bus)
{
bus->bus_low_power_state = DHD_BUS_D3_INFORM_SENT;
return;
}
static INLINE void
dhd_set_bus_lps_d3_informed(dhd_bus_t *bus)
{
unsigned long flags_bus;
DHD_BUS_LP_STATE_LOCK(bus->bus_lp_state_lock, flags_bus);
__dhd_set_bus_lps_d3_informed(bus);
DHD_BUS_LP_STATE_UNLOCK(bus->bus_lp_state_lock, flags_bus);
return;
}
static INLINE void
__dhd_set_bus_lps_d3_acked(dhd_bus_t *bus)
{
bus->bus_low_power_state = DHD_BUS_D3_ACK_RECIEVED;
return;
}
static INLINE void
dhd_set_bus_lps_d3_acked(dhd_bus_t *bus)
{
unsigned long flags_bus;
DHD_BUS_LP_STATE_LOCK(bus->bus_lp_state_lock, flags_bus);
__dhd_set_bus_lps_d3_acked(bus);
DHD_BUS_LP_STATE_UNLOCK(bus->bus_lp_state_lock, flags_bus);
return;
}
/* check routines */
#define DHD_CHK_BUS_IN_LPS(bus) dhd_check_bus_in_lps(bus)
#define __DHD_CHK_BUS_IN_LPS(bus) __dhd_check_bus_in_lps(bus)
#define DHD_CHK_BUS_NOT_IN_LPS(bus) !(DHD_CHK_BUS_IN_LPS(bus))
#define __DHD_CHK_BUS_NOT_IN_LPS(bus) !(__DHD_CHK_BUS_IN_LPS(bus))
#define DHD_CHK_BUS_LPS_D3_INFORMED(bus) DHD_CHK_BUS_IN_LPS(bus)
#define __DHD_CHK_BUS_LPS_D3_INFORMED(bus) __DHD_CHK_BUS_IN_LPS(bus)
#define DHD_CHK_BUS_LPS_D3_ACKED(bus) dhd_check_bus_lps_d3_acked(bus)
#define __DHD_CHK_BUS_LPS_D3_ACKED(bus) __dhd_check_bus_lps_d3_acked(bus)
/* set routines */
#define DHD_SET_BUS_NOT_IN_LPS(bus) dhd_set_bus_not_in_lps(bus)
#define __DHD_SET_BUS_NOT_IN_LPS(bus) __dhd_set_bus_not_in_lps(bus)
#define DHD_SET_BUS_LPS_D3_INFORMED(bus) dhd_set_bus_lps_d3_informed(bus)
#define __DHD_SET_BUS_LPS_D3_INFORMED(bus) __dhd_set_bus_lps_d3_informed(bus)
#define DHD_SET_BUS_LPS_D3_ACKED(bus) dhd_set_bus_lps_d3_acked(bus)
#define __DHD_SET_BUS_LPS_D3_ACKED(bus) __dhd_set_bus_lps_d3_acked(bus)
/* function declarations */
extern uint32* dhdpcie_bus_reg_map(osl_t *osh, ulong addr, int size);
@@ -401,8 +719,8 @@ extern int dhdpcie_bus_register(void);
extern void dhdpcie_bus_unregister(void);
extern bool dhdpcie_chipmatch(uint16 vendor, uint16 device);
extern struct dhd_bus* dhdpcie_bus_attach(osl_t *osh,
volatile char *regs, volatile char *tcm, void *pci_dev);
extern int dhdpcie_bus_attach(osl_t *osh, dhd_bus_t **bus_ptr,
volatile char *regs, volatile char *tcm, void *pci_dev, wifi_adapter_info_t *adapter);
extern uint32 dhdpcie_bus_cfg_read_dword(struct dhd_bus *bus, uint32 addr, uint32 size);
extern void dhdpcie_bus_cfg_write_dword(struct dhd_bus *bus, uint32 addr, uint32 size, uint32 data);
extern void dhdpcie_bus_intr_enable(struct dhd_bus *bus);
@@ -413,7 +731,14 @@ extern int32 dhdpcie_bus_isr(struct dhd_bus *bus);
extern void dhdpcie_free_irq(dhd_bus_t *bus);
extern void dhdpcie_bus_ringbell_fast(struct dhd_bus *bus, uint32 value);
extern void dhdpcie_bus_ringbell_2_fast(struct dhd_bus *bus, uint32 value, bool devwake);
extern void dhdpcie_dongle_reset(dhd_bus_t *bus);
extern int dhd_bus_cfg_sprom_ctrl_bp_reset(struct dhd_bus *bus);
extern int dhd_bus_cfg_ss_ctrl_bp_reset(struct dhd_bus *bus);
#ifdef DHD_PCIE_NATIVE_RUNTIMEPM
extern int dhdpcie_bus_suspend(struct dhd_bus *bus, bool state, bool byint);
#else
extern int dhdpcie_bus_suspend(struct dhd_bus *bus, bool state);
#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
extern int dhdpcie_pci_suspend_resume(struct dhd_bus *bus, bool state);
extern uint32 dhdpcie_force_alp(struct dhd_bus *bus, bool enable);
extern uint32 dhdpcie_set_l1_entry_time(struct dhd_bus *bus, int force_l1_entry_time);
@@ -426,51 +751,92 @@ extern uint8 dhdpcie_clkreq(osl_t *osh, uint32 mask, uint32 val);
extern int dhdpcie_disable_irq(dhd_bus_t *bus);
extern int dhdpcie_disable_irq_nosync(dhd_bus_t *bus);
extern int dhdpcie_enable_irq(dhd_bus_t *bus);
extern void dhd_bus_dump_dar_registers(struct dhd_bus *bus);
#if defined(linux) || defined(LINUX)
extern uint32 dhdpcie_rc_config_read(dhd_bus_t *bus, uint offset);
extern uint32 dhdpcie_rc_access_cap(dhd_bus_t *bus, int cap, uint offset, bool is_ext,
bool is_write, uint32 writeval);
extern uint32 dhdpcie_ep_access_cap(dhd_bus_t *bus, int cap, uint offset, bool is_ext,
bool is_write, uint32 writeval);
extern uint32 dhd_debug_get_rc_linkcap(dhd_bus_t *bus);
extern int dhdpcie_start_host_pcieclock(dhd_bus_t *bus);
extern int dhdpcie_stop_host_pcieclock(dhd_bus_t *bus);
#else
static INLINE uint32 dhdpcie_rc_config_read(dhd_bus_t *bus, uint offset) { return 0;}
static INLINE uint32 dhdpcie_rc_access_cap(dhd_bus_t *bus, int cap, uint offset, bool is_ext,
bool is_write, uint32 writeval) { return -1;}
static INLINE uint32 dhdpcie_ep_access_cap(dhd_bus_t *bus, int cap, uint offset, bool is_ext,
bool is_write, uint32 writeval) { return -1;}
static INLINE uint32 dhd_debug_get_rc_linkcap(dhd_bus_t *bus) { return -1;}
#endif
#if defined(linux) || defined(LINUX)
extern int dhdpcie_start_host_dev(dhd_bus_t *bus);
extern int dhdpcie_stop_host_dev(dhd_bus_t *bus);
extern int dhdpcie_disable_device(dhd_bus_t *bus);
extern int dhdpcie_alloc_resource(dhd_bus_t *bus);
extern void dhdpcie_free_resource(dhd_bus_t *bus);
extern void dhdpcie_dump_resource(dhd_bus_t *bus);
extern int dhdpcie_bus_request_irq(struct dhd_bus *bus);
void dhdpcie_os_setbar1win(dhd_bus_t *bus, uint32 addr);
void dhdpcie_os_wtcm8(dhd_bus_t *bus, ulong offset, uint8 data);
uint8 dhdpcie_os_rtcm8(dhd_bus_t *bus, ulong offset);
void dhdpcie_os_wtcm16(dhd_bus_t *bus, ulong offset, uint16 data);
uint16 dhdpcie_os_rtcm16(dhd_bus_t *bus, ulong offset);
void dhdpcie_os_wtcm32(dhd_bus_t *bus, ulong offset, uint32 data);
uint32 dhdpcie_os_rtcm32(dhd_bus_t *bus, ulong offset);
#ifdef DHD_SUPPORT_64BIT
void dhdpcie_os_wtcm64(dhd_bus_t *bus, ulong offset, uint64 data);
uint64 dhdpcie_os_rtcm64(dhd_bus_t *bus, ulong offset);
#endif
#endif /* LINUX || linux */
#if defined(linux) || defined(LINUX) || defined(DHD_EFI)
extern int dhdpcie_enable_device(dhd_bus_t *bus);
#endif
#ifdef BCMPCIE_OOB_HOST_WAKE
extern int dhdpcie_oob_intr_register(dhd_bus_t *bus);
extern void dhdpcie_oob_intr_unregister(dhd_bus_t *bus);
extern void dhdpcie_oob_intr_set(dhd_bus_t *bus, bool enable);
extern int dhdpcie_get_oob_irq_num(struct dhd_bus *bus);
extern int dhdpcie_get_oob_irq_status(struct dhd_bus *bus);
extern int dhdpcie_get_oob_irq_level(void);
#endif /* BCMPCIE_OOB_HOST_WAKE */
#ifdef PCIE_OOB
extern void dhd_oob_set_bt_reg_on(struct dhd_bus *bus, bool val);
extern int dhd_oob_get_bt_reg_on(struct dhd_bus *bus);
extern void dhdpcie_oob_init(dhd_bus_t *bus);
extern void dhd_bus_doorbell_timeout_reset(struct dhd_bus *bus);
extern int dhd_os_oob_set_device_wake(struct dhd_bus *bus, bool val);
extern void dhd_os_ib_set_device_wake(struct dhd_bus *bus, bool val);
#endif /* PCIE_OOB */
#if defined(PCIE_OOB) || defined(PCIE_INB_DW)
extern void dhd_bus_doorbell_timeout_reset(struct dhd_bus *bus);
#endif /* defined(PCIE_OOB) || defined(PCIE_INB_DW) */
#if defined(linux) || defined(LINUX)
/* XXX: SWWLAN-82173 Making PCIe RC D3cold by force during system PM
* exynos_pcie_pm_suspend : RC goes to suspend status & assert PERST
* exynos_pcie_pm_resume : de-assert PERST & RC goes to resume status
*/
#if defined(CONFIG_ARCH_EXYNOS)
#define SAMSUNG_PCIE_VENDOR_ID 0x144d
#if defined(CONFIG_MACH_UNIVERSAL5433)
#define SAMSUNG_PCIE_DEVICE_ID 0xa5e3
#define SAMSUNG_PCIE_CH_NUM
#elif defined(CONFIG_MACH_UNIVERSAL7420)
#define SAMSUNG_PCIE_DEVICE_ID 0xa575
#define SAMSUNG_PCIE_CH_NUM 1
#define EXYNOS_PCIE_VENDOR_ID 0x144d
#if defined(CONFIG_MACH_UNIVERSAL7420) || defined(CONFIG_SOC_EXYNOS7420)
#define EXYNOS_PCIE_DEVICE_ID 0xa575
#define EXYNOS_PCIE_CH_NUM 1
#elif defined(CONFIG_SOC_EXYNOS8890)
#define SAMSUNG_PCIE_DEVICE_ID 0xa544
#define SAMSUNG_PCIE_CH_NUM 0
#elif defined(CONFIG_SOC_EXYNOS7420)
#define SAMSUNG_PCIE_DEVICE_ID 0xa575
#define SAMSUNG_PCIE_CH_NUM 1
#elif defined(CONFIG_SOC_EXYNOS8895)
#define SAMSUNG_PCIE_DEVICE_ID 0xecec
#define SAMSUNG_PCIE_CH_NUM 0
#define EXYNOS_PCIE_DEVICE_ID 0xa544
#define EXYNOS_PCIE_CH_NUM 0
#elif defined(CONFIG_SOC_EXYNOS8895) || defined(CONFIG_SOC_EXYNOS9810) || \
defined(CONFIG_SOC_EXYNOS9820) || defined(CONFIG_SOC_EXYNOS9830) || \
defined(CONFIG_SOC_EXYNOS2100) || defined(CONFIG_SOC_EXYNOS1000) || \
defined(CONFIG_SOC_GS101)
#define EXYNOS_PCIE_DEVICE_ID 0xecec
#define EXYNOS_PCIE_CH_NUM 0
#else
#error "Not supported platform"
#endif /* CONFIG_SOC_EXYNOSXXXX & CONFIG_MACH_UNIVERSALXXXX */
extern void exynos_pcie_pm_suspend(int ch_num);
extern void exynos_pcie_pm_resume(int ch_num);
#endif /* CONFIG_ARCH_EXYNOS */
#if defined(CONFIG_ARCH_MSM)
@@ -483,6 +849,9 @@ extern void dhd_os_ib_set_device_wake(struct dhd_bus *bus, bool val);
#define MSM_PCIE_DEVICE_ID 0x0104
#elif defined(CONFIG_ARCH_MSM8998)
#define MSM_PCIE_DEVICE_ID 0x0105
#elif defined(CONFIG_ARCH_SDM845) || defined(CONFIG_ARCH_SM8150) || \
defined(CONFIG_ARCH_KONA) || defined(CONFIG_ARCH_LAHAINA)
#define MSM_PCIE_DEVICE_ID 0x0106
#else
#error "Not supported platform"
#endif
@@ -498,9 +867,17 @@ extern void dhd_os_ib_set_device_wake(struct dhd_bus *bus, bool val);
#define TEGRA_PCIE_DEVICE_ID 0x4347
#endif /* CONFIG_ARCH_TEGRA */
#if defined(BOARD_HIKEY)
#define HIKEY_PCIE_VENDOR_ID 0x19e5
#define HIKEY_PCIE_DEVICE_ID 0x3660
#endif /* BOARD_HIKEY */
#define DUMMY_PCIE_VENDOR_ID 0xffff
#define DUMMY_PCIE_DEVICE_ID 0xffff
#if defined(CONFIG_ARCH_EXYNOS)
#define PCIE_RC_VENDOR_ID SAMSUNG_PCIE_VENDOR_ID
#define PCIE_RC_DEVICE_ID SAMSUNG_PCIE_DEVICE_ID
#define PCIE_RC_VENDOR_ID EXYNOS_PCIE_VENDOR_ID
#define PCIE_RC_DEVICE_ID EXYNOS_PCIE_DEVICE_ID
#elif defined(CONFIG_ARCH_MSM)
#define PCIE_RC_VENDOR_ID MSM_PCIE_VENDOR_ID
#define PCIE_RC_DEVICE_ID MSM_PCIE_DEVICE_ID
@@ -510,17 +887,18 @@ extern void dhd_os_ib_set_device_wake(struct dhd_bus *bus, bool val);
#elif defined(CONFIG_ARCH_TEGRA)
#define PCIE_RC_VENDOR_ID TEGRA_PCIE_VENDOR_ID
#define PCIE_RC_DEVICE_ID TEGRA_PCIE_DEVICE_ID
#endif /* CONFIG_ARCH_EXYNOS */
#ifdef USE_EXYNOS_PCIE_RC_PMPATCH
#ifdef CONFIG_MACH_UNIVERSAL5433
extern int exynos_pcie_pm_suspend(void);
extern int exynos_pcie_pm_resume(void);
#elif defined(BOARD_HIKEY)
#define PCIE_RC_VENDOR_ID HIKEY_PCIE_VENDOR_ID
#define PCIE_RC_DEVICE_ID HIKEY_PCIE_DEVICE_ID
#else
extern int exynos_pcie_pm_suspend(int ch_num);
extern int exynos_pcie_pm_resume(int ch_num);
#endif /* CONFIG_MACH_UNIVERSAL5433 */
#endif /* USE_EXYNOS_PCIE_RC_PMPATCH */
/* Use dummy vendor and device IDs */
#define PCIE_RC_VENDOR_ID DUMMY_PCIE_VENDOR_ID
#define PCIE_RC_DEVICE_ID DUMMY_PCIE_DEVICE_ID
#endif /* CONFIG_ARCH_EXYNOS */
#endif /* linux || LINUX */
#define DHD_REGULAR_RING 0
#define DHD_HP2P_RING 1
#ifdef CONFIG_ARCH_TEGRA
extern int tegra_pcie_pm_suspend(void);
@@ -549,6 +927,10 @@ extern int dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data);
int bcmpcie_get_total_wake(struct dhd_bus *bus);
int bcmpcie_set_get_wake(struct dhd_bus *bus, int flag);
#endif /* DHD_WAKE_STATUS */
#ifdef DHD_MMIO_TRACE
extern void dhd_dump_bus_mmio_trace(dhd_bus_t *bus, struct bcmstrbuf *strbuf);
#endif /* defined(DHD_MMIO_TRACE) */
extern void dhd_dump_bus_ds_trace(dhd_bus_t *bus, struct bcmstrbuf *strbuf);
extern bool dhdpcie_bus_get_pcie_hostready_supported(dhd_bus_t *bus);
extern void dhd_bus_hostready(struct dhd_bus *bus);
#ifdef PCIE_OOB
@@ -565,43 +947,96 @@ extern int dhd_bus_inb_set_device_wake(struct dhd_bus *bus, bool val);
extern void dhd_bus_inb_ack_pending_ds_req(dhd_bus_t *bus);
#endif /* PCIE_INB_DW */
extern void dhdpcie_bus_enab_pcie_dw(dhd_bus_t *bus, uint8 dw_option);
extern bool dhdpcie_irq_enabled(struct dhd_bus *bus);
extern bool dhdpcie_bus_get_pcie_idma_supported(dhd_bus_t *bus);
extern bool dhdpcie_bus_get_pcie_ifrm_supported(dhd_bus_t *bus);
static INLINE uint32
dhd_pcie_config_read(osl_t *osh, uint offset, uint size)
{
OSL_DELAY(100);
return OSL_PCI_READ_CONFIG(osh, offset, size);
}
static INLINE uint32
dhd_pcie_corereg_read(si_t *sih, uint val)
{
OSL_DELAY(100);
si_corereg(sih, sih->buscoreidx, OFFSETOF(sbpcieregs_t, configaddr), ~0, val);
return si_corereg(sih, sih->buscoreidx, OFFSETOF(sbpcieregs_t, configdata), 0, 0);
}
#ifdef DHD_SSSR_DUMP
extern int dhdpcie_sssr_dump(dhd_pub_t *dhd);
#endif /* DHD_SSSR_DUMP */
#if defined(LINUX) || defined(linux)
extern int dhdpcie_irq_disabled(struct dhd_bus *bus);
extern int dhdpcie_set_master_and_d0_pwrstate(struct dhd_bus *bus);
#else
static INLINE bool dhdpcie_irq_disabled(struct dhd_bus *bus) { return BCME_ERROR;}
static INLINE int dhdpcie_set_master_and_d0_pwrstate(struct dhd_bus *bus)
{ return BCME_ERROR;}
#endif /* defined(LINUX) || defined(linux) */
#ifdef DHD_EFI
extern int dhd_os_wifi_platform_set_power(uint32 value);
int dhd_control_signal(dhd_bus_t *bus, char *arg, int set);
extern int dhd_wifi_properties(struct dhd_bus *bus, char *arg);
extern bool dhdpcie_is_arm_halted(struct dhd_bus *bus);
extern int dhd_os_wifi_platform_set_power(uint32 value);
extern void dhdpcie_dongle_pwr_toggle(dhd_bus_t *bus);
extern int dhd_otp_dump(dhd_bus_t *bus, char *arg);
void dhdpcie_dongle_flr_or_pwr_toggle(dhd_bus_t *bus);
int dhd_control_signal(dhd_bus_t *bus, char *arg, int len, int set);
extern int dhd_wifi_properties(struct dhd_bus *bus, char *arg, int len);
extern int dhd_otp_dump(dhd_bus_t *bus, char *arg, int len);
extern int dhdpcie_deinit_phase1(dhd_bus_t *bus);
int dhdpcie_disable_intr_poll(dhd_bus_t *bus);
int dhdpcie_enable_intr_poll(dhd_bus_t *bus);
#ifdef BT_OVER_PCIE
int dhd_btop_test(dhd_bus_t *bus, char *arg, int len);
#endif /* BT_OVER_PCIE */
#else
static INLINE int dhd_os_wifi_platform_set_power(uint32 value) {return BCME_OK; }
static INLINE bool dhdpcie_is_arm_halted(struct dhd_bus *bus) {return TRUE;}
static INLINE int dhd_os_wifi_platform_set_power(uint32 value) {return BCME_OK; }
static INLINE void
dhdpcie_dongle_flr_or_pwr_toggle(dhd_bus_t *bus)
{ return; }
#endif /* DHD_EFI */
int dhdpcie_config_check(dhd_bus_t *bus);
int dhdpcie_config_restore(dhd_bus_t *bus, bool restore_pmcsr);
int dhdpcie_config_save(dhd_bus_t *bus);
int dhdpcie_set_pwr_state(dhd_bus_t *bus, uint state);
extern bool dhdpcie_bus_get_pcie_hwa_supported(dhd_bus_t *bus);
extern bool dhdpcie_bus_get_pcie_idma_supported(dhd_bus_t *bus);
extern bool dhdpcie_bus_get_pcie_ifrm_supported(dhd_bus_t *bus);
extern bool dhdpcie_bus_get_pcie_dar_supported(dhd_bus_t *bus);
extern bool dhdpcie_bus_get_hp2p_supported(dhd_bus_t *bus);
static INLINE uint32
dhd_pcie_config_read(dhd_bus_t *bus, uint offset, uint size)
{
/* For 4375 or prior chips to 4375 */
if (bus->sih && bus->sih->buscorerev <= 64) {
OSL_DELAY(100);
}
return OSL_PCI_READ_CONFIG(bus->osh, offset, size);
}
static INLINE uint32
dhd_pcie_corereg_read(si_t *sih, uint val)
{
/* For 4375 or prior chips to 4375 */
if (sih->buscorerev <= 64) {
OSL_DELAY(100);
}
si_corereg(sih, sih->buscoreidx, OFFSETOF(sbpcieregs_t, configaddr), ~0, val);
return si_corereg(sih, sih->buscoreidx, OFFSETOF(sbpcieregs_t, configdata), 0, 0);
}
extern int dhdpcie_get_fwpath_otp(dhd_bus_t *bus, char *fw_path, char *nv_path,
char *clm_path, char *txcap_path);
extern int dhd_pcie_debug_info_dump(dhd_pub_t *dhd);
extern void dhd_pcie_intr_count_dump(dhd_pub_t *dhd);
extern void dhdpcie_bus_clear_intstatus(dhd_bus_t *bus);
#ifdef DHD_HP2P
extern uint16 dhd_bus_get_hp2p_ring_max_size(dhd_bus_t *bus, bool tx);
#endif
#if defined(DHD_EFI)
extern wifi_properties_t *dhd_get_props(dhd_bus_t *bus);
#endif
#if defined(DHD_EFI) || defined(NDIS)
extern int dhd_get_platform(dhd_pub_t* dhd, char *progname);
extern bool dhdpcie_is_chip_supported(uint32 chipid, int *idx);
extern bool dhdpcie_is_sflash_chip(uint32 chipid);
#endif
extern int dhd_get_pcie_linkspeed(dhd_pub_t *dhd);
extern void dhdpcie_bar1_window_switch_enab(dhd_bus_t *bus);
#ifdef PCIE_INB_DW
extern void dhdpcie_set_dongle_deepsleep(dhd_bus_t *bus, bool val);
extern void dhd_init_dongle_ds_lock(dhd_bus_t *bus);
extern void dhd_deinit_dongle_ds_lock(dhd_bus_t *bus);
#endif /* PCIE_INB_DW */
#endif /* dhd_pcie_h */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,311 @@
/*
* DHD debugability packet logging header file
*
* Copyright (C) 2020, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id$
*/
#ifndef __DHD_PKTLOG_H_
#define __DHD_PKTLOG_H_
#include <dhd_debug.h>
#include <dhd.h>
#include <asm/atomic.h>
#ifdef DHD_COMPACT_PKT_LOG
#include <linux/rbtree.h>
#endif /* DHD_COMPACT_PKT_LOG */
#ifdef DHD_PKT_LOGGING
#define DHD_PKT_LOG(args) DHD_INFO(args)
#define DEFAULT_MULTIPLE_PKTLOG_BUF 1
#ifndef CUSTOM_MULTIPLE_PKTLOG_BUF
#define CUSTOM_MULTIPLE_PKTLOG_BUF DEFAULT_MULTIPLE_PKTLOG_BUF
#endif /* CUSTOM_MULTIPLE_PKTLOG_BUF */
#define MIN_PKTLOG_LEN (32 * 10 * 2 * CUSTOM_MULTIPLE_PKTLOG_BUF)
#define MAX_PKTLOG_LEN (32 * 10 * 2 * 10)
#define MAX_DHD_PKTLOG_FILTER_LEN 14
#define MAX_MASK_PATTERN_FILTER_LEN 64
#define PKTLOG_TXPKT_CASE 0x0001
#define PKTLOG_TXSTATUS_CASE 0x0002
#define PKTLOG_RXPKT_CASE 0x0004
/* MAX_FILTER_PATTERN_LEN is buf len to print bitmask/pattern with string */
#define MAX_FILTER_PATTERN_LEN \
((MAX_MASK_PATTERN_FILTER_LEN * HD_BYTE_SIZE) + HD_PREFIX_SIZE + 1) * 2
#define PKTLOG_DUMP_BUF_SIZE (64 * 1024)
typedef struct dhd_dbg_pktlog_info {
frame_type payload_type;
size_t pkt_len;
uint32 driver_ts_sec;
uint32 driver_ts_usec;
uint32 firmware_ts;
uint32 pkt_hash;
bool direction;
void *pkt;
} dhd_dbg_pktlog_info_t;
typedef struct dhd_pktlog_ring_info
{
dll_t p_info; /* list pointer */
union {
wifi_tx_packet_fate tx_fate;
wifi_rx_packet_fate rx_fate;
uint32 fate;
};
dhd_dbg_pktlog_info_t info;
} dhd_pktlog_ring_info_t;
typedef struct dhd_pktlog_ring
{
dll_t ring_info_head; /* ring_info list */
dll_t ring_info_free; /* ring_info free list */
osl_atomic_t start;
uint32 pktlog_minmize;
uint32 pktlog_len; /* size of pkts */
uint32 pktcount;
spinlock_t *pktlog_ring_lock;
dhd_pub_t *dhdp;
dhd_pktlog_ring_info_t *ring_info_mem; /* ring_info mem pointer */
} dhd_pktlog_ring_t;
typedef struct dhd_pktlog_filter_info
{
uint32 id;
uint32 offset;
uint32 size_bytes; /* Size of pattern. */
uint32 enable;
uint8 mask[MAX_MASK_PATTERN_FILTER_LEN];
uint8 pattern[MAX_MASK_PATTERN_FILTER_LEN];
} dhd_pktlog_filter_info_t;
typedef struct dhd_pktlog_filter
{
dhd_pktlog_filter_info_t *info;
uint32 list_cnt;
uint32 enable;
} dhd_pktlog_filter_t;
typedef struct dhd_pktlog
{
struct dhd_pktlog_ring *pktlog_ring;
struct dhd_pktlog_filter *pktlog_filter;
osl_atomic_t pktlog_status;
dhd_pub_t *dhdp;
#ifdef DHD_COMPACT_PKT_LOG
struct rb_root cpkt_log_tt_rbt;
#endif /* DHD_COMPACT_PKT_LOG */
} dhd_pktlog_t;
typedef struct dhd_pktlog_pcap_hdr
{
uint32 magic_number;
uint16 version_major;
uint16 version_minor;
uint16 thiszone;
uint32 sigfigs;
uint32 snaplen;
uint32 network;
} dhd_pktlog_pcap_hdr_t;
#define PKTLOG_PCAP_MAGIC_NUM 0xa1b2c3d4
#define PKTLOG_PCAP_MAJOR_VER 0x02
#define PKTLOG_PCAP_MINOR_VER 0x04
#define PKTLOG_PCAP_SNAP_LEN 0x40000
#define PKTLOG_PCAP_NETWORK_TYPE 147
extern int dhd_os_attach_pktlog(dhd_pub_t *dhdp);
extern int dhd_os_detach_pktlog(dhd_pub_t *dhdp);
extern dhd_pktlog_ring_t* dhd_pktlog_ring_init(dhd_pub_t *dhdp, int size);
extern int dhd_pktlog_ring_deinit(dhd_pub_t *dhdp, dhd_pktlog_ring_t *ring);
extern int dhd_pktlog_ring_set_nextpos(dhd_pktlog_ring_t *ringbuf);
extern int dhd_pktlog_ring_get_nextbuf(dhd_pktlog_ring_t *ringbuf, void **data);
extern int dhd_pktlog_ring_set_prevpos(dhd_pktlog_ring_t *ringbuf);
extern int dhd_pktlog_ring_get_prevbuf(dhd_pktlog_ring_t *ringbuf, void **data);
extern int dhd_pktlog_ring_get_writebuf(dhd_pktlog_ring_t *ringbuf, void **data);
extern int dhd_pktlog_ring_add_pkts(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pktid,
uint32 direction);
extern int dhd_pktlog_ring_tx_status(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pktid,
uint16 status);
extern dhd_pktlog_ring_t* dhd_pktlog_ring_change_size(dhd_pktlog_ring_t *ringbuf, int size);
extern void dhd_pktlog_filter_pull_forward(dhd_pktlog_filter_t *filter,
uint32 del_filter_id, uint32 list_cnt);
#define PKT_RX 0
#define PKT_TX 1
#define PKT_WAKERX 2
#define DHD_INVALID_PKTID (0U)
#define PKTLOG_TRANS_TX 0x01
#define PKTLOG_TRANS_RX 0x02
#define PKTLOG_TRANS_TXS 0x04
#define PKTLOG_SET_IN_TX(dhdp) \
{ \
do { \
OSL_ATOMIC_OR((dhdp)->osh, &(dhdp)->pktlog->pktlog_status, PKTLOG_TRANS_TX); \
} while (0); \
}
#define PKTLOG_SET_IN_RX(dhdp) \
{ \
do { \
OSL_ATOMIC_OR((dhdp)->osh, &(dhdp)->pktlog->pktlog_status, PKTLOG_TRANS_RX); \
} while (0); \
}
#define PKTLOG_SET_IN_TXS(dhdp) \
{ \
do { \
OSL_ATOMIC_OR((dhdp)->osh, &(dhdp)->pktlog->pktlog_status, PKTLOG_TRANS_TXS); \
} while (0); \
}
#define PKTLOG_CLEAR_IN_TX(dhdp) \
{ \
do { \
OSL_ATOMIC_AND((dhdp)->osh, &(dhdp)->pktlog->pktlog_status, ~PKTLOG_TRANS_TX); \
} while (0); \
}
#define PKTLOG_CLEAR_IN_RX(dhdp) \
{ \
do { \
OSL_ATOMIC_AND((dhdp)->osh, &(dhdp)->pktlog->pktlog_status, ~PKTLOG_TRANS_RX); \
} while (0); \
}
#define PKTLOG_CLEAR_IN_TXS(dhdp) \
{ \
do { \
OSL_ATOMIC_AND((dhdp)->osh, &(dhdp)->pktlog->pktlog_status, ~PKTLOG_TRANS_TXS); \
} while (0); \
}
#define DHD_PKTLOG_TX(dhdp, pkt, pktdata, pktid) \
{ \
do { \
if ((dhdp) && (dhdp)->pktlog && (pkt)) { \
PKTLOG_SET_IN_TX(dhdp); \
if ((dhdp)->pktlog->pktlog_ring && \
OSL_ATOMIC_READ((dhdp)->osh, \
(&(dhdp)->pktlog->pktlog_ring->start))) { \
dhd_pktlog_ring_add_pkts(dhdp, pkt, pktdata, pktid, PKT_TX); \
} \
PKTLOG_CLEAR_IN_TX(dhdp); \
} \
} while (0); \
}
#define DHD_PKTLOG_TXS(dhdp, pkt, pktdata, pktid, status) \
{ \
do { \
if ((dhdp) && (dhdp)->pktlog && (pkt)) { \
PKTLOG_SET_IN_TXS(dhdp); \
if ((dhdp)->pktlog->pktlog_ring && \
OSL_ATOMIC_READ((dhdp)->osh, \
(&(dhdp)->pktlog->pktlog_ring->start))) { \
dhd_pktlog_ring_tx_status(dhdp, pkt, pktdata, pktid, status); \
} \
PKTLOG_CLEAR_IN_TXS(dhdp); \
} \
} while (0); \
}
#define DHD_PKTLOG_RX(dhdp, pkt, pktdata) \
{ \
do { \
if ((dhdp) && (dhdp)->pktlog && (pkt)) { \
PKTLOG_SET_IN_RX(dhdp); \
if (ntoh16((pkt)->protocol) != ETHER_TYPE_BRCM) { \
if ((dhdp)->pktlog->pktlog_ring && \
OSL_ATOMIC_READ((dhdp)->osh, \
(&(dhdp)->pktlog->pktlog_ring->start))) { \
dhd_pktlog_ring_add_pkts(dhdp, pkt, pktdata, \
DHD_INVALID_PKTID, PKT_RX); \
} \
} \
PKTLOG_CLEAR_IN_RX(dhdp); \
} \
} while (0); \
}
#define DHD_PKTLOG_WAKERX(dhdp, pkt, pktdata) \
{ \
do { \
if ((dhdp) && (dhdp)->pktlog && (pkt)) { \
PKTLOG_SET_IN_RX(dhdp); \
if (ntoh16((pkt)->protocol) != ETHER_TYPE_BRCM) { \
if ((dhdp)->pktlog->pktlog_ring && \
OSL_ATOMIC_READ((dhdp)->osh, \
(&(dhdp)->pktlog->pktlog_ring->start))) { \
dhd_pktlog_ring_add_pkts(dhdp, pkt, pktdata, \
DHD_INVALID_PKTID, PKT_WAKERX); \
} \
} \
PKTLOG_CLEAR_IN_RX(dhdp); \
} \
} while (0); \
}
extern dhd_pktlog_filter_t* dhd_pktlog_filter_init(int size);
extern int dhd_pktlog_filter_deinit(dhd_pktlog_filter_t *filter);
extern int dhd_pktlog_filter_add(dhd_pktlog_filter_t *filter, char *arg);
extern int dhd_pktlog_filter_del(dhd_pktlog_filter_t *filter, char *arg);
extern int dhd_pktlog_filter_enable(dhd_pktlog_filter_t *filter, uint32 pktlog_case, uint32 enable);
extern int dhd_pktlog_filter_pattern_enable(dhd_pktlog_filter_t *filter, char *arg, uint32 enable);
extern int dhd_pktlog_filter_info(dhd_pktlog_filter_t *filter);
extern bool dhd_pktlog_filter_matched(dhd_pktlog_filter_t *filter, char *data, uint32 pktlog_case);
extern bool dhd_pktlog_filter_existed(dhd_pktlog_filter_t *filter, char *arg, uint32 *id);
#define DHD_PKTLOG_FILTER_ADD(pattern, filter_pattern, dhdp) \
{ \
do { \
if ((strlen(pattern) + 1) < sizeof(filter_pattern)) { \
strncpy(filter_pattern, pattern, sizeof(filter_pattern)); \
dhd_pktlog_filter_add(dhdp->pktlog->pktlog_filter, filter_pattern); \
} \
} while (0); \
}
#define DHD_PKTLOG_DUMP_PATH DHD_COMMON_DUMP_PATH
extern int dhd_pktlog_debug_dump(dhd_pub_t *dhdp);
extern void dhd_pktlog_dump(void *handle, void *event_info, u8 event);
extern void dhd_schedule_pktlog_dump(dhd_pub_t *dhdp);
extern int dhd_pktlog_dump_write_memory(dhd_pub_t *dhdp, const void *user_buf, uint32 size);
extern int dhd_pktlog_dump_write_file(dhd_pub_t *dhdp);
#define DHD_PKTLOG_FATE_INFO_STR_LEN 256
#define DHD_PKTLOG_FATE_INFO_FORMAT "BRCM_Packet_Fate"
#define DHD_PKTLOG_DUMP_TYPE "pktlog_dump"
#define DHD_PKTLOG_DEBUG_DUMP_TYPE "pktlog_debug_dump"
extern void dhd_pktlog_get_filename(dhd_pub_t *dhdp, char *dump_path, int len);
extern uint32 dhd_pktlog_get_item_length(dhd_pktlog_ring_info_t *report_ptr);
extern uint32 dhd_pktlog_get_dump_length(dhd_pub_t *dhdp);
extern uint32 __dhd_dbg_pkt_hash(uintptr_t pkt, uint32 pktid);
#ifdef DHD_COMPACT_PKT_LOG
#define CPKT_LOG_BIT_SIZE 22
#define CPKT_LOG_MAX_NUM 80
extern int dhd_cpkt_log_proc(dhd_pub_t *dhdp, char *buf, int buf_len,
int bit_offset, int req_pkt_num);
#endif /* DHD_COMPACT_PKT_LOG */
#endif /* DHD_PKT_LOGGING */
#endif /* __DHD_PKTLOG_H_ */

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