net: wireless: rockchip_wlan: bcmdhd: Update to 101.10.591.x

This commit is contained in:
baiywt 2023-11-08 14:18:25 +08:00
parent c598125738
commit 0a60f6cf89
335 changed files with 78480 additions and 90214 deletions

View File

@ -1,6 +1,27 @@
# SPDX-License-Identifier: GPL-2.0
#
# Copyright (C) 2023, 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:>>
#
config BCMDHD
tristate "Broadcom FullMAC wireless cards support"
default m
help
This module adds support for wireless adapters based on
Broadcom FullMAC chipset.
@ -51,7 +72,6 @@ choice
config BCMDHD_OOB
depends on BCMDHD && BCMDHD_SDIO
bool "Out-of-Band Interrupt"
default y
help
Interrupt from WL_HOST_WAKE.
config BCMDHD_SDIO_IRQ

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

@ -1,8 +1,27 @@
# SPDX-License-Identifier: GPL-2.0
# bcmdhd
#
# Copyright (C) 2023, 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:>>
#
MODULE_NAME := bcmdhd
CONFIG_BCMDHD ?= m
CONFIG_AP6XXX ?= m
#CONFIG_BCMDHD_SDIO := y
#CONFIG_BCMDHD_PCIE := y
@ -14,47 +33,52 @@ CONFIG_BCMDHD_OOB := y
CONFIG_BCMDHD_PROPTXSTATUS := y
CONFIG_BCMDHD_AG := y
CONFIG_DHD_USE_STATIC_BUF := y
#CONFIG_BCMDHD_STATIC_BUF_IN_DHD := y
CONFIG_BCMDHD_ANDROID_VERSION := 12
CONFIG_BCMDHD_STATIC_BUF_IN_DHD := y
CONFIG_BCMDHD_ANDROID_VERSION := 14
CONFIG_BCMDHD_AUTO_SELECT := y
CONFIG_BCMDHD_DEBUG := y
#CONFIG_BCMDHD_RECONNECT := y
#CONFIG_BCMDHD_TIMESTAMP := y
#CONFIG_BCMDHD_WAPI := y
#CONFIG_BCMDHD_RANDOM_MAC := y
CONFIG_BCMDHD_REQUEST_FW := y
#CONFIG_BCMDHD_MULTIPLE_DRIVER := y
#CONFIG_BCMDHD_FW_SIGNATURE := y
#CONFIG_BCMDHD_DWDS := y
CONFIG_BCMDHD_TPUT := y
#CONFIG_BCMDHD_MULTIPLE_DRIVER := y
#CONFIG_BCMDHD_ADAPTER_INDEX := 0
CONFIG_MACH_PLATFORM := y
#CONFIG_BCMDHD_DTS := y
DHDCFLAGS = -Wall -Wstrict-prototypes -Wno-date-time \
-Wno-implicit-fallthrough -Wno-declaration-after-statement \
-Wno-vla -Wno-vla-extension \
-Dlinux -DLINUX -DBCMDRIVER \
DHDCFLAGS = -Wall -Wstrict-prototypes -Wno-date-time -Wno-strict-prototypes \
-Wno-uninitialized -Wno-unused-but-set-variable -Wno-address \
-Dlinux -DLINUX -DBCMDRIVER -DBCMUTILS_ERR_CODES \
-DBCMDONGLEHOST -DBCMDMA32 -DBCMFILEIMAGE \
-DDHDTHREAD -DDHD_DEBUG -DSHOW_EVENTS -DGET_OTP_MAC_ENABLE \
-DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DSUPPORT_PM2_ONLY \
-DPKTPRIO_OVERRIDE \
-DKEEP_ALIVE -DPKT_FILTER_SUPPORT -DDHDTCPACK_SUPPRESS \
-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 -DBCM_USE_PLATFORM_STRLCPY \
-DUSE_NEW_RSPEC_DEFS \
-DWL_EXT_IAPSTA -DWL_ESCAN -DCCODE_LIST -DSUSPEND_EVENT \
-DEAPOL_RESEND -DEAPOL_DYNAMATIC_RESEND -DWL_SCHED_SCAN \
-DENABLE_INSMOD_NO_FW_LOAD -Wframe-larger-than=2048 \
-DSCHED_SCAN_DELAYED_WORK -DDHD_PNO_FLAG
-DKEY_INSTALL_CHECK \
-DENABLE_INSMOD_NO_FW_LOAD
DHDOFILES = aiutils.o siutils.o sbutils.o bcmutils.o bcmwifi_channels.o \
DHDOFILES = aiutils.o siutils.o sbutils.o \
bcmutils.o bcmwifi_channels.o bcmxtlv.o bcm_app_utils.o bcmstdlib_s.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 \
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 \
hnd_pktq.o hnd_pktpool.o linux_pkt.o frag.o \
dhd_linux_exportfs.o dhd_linux_pktdump.o dhd_mschdbg.o linuxerrmap.o \
dhd_linux_tx.o dhd_linux_rx.o fwpkg_utils.o \
dhd_config.o dhd_ccode.o wl_event.o wl_android_ext.o \
wl_iapsta.o wl_escan.o
wl_iapsta.o wl_escan.o wl_timer.o
ifneq ($(CONFIG_WIRELESS_EXT),)
DHDOFILES += wl_iw.o
@ -63,39 +87,49 @@ 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
DHDOFILES += dhd_cfg80211.o wl_cfgvif.o wl_roam.o
DHDCFLAGS += -DWL_CFG80211 -DWLP2P -DWL_CFG80211_STA_EVENT
# DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS
DHDCFLAGS += -DWL_CFG80211_GON_COLLISION
DHDCFLAGS += -DWL_CAP_HE -DWL_6G_BAND -DWL_5P9G
# DHDCFLAGS += -DCONFIG_6GHZ_BKPORT
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 += -DHOSTAPD_BW_SUPPORT
DHDCFLAGS += -DWL_VIRTUAL_APSTA -DSTA_MGMT -DSOFTAP_UAPSD_OFF
DHDCFLAGS += -DWL_SOFTAP_ACS
DHDCFLAGS += -DNUM_SCB_MAX_PROBE=3
DHDCFLAGS += -DWL_SCB_TIMEOUT=10
DHDCFLAGS += -DEXPLICIT_DISCIF_CLEANUP
DHDCFLAGS += -DDHD_USE_SCAN_WAKELOCK
DHDCFLAGS += -DSPECIFIC_MAC_GEN_SCHEME
DHDCFLAGS += -DWL_IFACE_MGMT
DHDCFLAGS += -DWLFBT -DWL_GCMP_SUPPORT
DHDCFLAGS += -DWL_EXT_RECONNECT
DHDCFLAGS += -DDHD_LOSSLESS_ROAMING
DHDCFLAGS += -DSUPPORT_RSSI_SUM_REPORT
DHDCFLAGS += -DWLFBT -DWL_GCMP_SUPPORT -DWL_OWE -DWL_SAE_FT
DHDCFLAGS += -DROAM_CHANNEL_CACHE -DDHD_LOSSLESS_ROAMING
# DHDCFLAGS += -DWL_CFGVENDOR_SEND_HANG_EVENT
DHDCFLAGS += -DGTK_OFFLOAD_SUPPORT
DHDCFLAGS += -DRESTART_AP_WAR
# DHDCFLAGS += -DWL_STATIC_IF
DHDCFLAGS += -DWL_CLIENT_SAE -DWL_OWE
#DHDCFLAGS += -DWL_STATIC_IF #-DDHD_MAX_STATIC_IFS=2
DHDCFLAGS += -DWL_CLIENT_SAE
DHDCFLAGS += -DCONNECT_INFO_WAR -DWL_ROAM_WAR
DHDCFLAGS += -DVNDR_IE_WAR
DHDCFLAGS += -DRESTART_AP_WAR -DRXF0OVFL_REINIT_WAR
endif
#BCMDHD_SDIO
ifneq ($(CONFIG_BCMDHD_SDIO),)
BUS_TYPE := "sdio"
DHDCFLAGS += -DBCMSDIO -DMMC_SDIO_ABORT -DMMC_SW_RESET -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 \
BUS_TYPE := sdio
DHDCFLAGS += -DBCMSDIO -DMMC_SDIO_ABORT -DUSE_SDIOFIFO_IOVAR -DBCMLXSDMMC \
-DSDTEST -DBDC -DDHD_USE_IDLECOUNT -DCUSTOM_SDIO_F2_BLKSIZE=256 \
-DBCMSDIOH_TXGLOM -DBCMSDIOH_TXGLOM_EXT -DBCMSDIOH_STATIC_COPY_BUF \
-DRXFRAME_THREAD -DDHDENABLE_TAILPAD -DSUPPORT_P2P_GO_PS \
-DBCMSDIO_RXLIM_POST -DBCMSDIO_TXSEQ_SYNC -DCONSOLE_DPC \
-DBCMSDIO_INTSTATUS_WAR
DHDCFLAGS += -DMMC_HW_RESET #-DMMC_SW_RESET #-DBUS_POWER_RESTORE
ifeq ($(CONFIG_BCMDHD_OOB),y)
DHDCFLAGS += -DOOB_INTR_ONLY -DCUSTOMER_OOB -DHW_OOB
ifeq ($(CONFIG_BCMDHD_DISABLE_WOWLAN),y)
@ -110,15 +144,24 @@ endif
#BCMDHD_PCIE
ifneq ($(CONFIG_BCMDHD_PCIE),)
BUS_TYPE := "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_PKTID_AUDIT_ENABLED
DHDCFLAGS += -DINSMOD_FW_LOAD
DHDCFLAGS += -DCHIP_INTR_CONTROL
#DHDCFLAGS += -DDHD_PCIE_RUNTIMEPM -DMAX_IDLE_COUNT=11 -DCUSTOM_DHD_RUNTIME_MS=100
DHDCFLAGS += -DDHD_CONTROL_PCIE_ASPM_WIFI_TURNON
BUS_TYPE := pcie
DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1
DHDCFLAGS += -DDONGLE_ENABLE_ISOLATION
DHDCFLAGS += -DDHD_LB -DDHD_LB_RXP -DDHD_LB_STATS -DDHD_LB_TXP
DHDCFLAGS += -DDHD_LB_PRIMARY_CPUS=0xF0 -DDHD_LB_SECONDARY_CPUS=0x0E
# DHDCFLAGS += -DDHD_PKTID_AUDIT_ENABLED
DHDCFLAGS += -DEAPOL_PKT_PRIO -DENABLE_DHD_GRO
DHDCFLAGS += -DDHD_SKIP_DONGLE_RESET_IN_ATTACH
DHDCFLAGS += -DDHD_DONGLE_TRAP_IN_DETACH
DHDCFLAGS += -DFORCE_DONGLE_RESET_IN_DEVRESET_ON
DHDCFLAGS += -DDHD_USE_COHERENT_MEM_FOR_RING
DHDCFLAGS += -DCHECK_TRAP_ROT
DHDCFLAGS += -DINSMOD_FW_LOAD
DHDCFLAGS += -DCONFIG_HAS_WAKELOCK #-DDHD_DEBUG_WAKE_LOCK
DHDCFLAGS += -DDHD_PACKET_TIMEOUT_MS=50 -DMAX_TX_TIMEOUT=50
ifeq ($(CONFIG_AP6XXX),y)
DHDCFLAGS += -DWAKEUP_KSOFTIRQD_POST_NAPI_SCHEDULE
endif
ifeq ($(CONFIG_BCMDHD_OOB),y)
DHDCFLAGS += -DCUSTOMER_OOB -DBCMPCIE_OOB_HOST_WAKE -DHW_OOB
endif
@ -131,10 +174,16 @@ endif
#BCMDHD_USB
ifneq ($(CONFIG_BCMDHD_USB),)
BUS_TYPE := "usb"
BUS_TYPE := usb
DHDCFLAGS += -DUSBOS_TX_THREAD -DBCMDBUS -DBCMTRXV2 -DDBUS_USB_LOOPBACK \
-DBDC
DHDCFLAGS += -DBCM_REQUEST_FW -DEXTERNAL_FW_PATH
DHDCFLAGS += -DINSMOD_FW_LOAD
DHDCFLAGS += -DBCM_REQUEST_FW
DHDCFLAGS += -DSHOW_LOGTRACE
DHDCFLAGS += -DWL_EXT_WOWL
ifneq ($(CONFIG_BCMDHD_REQUEST_FW),y)
DHDCFLAGS += -DEXTERNAL_FW_PATH
endif
ifneq ($(CONFIG_BCMDHD_CUSB),)
DHDCFLAGS += -DBCMUSBDEV_COMPOSITE
CONFIG_BCMDHD_NO_POWER_OFF := y
@ -149,9 +198,17 @@ endif
ifeq ($(CONFIG_BCMDHD_MULTIPLE_DRIVER),y)
DHDCFLAGS += -DBCMDHD_MDRIVER
ifneq ($(CONFIG_BCMDHD_ADAPTER_INDEX),)
CONFIG_BCMDHD_STATIC_BUF_IN_DHD := y
MODULE_NAME := dhd$(BUS_TYPE)_$(CONFIG_BCMDHD_ADAPTER_INDEX)
DHDCFLAGS += -DADAPTER_IDX=$(CONFIG_BCMDHD_ADAPTER_INDEX)
DHDCFLAGS += -DBUS_TYPE=\"-$(BUS_TYPE)-$(CONFIG_BCMDHD_ADAPTER_INDEX)\"
DHDCFLAGS += -DDHD_LOG_PREFIX=\"[dhd-$(BUS_TYPE)-$(CONFIG_BCMDHD_ADAPTER_INDEX)]\"
else
MODULE_NAME := dhd$(BUS_TYPE)
DHDCFLAGS += -DBUS_TYPE=\"-$(BUS_TYPE)\"
DHDCFLAGS += -DDHD_LOG_PREFIX=\"[dhd-$(BUS_TYPE)]\"
MODULE_NAME := dhd$(BUS_TYPE)
endif
else
DHDCFLAGS += -DBUS_TYPE=\"\"
endif
@ -165,9 +222,11 @@ endif
ifeq ($(CONFIG_BCMDHD_PROPTXSTATUS),y)
ifneq ($(CONFIG_BCMDHD_USB),)
DHDCFLAGS += -DPROP_TXSTATUS
DHDCFLAGS += -DLIMIT_BORROW -DBULK_DEQUEUE
endif
ifneq ($(CONFIG_BCMDHD_SDIO),)
DHDCFLAGS += -DPROP_TXSTATUS -DPROPTX_MAXCOUNT
DHDCFLAGS += -DLIMIT_BORROW -DBULK_DEQUEUE
endif
ifneq ($(CONFIG_CFG80211),)
DHDCFLAGS += -DPROP_TXSTATUS_VSDB
@ -183,18 +242,22 @@ endif
ifneq ($(CONFIG_BCMDHD_ANDROID_VERSION),)
DHDCFLAGS += -DANDROID_VERSION=$(CONFIG_BCMDHD_ANDROID_VERSION)
DHDCFLAGS += -DDHD_NOTIFY_MAC_CHANGED
DHDCFLAGS += -DANDROID_BKPORT
ifneq ($(CONFIG_CFG80211),)
DHDCFLAGS += -DGSCAN_SUPPORT -DRTT_SUPPORT
DHDCFLAGS += -DWL_SAR_TX_POWER
# DHDCFLAGS += -DLINKSTAT_SUPPORT
DHDCFLAGS += -DCUSTOM_COUNTRY_CODE -DDHD_GET_VALID_CHANNELS
DHDCFLAGS += -DDEBUGABILITY -DDBG_PKT_MON
# DHDCFLAGS += -DDHD_LOG_DUMP
DHDCFLAGS += -DDHD_FW_COREDUMP
DHDCFLAGS += -DPNO_SUPPORT
DHDCFLAGS += -DWL_SCHED_SCAN
DHDCFLAGS += -DWL_P2P_RAND
DHDCFLAGS += -DGSCAN_SUPPORT -DRTT_SUPPORT
DHDCFLAGS += -DLINKSTAT_SUPPORT -DLINKSTAT_EXT_SUPPORT
DHDCFLAGS += -DCUSTOM_COUNTRY_CODE -DDHD_GET_VALID_CHANNELS
DHDCFLAGS += -DDEBUGABILITY -DDEBUGABILITY_DISABLE_MEMDUMP -DDBG_PKT_MON
DHDCFLAGS += -DDHD_LOG_DUMP -DDHD_FW_COREDUMP
# DHDCFLAGS += -DDHD_PKT_LOGGING_DBGRING
DHDCFLAGS += -DAPF -DNDO_CONFIG_SUPPORT -DRSSI_MONITOR_SUPPORT
DHDCFLAGS += -DDHD_WAKE_STATUS -DWL_LATENCY_MODE
DHDOFILES += dhd_rtt.o bcm_app_utils.o
DHDCFLAGS += -DDHD_WAKE_STATUS
DHDCFLAGS += -DWL_LATENCY_MODE
DHDOFILES += dhd_rtt.o
DHDOFILES += dhd_log_dump.o
endif
else
DHDCFLAGS += -DANDROID_VERSION=0
@ -210,6 +273,7 @@ ifeq ($(CONFIG_BCMDHD_DEBUG),y)
DHDCFLAGS += -DPKT_STATICS
DHDCFLAGS += -DKSO_DEBUG
# DHDCFLAGS += -DDHD_PKTDUMP_TOFW
# DHDCFLAGS += -DDHD_DUMP_FILE_WRITE_FROM_KERNEL
endif
# For Debug2
@ -221,11 +285,15 @@ ifneq ($(CONFIG_BCMDHD_PCIE),)
DHDCFLAGS += -DEWP_EDL
DHDCFLAGS += -DDNGL_EVENT_SUPPORT
DHDCFLAGS += -DDHD_SSSR_DUMP
DHDCFLAGS += -DDHD_MEM_STATS
DHDCFLAGS += -DDHD_FLOW_RING_STATUS_TRACE
DHDCFLAGS += -DDNGL_AXI_ERROR_LOGGING
endif
DHDOFILES += dhd_log_dump.o
endif
# MESH support for kernel 3.10 later
ifeq ($(CONFIG_WL_MESH),y)
ifeq ($(CONFIG_BCMDHD_WLMESH),y)
DHDCFLAGS += -DWLMESH
ifneq ($(CONFIG_CFG80211),)
DHDCFLAGS += -DWLMESH_CFG80211
@ -253,7 +321,7 @@ ifneq ($(CONFIG_CFG80211),)
ifneq ($(CONFIG_BCMDHD_SDIO),)
DHDCFLAGS += -DRXF_DEQUEUE_ON_BUSY
endif
DHDCFLAGS += -DWL_STATIC_IF
#DHDCFLAGS += -DWL_STATIC_IF
endif
endif
@ -263,10 +331,19 @@ ifeq ($(CONFIG_CSI_SUPPORT),y)
DHDOFILES += dhd_csi.o
endif
# For CONNECTION_IMPROVE
ifeq ($(CONFIG_BCMDHD_RECONNECT),y)
DHDCFLAGS += -DEAPOL_RESEND -DEAPOL_RESEND_M4
ifneq ($(CONFIG_CFG80211),)
DHDCFLAGS += -DWL_EXT_RECONNECT -DWL_REASSOC_BCAST
DHDCFLAGS += -DWL_EXT_DISCONNECT_RECONNECT
endif
endif
# For TPUT_IMPROVE
ifeq ($(CONFIG_BCMDHD_TPUT),y)
DHDCFLAGS += -DDHD_TPUT_PATCH
DHDCFLAGS += -DTCPACK_INFO_MAXNUM=10 -DTCPDATA_INFO_MAXNUM=10
DHDCFLAGS += -DTCPACK_INFO_MAXNUM=40 -DTCPDATA_INFO_MAXNUM=40
ifneq ($(CONFIG_BCMDHD_SDIO),)
DHDCFLAGS += -DDYNAMIC_MAX_HDR_READ
DHDCFLAGS :=$(filter-out -DSDTEST,$(DHDCFLAGS))
@ -301,20 +378,29 @@ endif
# For NAN
ifneq ($(CONFIG_BCMDHD_NAN),)
DHDCFLAGS += -DWL_NAN -DWL_NAN_DISC_CACHE
DHDCFLAGS += -DWL_NAN -DWL_NAN_DISC_CACHE -DWL_NANP2P -DWL_NAN_ENABLE_MERGE
DHDOFILES += wl_cfgnan.o bcmbloom.o
endif
# For Module auto-selection
ifeq ($(CONFIG_BCMDHD_AUTO_SELECT),y)
DHDCFLAGS += -DUPDATE_MODULE_NAME
ifeq ($(CONFIG_BCMDHD_REQUEST_FW),y)
# DHDCFLAGS += -DFW_AMPAK_PATH="\"ampak\""
# DHDCFLAGS += -DMODULE_PATH
endif
ifneq ($(CONFIG_BCMDHD_SDIO),)
DHDCFLAGS += -DGET_OTP_MODULE_NAME -DCOMPAT_OLD_MODULE
endif
endif
ifeq ($(CONFIG_AP6XXX),y)
DHDCFLAGS += -DUSE_LATE_INITCALL_SYNC
DHDCFLAGS += -DBCM_USE_PLATFORM_STRLCPY
endif
ifeq ($(CONFIG_AP6XXX),m)
DHDCFLAGS += -DBCMDHD_MODULAR
DHDCFLAGS += -DBOARD_MODULAR_INIT
endif
ifeq ($(CONFIG_MACH_PLATFORM),y)
@ -324,19 +410,36 @@ ifeq ($(CONFIG_BCMDHD_DTS),y)
endif
DHDCFLAGS += -DCUSTOMER_HW -DDHD_OF_SUPPORT
DHDCFLAGS += -DCUSTOMER_HW_ROCKCHIP
# DHDCFLAGS += -DCUSTOMER_HW_ROCKCHIP_RK3588
DHDCFLAGS += -DBCM_USE_PLATFORM_STRLCPY
endif
ifneq ($(CONFIG_BCMDHD_PCIE),)
ifneq ($(filter -DCUSTOMER_HW_ROCKCHIP_RK3588, $(DHDCFLAGS)),)
DHDCFLAGS += -DDHD_CONTROL_PCIE_ASPM_WIFI_TURNON
endif
endif
ifeq ($(CONFIG_BCMDHD_REQUEST_FW),y)
DHDCFLAGS += -DDHD_LINUX_STD_FW_API
DHDCFLAGS += -DDHD_REQUEST_FW_PATH
DHDCFLAGS += -DDHD_FW_NAME="\"fw_bcmdhd.bin\""
DHDCFLAGS += -DDHD_NVRAM_NAME="\"nvram.txt\""
DHDCFLAGS += -DDHD_CLM_NAME="\"clm_bcmdhd.blob\""
DHDCFLAGS += -DDHD_CONFIG_NAME="\"config.txt\""
else
DHDCFLAGS += -DDHD_SUPPORT_VFS_CALL
ifeq ($(CONFIG_BCMDHD_FW_PATH),)
DHDCFLAGS += -DCONFIG_BCMDHD_FW_PATH="\"/system/etc/firmware/fw_bcmdhd.bin\""
DHDCFLAGS += -DCONFIG_BCMDHD_NVRAM_PATH="\"/system/etc/firmware/nvram.txt\""
DHDCFLAGS += -DCONFIG_BCMDHD_CLM_PATH="\"/system/etc/firmware/clm_bcmdhd.blob\""
DHDCFLAGS += -DCONFIG_BCMDHD_FW_PATH="\"/vendor/etc/firmware/fw_bcmdhd.bin\""
DHDCFLAGS += -DCONFIG_BCMDHD_NVRAM_PATH="\"/vendor/etc/firmware/nvram.txt\""
DHDCFLAGS += -DCONFIG_BCMDHD_CLM_PATH="\"/vendor/etc/firmware/clm_bcmdhd.blob\""
endif
DHDCFLAGS += -DCONFIG_BCMDHD_CONFIG_PATH="\"/vendor/etc/firmware/config.txt\""
endif
ifeq ($(CONFIG_BCMDHD_FW_SIGNATURE),y)
DHDCFLAGS += -DFW_SIGNATURE
DHDCFLAGS += -DBL_HEAP_START_GAP_SIZE=0x1000 -DBL_HEAP_SIZE=0x10000
endif
ifeq ($(CONFIG_BCMDHD_AG),y)
@ -352,7 +455,12 @@ else
endif
DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -DENHANCED_STATIC_BUF
DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF
ifneq ($(filter -DDHD_LOG_DUMP, $(DHDCFLAGS)),)
DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP
endif
ifneq ($(filter -DDHD_FW_COREDUMP, $(DHDCFLAGS)),)
DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP
endif
ifneq ($(CONFIG_BCMDHD_PCIE),)
DHDCFLAGS += -DDHD_USE_STATIC_CTRLBUF
endif
@ -363,8 +471,7 @@ BCMDHD_ROOT = $(src)
#$(warning "BCMDHD_ROOT=$(BCMDHD_ROOT)")
EXTRA_CFLAGS = $(DHDCFLAGS)
EXTRA_CFLAGS += -DDHD_COMPILED=\"$(BCMDHD_ROOT)\"
EXTRA_CFLAGS += -I$(srctree)/$(BCMDHD_ROOT)/include/ -I$(srctree)/$(BCMDHD_ROOT)/
EXTRA_CFLAGS += $(call cc-disable-warning, unused-but-set-variable)
EXTRA_CFLAGS += -I$(BCMDHD_ROOT)/include/ -I$(BCMDHD_ROOT)/
ifeq ($(CONFIG_AP6XXX),m)
EXTRA_LDFLAGS += --strip-debug
endif

View File

@ -2,7 +2,7 @@
* Misc utility routines for accessing chip-specific features
* of the SiliconBackplane-based Broadcom chips.
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -52,7 +52,7 @@ static bool ai_get_apb_bridge(const si_t *sih, uint32 coreidx, uint32 *apb_id,
uint32 *apb_coreunit);
#endif /* AXI_TIMEOUTS_NIC */
#if defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC)
#if defined(AXI_TIMEOUTS) || defined(AXI_TIMEOUTS_NIC)
static void ai_reset_axi_to(const si_info_t *sii, aidmp_t *ai);
#endif /* defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC) */
@ -169,7 +169,7 @@ get_asd(const si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *ad
/* Parse the enumeration rom to identify all cores */
void
BCMATTACHFN(ai_scan)(si_t *sih, void *regs, uint devid)
ai_scan(si_t *sih, void *regs, uint devid)
{
si_info_t *sii = SI_INFO(sih);
si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info;
@ -177,6 +177,7 @@ BCMATTACHFN(ai_scan)(si_t *sih, void *regs, uint devid)
uint32 erombase, *eromptr, *eromlim;
axi_wrapper_t * axi_wrapper = sii->axi_wrapper;
SI_MSG_DBG_REG(("%s: Enter\n", __FUNCTION__));
BCM_REFERENCE(devid);
erombase = R_REG(sii->osh, &cc->eromptr);
@ -225,6 +226,7 @@ BCMATTACHFN(ai_scan)(si_t *sih, void *regs, uint devid)
cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI);
if (cia == (ER_END | ER_VALID)) {
SI_VMSG(("Found END of erom after %d cores\n", sii->numcores));
SI_MSG_DBG_REG(("%s: Exit\n", __FUNCTION__));
return;
}
@ -423,6 +425,11 @@ BCMATTACHFN(ai_scan)(si_t *sih, void *regs, uint devid)
/* cache APB bridge wrapper address for set/clear timeout */
if ((mfg == MFGID_ARM) && (cid == APB_BRIDGE_ID)) {
ASSERT(sii->num_br < SI_MAXBR);
if (sii->num_br >= SI_MAXBR) {
SI_ERROR(("bridge number %d is overflowed\n", sii->num_br));
goto error;
}
sii->br_wrapba[sii->num_br++] = addrl;
}
@ -474,6 +481,7 @@ BCMATTACHFN(ai_scan)(si_t *sih, void *regs, uint devid)
error:
sii->numcores = 0;
SI_MSG_DBG_REG(("%s: Exit\n", __FUNCTION__));
return;
}
@ -612,8 +620,10 @@ BCMPOSTTRAPFN(_ai_setcoreidx)(si_t *sih, uint coreidx, uint use_wrapn)
sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE);
/* point bar0 window */
ai_corereg(sih, sih->buscoreidx, PCIE_TER_BAR0_WIN, ~0, addr);
ai_corereg(sih, sih->buscoreidx, PCIE_TER_BAR0_WRAPPER, ~0, wrap);
ai_corereg(sih, sih->buscoreidx,
PCIE_TER_BAR0_WIN_REG(sih->buscorerev), ~0, addr);
ai_corereg(sih, sih->buscoreidx,
PCIE_TER_BAR0_WRAPPER_REG(sih->buscorerev), ~0, wrap);
break;
default: /* other slices */
@ -643,6 +653,10 @@ BCMPOSTTRAPFN(_ai_setcoreidx)(si_t *sih, uint coreidx, uint use_wrapn)
sii->curidx = coreidx;
if (regs) {
SI_MSG_DBG_REG(("%s: %d\n", __FUNCTION__, coreidx));
}
return regs;
}
@ -1755,7 +1769,7 @@ ai_update_backplane_timeouts(const si_t *sih, bool enable, uint32 timeout_exp, u
#endif /* AXI_TIMEOUTS || AXI_TIMEOUTS_NIC */
}
#if defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC)
#if defined(AXI_TIMEOUTS) || defined(AXI_TIMEOUTS_NIC)
/* slave error is ignored, so account for those cases */
static uint32 si_ignore_errlog_cnt = 0;
@ -1824,12 +1838,6 @@ BCMPOSTTRAPFN(ai_ignore_errlog)(const si_info_t *sii, const aidmp_t *ai,
extd_axi_id_mask = TRUE;
ignore_errsts_2 = AIELS_DECODE;
break;
#ifdef USE_HOSTMEM
case BCM43602_CHIP_ID:
axi_id = BCM43602_BT_AXI_ID;
address_check = FALSE;
break;
#endif /* USE_HOSTMEM */
default:
return FALSE;
}
@ -1946,7 +1954,7 @@ ai_clear_backplane_to_fast(si_t *sih, void *addr)
}
#endif /* AXI_TIMEOUTS_NIC */
#if defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC)
#if defined(AXI_TIMEOUTS) || defined(AXI_TIMEOUTS_NIC)
static bool g_disable_backplane_logs = FALSE;
static uint32 last_axi_error = AXI_WRAP_STS_NONE;
@ -2086,11 +2094,6 @@ BCMPOSTTRAPFN(ai_clear_backplane_to_per_core)(si_t *sih, uint coreid, uint coreu
case AIELS_DECODE:
SI_PRINT(("AXI decode error\n"));
#ifdef USE_HOSTMEM
/* Ignore known cases of CR4 prefetch abort bugs */
if ((errlog_id & (BCM_AXI_ID_MASK | BCM_AXI_ACCESS_TYPE_MASK)) !=
(BCM43xx_AXI_ACCESS_TYPE_PREFETCH | BCM43xx_CR4_AXI_ID))
#endif
{
ret |= AXI_WRAP_STS_DECODE_ERR;
}
@ -2236,7 +2239,7 @@ uint32
BCMPOSTTRAPFN(ai_clear_backplane_to)(si_t *sih)
{
uint32 ret = 0;
#if defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC)
#if defined(AXI_TIMEOUTS) || defined(AXI_TIMEOUTS_NIC)
const si_info_t *sii = SI_INFO(sih);
aidmp_t *ai;
uint32 i;
@ -2490,7 +2493,7 @@ BCMPOSTTRAPRAMFN(ai_get_wrapper_base_addr)(uint32 **offset)
}
uint32
BCMATTACHFN(ai_wrapper_dump_buf_size)(const si_t *sih)
ai_wrapper_dump_buf_size(const si_t *sih)
{
uint32 buf_size = 0;
uint32 wrapper_count = 0;
@ -2539,7 +2542,7 @@ uint32
BCMPOSTTRAPFN(ai_wrapper_dump_last_timeout)(const si_t *sih, uint32 *error, uint32 *core,
uint32 *ba, uchar *p)
{
#if defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC)
#if defined(AXI_TIMEOUTS) || defined(AXI_TIMEOUTS_NIC)
uint32 *p32;
uint32 wrap_ba = last_axi_error_wrap;
uint i;
@ -2590,7 +2593,7 @@ BCMPOSTTRAPFN(ai_wrapper_dump_binary)(const si_t *sih, uchar *p)
bool
BCMPOSTTRAPFN(ai_check_enable_backplane_log)(const si_t *sih)
{
#if defined (AXI_TIMEOUTS) || defined (AXI_TIMEOUTS_NIC)
#if defined(AXI_TIMEOUTS) || defined(AXI_TIMEOUTS_NIC)
if (g_disable_backplane_logs) {
return FALSE;
}

View File

@ -3,7 +3,7 @@
* Contents are wifi-specific, used by any kernel or app-level
* software that might want wifi things as it grows.
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -28,7 +28,9 @@
#ifdef BCMDRIVER
#include <osl.h>
#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
#ifndef tolower
#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
#endif /* tolower */
#else /* BCMDRIVER */
#include <stdio.h>
#include <string.h>
@ -40,7 +42,7 @@
#endif /* BCMDRIVER */
#include <bcmwifi_channels.h>
#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL) || defined(_CONSOLE))
#include <bcmstdlib.h> /* For wlexe/Makefile.wlm_dll */
#endif
@ -109,33 +111,7 @@ cca_info(uint8 *bitmap, int num_bits, int *left, int *bit_pos)
static uint8
spec_to_chan(chanspec_t chspec)
{
uint8 center_ch, edge, primary, sb;
center_ch = CHSPEC_CHANNEL(chspec);
if (CHSPEC_IS20(chspec)) {
return center_ch;
} else {
/* the lower edge of the wide channel is half the bw from
* the center channel.
*/
if (CHSPEC_IS40(chspec)) {
edge = center_ch - CH_20MHZ_APART;
} else {
/* must be 80MHz (until we support more) */
ASSERT(CHSPEC_IS80(chspec));
edge = center_ch - CH_40MHZ_APART;
}
/* find the channel number of the lowest 20MHz primary channel */
primary = edge + CH_10MHZ_APART;
/* select the actual subband */
sb = (chspec & WL_CHANSPEC_CTL_SB_MASK) >> WL_CHANSPEC_CTL_SB_SHIFT;
primary = primary + sb * CH_20MHZ_APART;
return primary;
}
return wf_chspec_primary20_chan(chspec);
}
/*
@ -161,7 +137,7 @@ cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chans
return BCME_NOMEM;
}
memset(bitmap, 0, bitmap_sz);
bzero(bitmap, bitmap_sz);
/* Initially, all channels are up for consideration */
for (i = 0; i < num_chans; i++) {
if (input[i]->chanspec)
@ -1180,8 +1156,8 @@ wl_cntbuf_to_xtlv_format(void *ctx, void *cntbuf, int buflen, uint32 corerev)
}
#ifdef BCMDRIVER
wlccnt = MALLOC(osh, sizeof(*wlccnt));
macstat = MALLOC(osh, WL_CNT_MCST_STRUCT_SZ);
wlccnt = MALLOCZ(osh, sizeof(*wlccnt));
macstat = MALLOCZ(osh, WL_CNT_MCST_STRUCT_SZ);
#else
wlccnt = (wl_cnt_wlc_t *)malloc(sizeof(*wlccnt));
macstat = (uint32 *)malloc(WL_CNT_MCST_STRUCT_SZ);
@ -1251,7 +1227,7 @@ wl_cntbuf_to_xtlv_format(void *ctx, void *cntbuf, int buflen, uint32 corerev)
xtlv_desc[2].len = 0;
xtlv_desc[2].ptr = NULL;
memset(cntbuf, 0, buflen);
bzero(cntbuf, buflen);
res = bcm_pack_xtlv_buf_from_mem(&xtlvbuf_p, &xtlvbuflen,
xtlv_desc, BCM_XTLV_OPTION_ALIGN32);

View File

@ -1,766 +0,0 @@
/*
* 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,7 +1,7 @@
/*
* Bloom filter support
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -24,16 +24,13 @@
#include <typedefs.h>
#include <bcmdefs.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0))
#include <stdarg.h>
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0) */
#ifdef BCMDRIVER
#include <osl.h>
#include <bcmutils.h>
#else /* !BCMDRIVER */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifndef ASSERT
#define ASSERT(exp)
#endif
@ -71,7 +68,7 @@ bcm_bloom_create(bcm_bloom_alloc_t alloc_cb,
err = BCME_NOMEM;
goto done;
}
memset(bp, 0, sizeof(*bp));
bzero(bp, sizeof(*bp));
bp->cb_ctx = cb_ctx;
bp->max_hash = max_hash;
@ -80,7 +77,7 @@ bcm_bloom_create(bcm_bloom_alloc_t alloc_cb,
err = BCME_NOMEM;
goto done;
}
memset(bp->hash, 0, sizeof(*bp->hash) * max_hash);
bzero(bp->hash, sizeof(*bp->hash) * max_hash);
if (filter_size > 0) {
bp->filter = (*alloc_cb)(cb_ctx, filter_size);
@ -89,7 +86,7 @@ bcm_bloom_create(bcm_bloom_alloc_t alloc_cb,
goto done;
}
bp->filter_size = filter_size;
memset(bp->filter, 0, filter_size);
bzero(bp->filter, filter_size);
}
*bloom = bp;

View File

@ -1,7 +1,7 @@
/*
* bcmevent read-only data shared by kernel or app layers
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -28,6 +28,7 @@
#include <bcmeth.h>
#include <bcmevent.h>
#include <802.11.h>
#include <802.11brcm.h>
/* Table of event name strings for UIs and debugging dumps */
typedef struct {
@ -179,9 +180,6 @@ 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),
@ -189,21 +187,12 @@ static const bcmevent_name_str_t bcmevent_names[] = {
#ifdef WLBSSLOAD_REPORT
BCMEVENT_NAME(WLC_E_BSS_LOAD),
#endif
#if defined(BT_WIFI_HANDOVER) || defined(WL_TBOW)
BCMEVENT_NAME(WLC_E_BT_WIFI_HANDOVER_REQ),
#endif
#ifdef WLFBT
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),
@ -237,14 +226,27 @@ static const bcmevent_name_str_t bcmevent_names[] = {
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)
BCMEVENT_NAME(WLC_E_TWT),
#endif /* WL_TWT */
BCMEVENT_NAME(WLC_E_AMT),
BCMEVENT_NAME(WLC_E_ROAM_SCAN_RESULT),
#if defined(XRAPI)
BCMEVENT_NAME(WLC_E_XR_SOFTAP_PSMODE),
#endif /* XRAPI */
#ifdef WL_SIB_COEX
BCMEVENT_NAME(WLC_E_SIB),
#endif /* WL_SIB_COEX */
BCMEVENT_NAME(WLC_E_MSCS),
BCMEVENT_NAME(WLC_E_RXDMA_RECOVERY_ATMPT),
#ifdef WL_SCHED_SCAN
BCMEVENT_NAME(WLC_E_PFN_PARTIAL_RESULT),
#endif /* WL_SCHED_SCAN */
BCMEVENT_NAME(WLC_E_MLO_LINK_INFO),
BCMEVENT_NAME(WLC_E_C2C),
BCMEVENT_NAME(WLC_E_BCN_TSF),
BCMEVENT_NAME(WLC_E_OWE_INFO),
BCMEVENT_NAME(WLC_E_ULMU_DISABLED_REASON_UPD),
};
const char *bcmevent_get_name(uint event_type)
@ -396,7 +398,8 @@ is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype,
if (out_event) {
/* ensure BRCM event pkt aligned */
memcpy(&out_event->event, &bcm_event->event, sizeof(wl_event_msg_t));
(void)memcpy_s(&out_event->event, sizeof(out_event->event),
&bcm_event->event, sizeof(out_event->event));
}
break;
@ -424,8 +427,9 @@ is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype,
if (out_event) {
/* ensure BRCM dngl event pkt aligned */
memcpy(&out_event->dngl_event, &((bcm_dngl_event_t *)pktdata)->dngl_event,
sizeof(bcm_dngl_event_msg_t));
(void)memcpy_s(&out_event->dngl_event, sizeof(out_event->dngl_event),
&((bcm_dngl_event_t *)pktdata)->dngl_event,
sizeof(out_event->dngl_event));
}
break;

View File

@ -1,88 +0,0 @@
#
# 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

@ -1,60 +0,0 @@
#
# 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,7 +2,7 @@
* BCMSDH interface glue
* implement bcmsdh API for SDIOH driver
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -46,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) */
@ -56,7 +56,7 @@ 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;
@ -78,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;
@ -358,9 +358,6 @@ bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err)
return data;
}
#ifdef BCMSDH_MODULE
EXPORT_SYMBOL(bcmsdh_cfg_read);
#endif
void
bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err)
@ -391,9 +388,6 @@ bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err)
BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__,
fnc_num, addr, data));
}
#ifdef BCMSDH_MODULE
EXPORT_SYMBOL(bcmsdh_cfg_write);
#endif
uint32
bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err)
@ -498,7 +492,6 @@ bcmsdh_cisaddr_read(void *sdh, uint func, uint8 *cisd, uint32 offset)
return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
}
int
bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set)
{

View File

@ -1,7 +1,7 @@
/*
* SDIO access interface for drivers - linux specific (pci only)
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -95,23 +95,6 @@ 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 */
@ -142,12 +125,6 @@ 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. */
@ -156,28 +133,8 @@ 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);
}
@ -271,15 +228,37 @@ int bcmsdh_set_get_wake(bcmsdh_info_t *bcmsdh, int flag)
bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
unsigned long flags;
#endif
int ret = 0;
int ret;
#if defined(OOB_INTR_ONLY)
spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags);
#endif
ret = bcmsdh->pkt_wake;
bcmsdh->total_wake_count += flag;
bcmsdh->pkt_wake = flag;
#if defined(OOB_INTR_ONLY)
spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags);
#endif
return ret;
}
int bcmsdh_get_wake(bcmsdh_info_t *bcmsdh)
{
#if defined(OOB_INTR_ONLY)
bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
unsigned long flags;
#endif
int ret;
#if defined(OOB_INTR_ONLY)
spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags);
#endif
ret = bcmsdh->pkt_wake;
#if defined(OOB_INTR_ONLY)
spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags);
#endif
return ret;
@ -566,7 +545,7 @@ EXPORT_SYMBOL(bcmsdh_intr_dereg);
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,7 +1,7 @@
/*
* BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -43,7 +43,7 @@
#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
@ -82,9 +82,23 @@ static void IRQHandler(struct sdio_func *func);
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, 18, 0) && defined(MMC_SW_RESET)
#if defined(ENABLE_INSMOD_NO_FW_LOAD)
#if defined(MMC_SW_RESET) && LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0)
extern int mmc_sw_reset(struct mmc_card *card);
#else
extern int mmc_sw_reset(struct mmc_host *host);
#endif
#elif defined(MMC_HW_RESET) && LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)
extern int mmc_hw_reset(struct mmc_card *card);
#else
extern int mmc_hw_reset(struct mmc_host *host);
#endif
#elif defined(BUS_POWER_RESTORE) && \
LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
#undef MMC_SW_RESET
#undef MMC_HW_RESET
#else
extern int sdio_reset_comm(struct mmc_card *card);
#endif
@ -103,13 +117,15 @@ extern PBCMSDH_SDMMC_INSTANCE gInstance;
#define CUSTOM_SDIO_F1_BLKSIZE DEFAULT_SDIO_F1_BLKSIZE
#endif
#define COPY_BUF_SIZE (SDPCM_MAXGLOM_SIZE * 1600)
#define MAX_IO_RW_EXTENDED_BLK 511
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) */
@ -139,7 +155,7 @@ static int
sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data);
#endif /* NOTYET */
#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)
{
@ -148,6 +164,8 @@ void sdioh_sdmmc_card_enable_func_f3(sdioh_info_t *sd, struct sdio_func *func)
}
#endif /* defined (BT_OVER_SDIO) */
void sdmmc_set_timing(sdioh_info_t *sd, uint8 timing);
uint8 sdmmc_get_timing(sdioh_info_t *sd);
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);
@ -182,12 +200,49 @@ sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd)
err_ret = sdio_enable_func(sd->func[1]);
sdio_release_host(sd->func[1]);
if (err_ret) {
sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x\n", err_ret));
sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: %d\n", err_ret));
}
return FALSE;
}
/*
* Set standard CCCR driver strength. Default value is type B.
* Type: Value, driver strength
* A: 0x10, x1.5
* B: 0x00, x1
* C: 0x20, x0.75
* D: 0x30, x0.5
*/
int
sdioh_set_driver_strength(struct sdio_func *func, uint8 level)
{
int reg;
int err = 0;
sdio_claim_host(func);
reg = sdio_readb(func, SDIOD_CCCR_DRIVER_STRENGTH, &err);
if (err) {
sd_err(("sd_ds error for read SDIOD_CCCR_DRIVER_STRENGTH : 0x%x\n", err));
goto done;
} else {
sd_info(("SYNA: sd_ds get cccr driver strength 0x%x\n", reg));
}
reg = ((reg & 0xf) | level);
sdio_writeb(func, reg, SDIOD_CCCR_DRIVER_STRENGTH, &err);
if (err) {
sd_err(("sd_ds error for write SDIOD_CCCR_DRIVER_STRENGTH : 0x%x\n", err));
goto done;
} else {
sd_info(("SYNA: sd_ds set cccr driver strength 0x%x\n", reg));
}
done:
sdio_release_host(func);
return err;
}
/*
* Public entry points & extern's
*/
@ -209,6 +264,14 @@ sdioh_attach(osl_t *osh, struct sdio_func *func)
return NULL;
}
bzero((char *)sd, sizeof(sdioh_info_t));
#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STATIC_COPY_BUF)
sd->copy_buf = MALLOC(osh, COPY_BUF_SIZE);
if (sd->copy_buf == NULL) {
sd_err(("%s: MALLOC of %d-byte copy_buf failed\n",
__FUNCTION__, COPY_BUF_SIZE));
goto fail;
}
#endif
sd->osh = osh;
sd->fake_func0.num = 0;
sd->fake_func0.card = func->card;
@ -224,7 +287,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) */
@ -273,6 +336,9 @@ sdioh_attach(osl_t *osh, struct sdio_func *func)
return sd;
fail:
#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STATIC_COPY_BUF)
MFREE(sd->osh, sd->copy_buf, COPY_BUF_SIZE);
#endif
MFREE(sd->osh, sd, sizeof(sdioh_info_t));
return NULL;
}
@ -301,6 +367,9 @@ sdioh_detach(osl_t *osh, sdioh_info_t *sd)
sd->func[1] = NULL;
sd->func[2] = NULL;
#if defined(BCMSDIOH_TXGLOM) && defined(BCMSDIOH_STATIC_COPY_BUF)
MFREE(sd->osh, sd->copy_buf, COPY_BUF_SIZE);
#endif
MFREE(sd->osh, sd, sizeof(sdioh_info_t));
}
return SDIOH_API_RC_SUCCESS;
@ -329,7 +398,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);
@ -357,7 +426,8 @@ sdioh_disable_func_intr(sdioh_info_t *sd)
sdio_claim_host(sd->func[0]);
reg = sdio_readb(sd->func[0], SDIOD_CCCR_INTEN, &err);
if (err) {
sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x (ignore when remove)\n",
__FUNCTION__, err));
sdio_release_host(sd->func[0]);
return SDIOH_API_RC_FAIL;
}
@ -483,7 +553,8 @@ enum {
IOV_HCIREGS,
IOV_POWER,
IOV_CLOCK,
IOV_RXCHAIN
IOV_RXCHAIN,
IOV_DS
};
const bcm_iovar_t sdioh_iovars[] = {
@ -494,10 +565,6 @@ 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 },
@ -507,6 +574,7 @@ const bcm_iovar_t sdioh_iovars[] = {
#ifdef BCMDBG
{"sd_hciregs", IOV_HCIREGS, 0, 0, IOVT_BUFFER, 0 },
#endif
{"sd_ds", IOV_DS, 0, 0, IOVT_UINT32, 0 },
{NULL, 0, 0, 0, 0, 0 }
};
@ -721,88 +789,52 @@ 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):
case IOV_GVAL(IOV_DS):
{
/* XXX Should copy for alignment reasons */
sdreg_t *sd_ptr = (sdreg_t *)params;
uint8 reg2;
int err;
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;
sdio_claim_host(si->func[0]);
reg2 = sdio_readb(si->func[0], SDIOD_CCCR_DRIVER_STRENGTH, &err);
if (err) {
sd_err(("sd_ds error for read SDIOD_CCCR_DRIVER_STRENGTH : 0x%x\n", err));
bcmerror = BCME_SDIO_ERROR;
} else {
sd_trace(("sd_ds get cccr driver strength 0x%x\n", reg2));
}
sdio_release_host(si->func[0]);
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); */
int_val = (int)reg2;
bcopy(&int_val, arg, sizeof(int_val));
break;
}
case IOV_SVAL(IOV_HOSTREG):
case IOV_SVAL(IOV_DS):
{
/* XXX Should copy for alignment reasons */
sdreg_t *sd_ptr = (sdreg_t *)params;
uint8 type;
int err;
if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
if (int_val == 0) {
type = 0x0;
} else if (int_val == 1) {
type = 0x10;
} else if (int_val == 2) {
type = 0x20;
} else if (int_val == 3) {
type = 0x30;
} else {
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;
err = sdioh_set_driver_strength(si->func[0], type);
if (err) {
sd_err(("sd_ds error write SDIOD_CCCR_DRIVER_STRENGTH : 0x%x\n", err));
}
break;
}
#endif /* BCMINTERNAL */
default:
bcmerror = BCME_UNSUPPORTED;
break;
@ -949,7 +981,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));
@ -1014,7 +1046,7 @@ 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) */
}
@ -1206,7 +1238,7 @@ sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint add
if (err_ret)
#endif /* MMC_SDIO_ABORT */
{
sd_err(("bcmsdh_sdmmc: Failed to %s word F%d:@0x%05x=%02x, Err: 0x%08x\n",
sd_err(("bcmsdh_sdmmc: Failed to %s word F%d:@0x%05x=%02x, Err: %d\n",
rw ? "Write" : "Read", func, addr, *word, err_ret));
}
}
@ -1356,7 +1388,8 @@ sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func
return SDIOH_API_RC_FAIL;
}
}
} else if(sd->txglom_mode == SDPCM_TXGLOM_CPY) {
}
else if(sd->txglom_mode == SDPCM_TXGLOM_CPY) {
for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
ttl_len += PKTLEN(sd->osh, pnext);
}
@ -1365,16 +1398,20 @@ sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func
for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext);
pkt_len = PKTLEN(sd->osh, pnext);
if (!localbuf) {
#ifdef BCMSDIOH_STATIC_COPY_BUF
if (ttl_len <= COPY_BUF_SIZE)
localbuf = sd->copy_buf;
#else
localbuf = (uint8 *)MALLOC(sd->osh, ttl_len);
#endif
if (localbuf == NULL) {
sd_err(("%s: %s TXGLOM: localbuf malloc FAILED\n",
__FUNCTION__, (write) ? "TX" : "RX"));
sd_err(("%s: %s localbuf malloc FAILED ttl_len=%d\n",
__FUNCTION__, (write) ? "TX" : "RX", ttl_len));
ttl_len -= pkt_len;
goto txglomfail;
}
}
bcopy(buf, (localbuf + local_plen), pkt_len);
local_plen += pkt_len;
if (PKTNEXT(sd->osh, pnext))
@ -1419,8 +1456,10 @@ txglomfail:
return SDIOH_API_RC_FAIL;
}
#ifndef BCMSDIOH_STATIC_COPY_BUF
if (localbuf)
MFREE(sd->osh, localbuf, ttl_len);
#endif
#ifndef PKT_STATICS
if (sd_msglevel & SDH_COST_VAL)
@ -1746,21 +1785,44 @@ 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)
#if defined(ENABLE_INSMOD_NO_FW_LOAD)
static int sdio_sw_reset(sdioh_info_t *sd)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) && defined(MMC_SW_RESET)
struct mmc_host *host = sd->func[0]->card->host;
#endif
struct mmc_card *card = sd->func[0]->card;
int err = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) && defined(MMC_SW_RESET)
printf("%s: Enter\n", __FUNCTION__);
#if defined(MMC_SW_RESET) && LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
/* MMC_SW_RESET */
printf("%s: call mmc_sw_reset\n", __FUNCTION__);
sdio_claim_host(sd->func[0]);
err = mmc_sw_reset(host);
sdio_release_host(sd->func[0]);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0)
err = mmc_sw_reset(card);
#else
err = sdio_reset_comm(sd->func[0]->card);
err = mmc_sw_reset(card->host);
#endif
sdio_release_host(sd->func[0]);
#elif defined(MMC_HW_RESET) && LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
/* MMC_HW_RESET */
printf("%s: call mmc_hw_reset\n", __FUNCTION__);
sdio_claim_host(sd->func[0]);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
while (atomic_read(&card->sdio_funcs_probed) > 1) {
atomic_dec(&card->sdio_funcs_probed);
}
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)
err = mmc_hw_reset(card);
#else
err = mmc_hw_reset(card->host);
#endif
sdio_release_host(sd->func[0]);
#elif defined(BUS_POWER_RESTORE) && \
LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
printf("%s: call mmc_power_restore_host\n", __FUNCTION__);
mmc_power_restore_host(card->host);
#else
/* sdio_reset_comm */
err = sdio_reset_comm(card);
#endif
if (err)
@ -1786,60 +1848,60 @@ sdioh_start(sdioh_info_t *sd, int stage)
sdio access will come in way
*/
if (sd->func[0]) {
if (stage == 0) {
/* Since the power to the chip is killed, we will have
re enumerate the device again. Set the block size
and enable the fucntion 1 for in preparation for
downloading the code
*/
/* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux
2.6.27. The implementation prior to that is buggy, and needs broadcom's
patch for it
*/
#if defined(ENABLE_INSMOD_NO_FW_LOAD) && !defined(BUS_POWER_RESTORE)
if ((ret = sdio_sw_reset(sd))) {
sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
return ret;
} else
if (stage == 0) {
/* Since the power to the chip is killed, we will have
re enumerate the device again. Set the block size
and enable the fucntion 1 for in preparation for
downloading the code
*/
/* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux
2.6.27. The implementation prior to that is buggy, and needs broadcom's
patch for it
*/
#if defined(ENABLE_INSMOD_NO_FW_LOAD)
if ((ret = sdio_sw_reset(sd))) {
sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
return ret;
} else
#endif
{
sd->num_funcs = 2;
sd->sd_blockmode = TRUE;
sd->use_client_ints = TRUE;
sd->client_block_size[0] = 64;
{
sd->num_funcs = 2;
sd->sd_blockmode = TRUE;
sd->use_client_ints = TRUE;
sd->client_block_size[0] = 64;
if (sd->func[1]) {
/* Claim host controller */
sdio_claim_host(sd->func[1]);
if (sd->func[1]) {
/* Claim host controller */
sdio_claim_host(sd->func[1]);
sd->client_block_size[1] = 64;
ret = sdio_set_block_size(sd->func[1], 64);
if (ret) {
sd_err(("bcmsdh_sdmmc: Failed to set F1 "
"blocksize(%d)\n", ret));
sd->client_block_size[1] = 64;
ret = sdio_set_block_size(sd->func[1], 64);
if (ret) {
sd_err(("bcmsdh_sdmmc: Failed to set F1 "
"blocksize(%d)\n", ret));
}
/* Release host controller F1 */
sdio_release_host(sd->func[1]);
}
/* Release host controller F1 */
sdio_release_host(sd->func[1]);
}
if (sd->func[2]) {
/* Claim host controller F2 */
sdio_claim_host(sd->func[2]);
if (sd->func[2]) {
/* Claim host controller F2 */
sdio_claim_host(sd->func[2]);
sd->client_block_size[2] = sd_f2_blocksize;
printf("%s: set sd_f2_blocksize %d\n", __FUNCTION__, sd_f2_blocksize);
ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize);
if (ret) {
sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize"
" to %d(%d)\n", sd_f2_blocksize, ret));
}
sd->client_block_size[2] = sd_f2_blocksize;
printf("%s: set sd_f2_blocksize %d\n", __FUNCTION__, sd_f2_blocksize);
ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize);
if (ret) {
sd_err(("bcmsdh_sdmmc: Failed to set F2 "
"blocksize to %d(%d)\n", sd_f2_blocksize, ret));
/* Release host controller F2 */
sdio_release_host(sd->func[2]);
}
/* Release host controller F2 */
sdio_release_host(sd->func[2]);
}
sdioh_sdmmc_card_enablefuncs(sd);
sdioh_sdmmc_card_enablefuncs(sd);
}
} else {
#if !defined(OOB_INTR_ONLY)
@ -1856,8 +1918,7 @@ sdioh_start(sdioh_info_t *sd, int stage)
bcmsdh_oob_intr_set(sd->bcmsdh, TRUE);
#endif /* !defined(OOB_INTR_ONLY) */
}
}
else
} else
sd_err(("%s Failed\n", __FUNCTION__));
#endif /* defined(OEM_ANDROID) */
@ -1894,10 +1955,20 @@ sdioh_stop(sdioh_info_t *sd)
}
else
sd_err(("%s Failed\n", __FUNCTION__));
#endif /* defined(OEM_ANDROID) */
#if !defined(MMC_SW_RESET) && !defined(MMC_HW_RESET)
#if defined(BUS_POWER_RESTORE) && \
LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
if (sd->func[0]) {
struct mmc_card *card = sd->func[0]->card;
printf("%s: call mmc_power_save_host\n", __FUNCTION__);
mmc_power_save_host(card->host);
}
#endif
#endif
#if !defined(OOB_INTR_ONLY)
sdio_claim_host_unlock_local(sd);
#endif
#endif /* defined(OEM_ANDROID) */
return (0);
}
@ -1907,16 +1978,6 @@ 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)
{
@ -1941,6 +2002,29 @@ sdioh_gpio_init(sdioh_info_t *sd)
return SDIOH_API_RC_FAIL;
}
uint8
sdmmc_get_timing(sdioh_info_t *sd)
{
struct sdio_func *sdio_func = sd->func[0];
struct mmc_host *host = sdio_func->card->host;
return host->ios.timing;
}
void
sdmmc_set_timing(sdioh_info_t *sd, uint8 timing)
{
struct sdio_func *sdio_func = sd->func[0];
struct mmc_host *host = sdio_func->card->host;
struct mmc_ios *ios = &host->ios;
mmc_host_clk_hold(host);
DHD_INFO(("%s: Before change: sd current timing is %u\n", __FUNCTION__, ios->timing));
ios->timing = timing;
host->ops->set_ios(host, ios);
DHD_ERROR(("%s: After change: sd timing is %u\n", __FUNCTION__, ios->timing));
mmc_host_clk_release(host);
}
uint
sdmmc_get_clock_rate(sdioh_info_t *sd)
{

View File

@ -1,7 +1,7 @@
/*
* BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -91,8 +91,12 @@ static int sdioh_probe(struct sdio_func *func)
adapter->bus_num = host_idx;
adapter->slot_num = rca;
adapter->sdio_func = func;
} else
} else {
sd_err(("can't find adapter info for this chip\n"));
#ifdef ADAPTER_IDX
goto fail;
#endif
}
#ifdef WL_CFG80211
wl_cfg80211_set_parent_dev(&func->dev);
@ -198,6 +202,7 @@ static const struct sdio_device_id bcmsdh_sdmmc_ids[] = {
{ 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, BCM43756_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) },
@ -207,6 +212,9 @@ static const struct sdio_device_id bcmsdh_sdmmc_ids[] = {
{ 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(SDIO_VENDOR_ID_BROADCOM, SDIO_ANY_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM4381_CHIP_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM4382_CHIP_ID) },
{ SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) },
{ 0, 0, 0, 0 /* end: all zeroes */
},

View File

@ -1,147 +0,0 @@
/*
* SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer
*
* 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: 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)) \
printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \
} while (0)
#define BLOCK_SIZE_4318 64
#define BLOCK_SIZE_4328 512
/* internal return code */
#define SUCCESS 0
#undef ERROR
#define ERROR 1
/* private bus modes */
#define SDIOH_MODE_SPI 0
#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */
#define USE_MULTIBLOCK 0x4
struct sdioh_info {
uint cfg_bar; /* pci cfg address for bar */
uint32 caps; /* cached value of capabilities reg */
uint bar0; /* BAR0 for PCI Device */
osl_t *osh; /* osh handler */
void *controller; /* Pointer to SPI Controller's private data struct */
uint lockcount; /* nest count of sdspi_lock() calls */
bool client_intr_enabled; /* interrupt connnected flag */
bool intr_handler_valid; /* client driver interrupt handler valid */
sdioh_cb_fn_t intr_handler; /* registered interrupt handler */
void *intr_handler_arg; /* argument to call interrupt handler */
bool initialized; /* card initialized */
uint32 target_dev; /* Target device ID */
uint32 intmask; /* Current active interrupts */
void *sdos_info; /* Pointer to per-OS private data */
uint32 controller_type; /* Host controller type */
uint8 version; /* Host Controller Spec Compliance Version */
uint irq; /* Client irq */
uint32 intrcount; /* Client interrupts */
uint32 local_intrcount; /* Controller interrupts */
bool host_init_done; /* Controller initted */
bool card_init_done; /* Client SDIO interface initted */
bool polled_mode; /* polling for command completion */
bool sd_use_dma; /* DMA on CMD53 */
bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */
/* Must be on for sd_multiblock to be effective */
bool use_client_ints; /* If this is false, make sure to restore */
bool got_hcint; /* Host Controller interrupt. */
/* polling hack in wl_linux.c:wl_timer() */
int adapter_slot; /* Maybe dealing with multiple slots/controllers */
int sd_mode; /* SD1/SD4/SPI */
int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */
uint32 data_xfer_count; /* Current register transfer size */
uint32 cmd53_wr_data; /* Used to pass CMD53 write data */
uint32 card_response; /* Used to pass back response status byte */
uint32 card_rsp_data; /* Used to pass back response data word */
uint16 card_rca; /* Current Address */
uint8 num_funcs; /* Supported funcs on client */
uint32 com_cis_ptr;
uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS];
void *dma_buf;
ulong dma_phys;
int r_cnt; /* rx count */
int t_cnt; /* tx_count */
};
/************************************************************
* Internal interfaces: per-port references into bcmsdspi.c
*/
/* Global message bits */
extern uint sd_msglevel;
/**************************************************************
* Internal interfaces: bcmsdspi.c references to per-port code
*/
/* Register mapping routines */
extern uint32 *spi_reg_map(osl_t *osh, uintptr addr, int size);
extern void spi_reg_unmap(osl_t *osh, uintptr addr, int size);
/* Interrupt (de)registration routines */
extern int spi_register_irq(sdioh_info_t *sd, uint irq);
extern void spi_free_irq(uint irq, sdioh_info_t *sd);
/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */
extern void spi_lock(sdioh_info_t *sd);
extern void spi_unlock(sdioh_info_t *sd);
/* Allocate/init/free per-OS private data */
extern int spi_osinit(sdioh_info_t *sd);
extern void spi_osfree(sdioh_info_t *sd);
#endif /* _BCM_SD_SPI_H */

View File

@ -1,433 +0,0 @@
/*
* Broadcom SPI Host Controller Driver - Linux Per-port
*
* 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 <typedefs.h>
#include <bcmutils.h>
#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()) /* XXX Doesn't handle CONFIG_PREEMPT? */
#endif
/* Interrupt handler */
static irqreturn_t
sdspi_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;
sd = (sdioh_info_t *)dev_id;
sd->local_intrcount++;
if (!sd->card_init_done) {
sd_err(("%s: Hey Bogus intr...not even initted: irq %d\n", __FUNCTION__, irq));
return IRQ_RETVAL(FALSE);
} else {
ours = spi_check_client_intr(sd, NULL);
/* For local interrupts, wake the waiting process */
if (ours && sd->got_hcint) {
sdos = (struct sdos_info *)sd->sdos_info;
wake_up_interruptible(&sdos->intr_wait_queue);
}
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;
}
/* Free Linux 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)
{
return (uint32 *)REG_MAP(addr, size);
}
void
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)
{
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);
#ifndef BCMSPI_ANDROID
init_waitqueue_head(&sdos->intr_wait_queue);
#endif /* !BCMSPI_ANDROID */
return BCME_OK;
}
void
spi_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;
}
#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);
return SDIOH_API_RC_SUCCESS;
}
/* Protect against reentrancy (disable device interrupts while executing) */
void
spi_lock(sdioh_info_t *sd)
{
ulong flags;
struct sdos_info *sdos;
sdos = (struct sdos_info *)sd->sdos_info;
ASSERT(sdos);
sd_trace(("%s: %d\n", __FUNCTION__, sd->lockcount));
spin_lock_irqsave(&sdos->lock, flags);
if (sd->lockcount) {
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);
}
/* Enable client interrupt */
void
spi_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) {
#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
ASSERT(!yield);
#endif
sd_trace(("%s: yield %d canblock %d\n",
__FUNCTION__, yield, BLOCKABLE()));
/* Clear the "interrupt happened" flag and last intrstatus */
sd->got_hcint = FALSE;
#ifdef BCMSDYIELD
if (yield && BLOCKABLE()) {
struct sdos_info *sdos;
sdos = (struct sdos_info *)sd->sdos_info;
/* Wait for the indication, the interrupt will be masked when the ISR fires. */
wait_event_interruptible(sdos->intr_wait_queue, (sd->got_hcint));
} else
#endif /* BCMSDYIELD */
{
spi_spinbits(sd);
}
}
#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 */

View File

@ -1,7 +1,7 @@
/*
* 'Standard' SDIO HOST CONTROLLER driver
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -134,38 +134,46 @@ uint32 sd3_autoselect_uhsi_max = 0;
* All has DrvStr as 'B' [val:0] and CLKGEN as 0.
*/
static unsigned short presetval_sw_table[] = {
0x0520, /* initialization: DrvStr:'B' [0]; CLKGen:0;
0x0520, /* initialization: DrvStr:'B' [0]; CLKGen:0;
* SDCLKFreqSel: 520 [division: 320*2 = 640: ~400 KHz]
*/
0x0008, /* default speed:DrvStr:'B' [0]; CLKGen:0;
* SDCLKFreqSel: 8 [division: 6*2 = 12: ~25 MHz]
*/
0x0004, /* High speed: DrvStr:'B' [0]; CLKGen:0;
0x0004, /* High speed: DrvStr:'B' [0]; CLKGen:0;
* SDCLKFreqSel: 4 [division: 3*2 = 6: ~50 MHz]
*/
0x0008, /* SDR12: DrvStr:'B' [0]; CLKGen:0;
0x0008, /* SDR12: DrvStr:'B' [0]; CLKGen:0;
* SDCLKFreqSel: 8 [division: 6*2 = 12: ~25 MHz]
*/
0x0004, /* SDR25: DrvStr:'B' [0]; CLKGen:0;
0x0004, /* SDR25: DrvStr:'B' [0]; CLKGen:0;
* SDCLKFreqSel: 4 [division: 3*2 = 6: ~50 MHz]
*/
0x0001, /* SDR50: DrvStr:'B' [0]; CLKGen:0;
0x0001, /* SDR50: DrvStr:'B' [0]; CLKGen:0;
* SDCLKFreqSel: 2 [division: 1*2 = 2: ~100 MHz]
*/
0x0001, /* SDR104: DrvStr:'B' [0]; CLKGen:0;
0x0001, /* SDR104: DrvStr:'B' [0]; CLKGen:0;
SDCLKFreqSel: 1 [no division: ~255/~208 MHz]
*/
0x0002 /* DDR50: DrvStr:'B' [0]; CLKGen:0;
0x0002 /* DDR50: DrvStr:'B' [0]; CLKGen:0;
SDCLKFreqSel: 4 [division: 3*2 = 6: ~50 MHz]
*/
};
#ifdef BCMFPGA_HW
/*
* Voltage switch, clock tuning and preset are not supported in
* FPGA which operates at 6.25Mhz.
*/
bool sd3_sw_override1 = TRUE;
#else
/* This is to have software overrides to the hardware. Info follows:
For override [1]: Preset registers: not supported
For override [1]: Preset registers: not supported
Voltage switch: not supported
Clock Tuning: not supported
*/
bool sd3_sw_override1 = FALSE;
#endif /* BCMFPGA_HW */
bool sd3_sw_read_magic_bytes = FALSE;
#define SD3_TUNING_REQD(sd, sd_uhsimode) ((sd_uhsimode != SD3CLKMODE_DISABLED) && \
@ -248,14 +256,6 @@ static bool sdstd_3_get_matching_drvstrn(sdioh_info_t *sd,
static int sdstd_3_clock_wrapper(sdioh_info_t *sd);
static int sdstd_clock_wrapper(sdioh_info_t *sd);
#ifdef BCMINTERNAL
#ifdef NOTUSED
static int parse_caps(uint32 caps_reg, char *buf, int len);
static int parse_state(uint32 state_reg, char *buf, int len);
static void cis_fetch(sdioh_info_t *sd, int func, char *data, int len);
#endif /* NOTUSED */
#endif /* BCMINTERNAL */
#ifdef BCMDBG
static void print_regs(sdioh_info_t *sd);
#endif
@ -321,25 +321,6 @@ sdstd_wreg(sdioh_info_t *sd, uint reg, uint32 data)
sd_ctrl(("32: W Reg 0x%02x, Data 0x%x\n", reg, data));
}
#ifdef BCMINTERNAL
#ifdef NOTUSED
static void
sdstd_or_reg(sdioh_info_t *sd, uint reg, uint32 val)
{
volatile uint32 data = *(volatile uint32 *)(sd->mem_space + reg);
data |= val;
*(volatile uint32 *)(sd->mem_space + reg) = (volatile uint32)data;
}
static void
sdstd_mod_reg(sdioh_info_t *sd, uint reg, uint32 mask, uint32 val)
{
volatile uint32 data = *(volatile uint32 *)(sd->mem_space + reg);
data &= ~mask;
data |= (val & mask);
*(volatile uint32 *)(sd->mem_space + reg) = (volatile uint32)data;
}
#endif /* NOTUSED */
#endif /* BCMINTERNAL */
/* 8 bit PCI regs */
static inline void
@ -545,7 +526,8 @@ enum {
IOV_CLOCK,
IOV_UHSIMOD,
IOV_TUNEMOD,
IOV_TUNEDIS
IOV_TUNEDIS,
IOV_DS
};
const bcm_iovar_t sdioh_iovars[] = {
@ -575,6 +557,7 @@ const bcm_iovar_t sdioh_iovars[] = {
#endif
{"tuning_mode", IOV_TUNEMOD, 0, 0, IOVT_UINT32, 0},
{"sd3_tuning_disable", IOV_TUNEDIS, 0, 0, IOVT_BOOL, 0},
{"sd_ds", IOV_DS, 0, 0, IOVT_UINT32, 0},
{NULL, 0, 0, 0, 0, 0 }
};
@ -1024,6 +1007,58 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name,
si->sd3_tuning_disable = (bool)int_val;
break;
case IOV_GVAL(IOV_DS):
{
uint32 drvstrn;
int status;
status = sdstd_card_regread(si, 0, SDIOD_CCCR_DRIVER_STRENGTH, 1, &drvstrn);
if (status != BCME_OK) {
sd_err(("sd_ds error for read SDIOD_CCCR_DRIVER_STRENGTH : 0x%x\n",
status));
bcmerror = BCME_SDIO_ERROR;
} else {
sd_err(("sd_ds get cccr driver strength 0x%x\n", drvstrn));
}
int_val = (uint32)drvstrn;
bcopy(&int_val, arg, val_size);
break;
}
case IOV_SVAL(IOV_DS):
{
uint32 drvstrn;
int status;
status = sdstd_card_regread(si, 0, SDIOD_CCCR_DRIVER_STRENGTH, 1, &drvstrn);
if (status != BCME_OK) {
sd_err(("sd_ds error for read SDIOD_CCCR_DRIVER_STRENGTH : 0x%x\n",
status));
bcmerror = BCME_SDIO_ERROR;
} else {
sd_err(("sd_ds get cccr driver strength 0x%x\n", drvstrn));
}
if (int_val == 0) {
drvstrn = ((drvstrn & 0xf) | 0x0);
} else if (int_val == 1) {
drvstrn = ((drvstrn & 0xf) | 0x10);
} else if (int_val == 2) {
drvstrn = ((drvstrn & 0xf) | 0x20);
} else if (int_val == 3) {
drvstrn = ((drvstrn & 0xf) | 0x30);
} else {
bcmerror = BCME_BADARG;
break;
}
status = sdstd_card_regwrite(si, 0, SDIOD_CCCR_DRIVER_STRENGTH, 1, drvstrn);
if (status != BCME_OK) {
sd_err(("sd_ds error write SDIOD_CCCR_DRIVER_STRENGTH : 0x%x\n", status));
}
break;
}
default:
bcmerror = BCME_UNSUPPORTED;
break;
@ -1834,15 +1869,6 @@ sdstd_check_errs(sdioh_info_t *sdioh_info, uint32 cmd, uint32 arg)
return ERROR;
}
#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
*/
@ -1988,12 +2014,6 @@ sdstd_host_init(sdioh_info_t *sd)
__FUNCTION__));
sd->controller_type = SDIOH_TYPE_JMICRON;
detect_slots = TRUE;
#ifdef BCMINTERNAL
} else if ((OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_VID, 4) & 0xFFFF) == VENDOR_JINVANI) {
sd_info(("%s: Found Jinvani Standard SDIO Host Controller\n", __FUNCTION__));
detect_slots = FALSE;
sd->controller_type = SDIOH_TYPE_JINVANI_GOLD;
#endif /* BCMINTERNAL */
} else {
return ERROR;
}
@ -2127,46 +2147,6 @@ sdstd_host_init(sdioh_info_t *sd)
sdstd_set_dma_mode(sd, sd->sd_dma_mode);
#if defined(BCMINTERNAL)
if (OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_VID, 4) ==
((SDIOH_FPGA_ID << 16) | VENDOR_BROADCOM)) {
sd_err(("* * * SDIO20H FPGA Build Date: 0x%04x\n", sdstd_rreg(sd, 0x110)));
}
if (GFIELD(sd->caps, CAP_MAXBLOCK) == 0x3) {
sd_info(("SD HOST CAPS: Max block size is INVALID\n"));
} else {
sd_info(("SD HOST CAPS: Max block size is %d bytes\n",
512 << GFIELD(sd->caps, CAP_MAXBLOCK)));
}
sd_info(("SD HOST CAPS: 64-bit DMA is %ssupported.\n",
GFIELD(sd->caps, CAP_64BIT_HOST) ? "" : "not "));
sd_info(("SD HOST CAPS: Suspend/Resume is %ssupported.\n",
GFIELD(sd->caps, CAP_SUSPEND) ? "" : "not "));
sd_err(("SD HOST CAPS: SD Host supports "));
if (GFIELD(sd->caps, CAP_VOLT_3_3)) {
sd_err(("3.3V"));
if (GFIELD(sd->curr_caps, CAP_CURR_3_3)) {
sd_err(("@%dmA\n", 4*GFIELD(sd->curr_caps, CAP_CURR_3_3)));
}
}
if (GFIELD(sd->caps, CAP_VOLT_3_0)) {
sd_err((", 3.0V"));
if (GFIELD(sd->curr_caps, CAP_CURR_3_0)) {
sd_err(("@%dmA\n", 4*GFIELD(sd->curr_caps, CAP_CURR_3_0)));
}
}
if (GFIELD(sd->caps, CAP_VOLT_1_8)) {
sd_err((", 1.8V"));
if (GFIELD(sd->curr_caps, CAP_CURR_1_8)) {
sd_err(("@%dmA\n", 4*GFIELD(sd->curr_caps, CAP_CURR_1_8)));
}
}
sd_err(("\n"));
#endif /* defined(BCMINTERNAL) */
sdstd_reset(sd, 1, 0);
/* Read SD4/SD1 mode */
@ -2257,15 +2237,6 @@ sdstd_client_init(sdioh_info_t *sd)
uint32 regdata;
uint16 powerstat = 0;
#ifdef BCMINTERNAL
#ifdef NOTUSED
/* Handy routine to dump capabilities. */
static char caps_buf[500];
parse_caps(sd->caps, caps_buf, 500);
sd_err((caps_buf));
#endif /* NOTUSED */
#endif /* BCMINTERNAL */
sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot));
/* Clear any pending ints */
@ -2433,11 +2404,24 @@ sdstd_client_init(sdioh_info_t *sd)
static int
sdstd_clock_wrapper(sdioh_info_t *sd)
{
uint ret = 0;
sd_trace(("%s:Enter\n", __FUNCTION__));
/* After configuring for High-Speed mode, set the desired clock rate. */
sdstd_set_highspeed_mode(sd, (bool)sd_hiok);
if (FALSE == sdstd_start_clock(sd, (uint16)sd_divisor)) {
#ifdef BCMFPGA_HW
/*
* To make the SDIO clock 6.25Mhz for FPGA divide the
* standard clock with 8 insted of default 2. 50Mhz/8 = 6.25Mhz
* sdstd_clock_wrapper() is used to start clock for default and
* high speed only.
*/
sd_err(("%s set 6.25Mhz clock speed for FPGA default or high speed\n", __FUNCTION__));
ret = sdstd_start_clock(sd, ((uint16)sd_divisor * 4));
#else
ret = sdstd_start_clock(sd, (uint16)sd_divisor);
#endif /* BCMFPGA_HW */
if (ret != TRUE) {
sd_err(("sdstd_start_clock failed\n"));
return ERROR;
}
@ -2693,6 +2677,7 @@ sdstd_3_set_highspeed_uhsi_mode(sdioh_info_t *sd, int sd3ClkMode)
uint8 hc_reg8;
uint16 val1 = 0, presetval = 0;
uint32 regdata;
uint32 ret = 0;
sd3_trace(("sd3: %s:enter:clkmode:%d\n", __FUNCTION__, sd3ClkMode));
@ -2780,9 +2765,19 @@ sdstd_3_set_highspeed_uhsi_mode(sdioh_info_t *sd, int sd3ClkMode)
sdstd_wreg16(sd, SD3_HostCntrl2, val1);
sd_err(("%s:HostCtrl2 final value:0x%x\n", __FUNCTION__, val1));
#ifdef BCMFPGA_HW
/*
* To make the SDIO clock 6.25Mhz for FPGA divide the
* standard clock with 0x20. 208Mhz/32 = 6.25Mhz
* this function is invoked to start clock for UHSI mode only
*/
sd_err(("%s set 6.25Mhz clock speed for UHSI speed\n", __FUNCTION__));
ret = sdstd_start_clock(sd, 0x20);
#else
ret = sdstd_start_clock(sd, GFIELD(presetval, PRESET_CLK_DIV));
#endif /* BCMFPGA_HW */
if (ret != TRUE) {
/* start clock : clk will be enabled inside. */
if (FALSE == sdstd_start_clock(sd, GFIELD(presetval, PRESET_CLK_DIV))) {
sd_err(("sdstd_start_clock failed\n"));
return ERROR;
}
@ -3143,16 +3138,6 @@ sdstd_set_highspeed_mode(sdioh_info_t *sd, bool HSMode)
reg8 = sdstd_rreg8(sd, SD_HostCntrl);
#ifdef BCMINTERNAL
/* The Jinvani SD Gold Host forces the highest clock rate in high-speed mode */
/* Only enable high-speed mode if the SD clock divisor is 1. */
if (sd->controller_type == SDIOH_TYPE_JINVANI_GOLD) {
if (sd_divisor != 1) {
HSMode = FALSE;
}
}
#endif /* BCMINTERNAL */
if (HSMode == TRUE) {
if (sd_hiok && (GFIELD(sd->caps, CAP_HIGHSPEED)) == 0) {
sd_err(("Host Controller does not support hi-speed mode.\n"));
@ -3409,61 +3394,6 @@ print_regs(sdioh_info_t *sd)
}
#endif /* BCMDBG */
#ifdef BCMINTERNAL
#ifdef NOTUSED
static int
parse_state(uint32 state, char *buf, int len)
{
char *data = buf;
sd_err(("Parsing state 0x%x\n", state));
if (!len) {
return (0);
}
data += sprintf(data, "cmd_inhibit %d\n", GFIELD(state, PRES_CMD_INHIBIT));
data += sprintf(data, "dat_inhibit %d\n", GFIELD(state, PRES_DAT_INHIBIT));
data += sprintf(data, "dat_busy %d\n", GFIELD(state, PRES_DAT_BUSY));
data += sprintf(data, "write_active %d\n", GFIELD(state, PRES_WRITE_ACTIVE));
data += sprintf(data, "read_active %d\n", GFIELD(state, PRES_READ_ACTIVE));
data += sprintf(data, "write_data_rdy %d\n", GFIELD(state, PRES_WRITE_DATA_RDY));
data += sprintf(data, "read_data_rdy %d\n", GFIELD(state, PRES_READ_DATA_RDY));
data += sprintf(data, "card_present %d\n", GFIELD(state, PRES_CARD_PRESENT));
data += sprintf(data, "card_stable %d\n", GFIELD(state, PRES_CARD_STABLE));
data += sprintf(data, "card_present_raw %d\n", GFIELD(state, PRES_CARD_PRESENT_RAW));
data += sprintf(data, "write_enabled %d\n", GFIELD(state, PRES_WRITE_ENABLED));
data += sprintf(data, "cmd_signal %d\n", GFIELD(state, PRES_CMD_SIGNAL));
return (data - buf);
}
static int
parse_caps(uint32 cap, char *buf, int len)
{
int block = 0xbeef;
char *data = buf;
data += sprintf(data, "TimeOut Clock Freq:\t%d\n", GFIELD(cap, CAP_TO_CLKFREQ));
data += sprintf(data, "TimeOut Clock Unit:\t%d\n", GFIELD(cap, CAP_TO_CLKUNIT));
data += sprintf(data, "Base Clock:\t\t%d\n", GFIELD(cap, CAP_BASECLK));
switch (GFIELD(cap, CAP_MAXBLOCK)) {
case 0: block = 512; break;
case 1: block = 1024; break;
case 2: block = 2048; break;
case 3: block = 0; break;
}
data += sprintf(data, "Max Block Size:\t\t%d\n", block);
data += sprintf(data, "Support High Speed:\t%d\n", GFIELD(cap, CAP_HIGHSPEED));
data += sprintf(data, "Support DMA:\t\t%d\n", GFIELD(cap, CAP_DMA));
data += sprintf(data, "Support Suspend:\t%d\n", GFIELD(cap, CAP_SUSPEND));
data += sprintf(data, "Support 3.3 Volts:\t%d\n", GFIELD(cap, CAP_VOLT_3_3));
data += sprintf(data, "Support 3.0 Volts:\t%d\n", GFIELD(cap, CAP_VOLT_3_0));
data += sprintf(data, "Support 1.8 Volts:\t%d\n", GFIELD(cap, CAP_VOLT_1_8));
return (data - buf);
}
#endif /* NOTUSED */
#endif /* BCMINTERNAL */
/* XXX Per SDIO Host Controller Spec section 3.2.1
Note: for 2.x HC, new_sd_divisor should be a power of 2, but for 3.0
HC, new_sd_divisor should be a multiple of 2.
@ -3507,11 +3437,6 @@ sdstd_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor)
new_sd_divisor = 256;
divisor = (new_sd_divisor >> 1) << 8;
}
#ifdef BCMINTERNAL
if (sd->controller_type == SDIOH_TYPE_JINVANI_GOLD) {
divisor = (new_sd_divisor >> 2) << 8;
}
#endif /* BCMINTERNAL */
sd_info(("Clock control is 0x%x\n", sdstd_rreg16(sd, SD_ClockCntrl)));
if (sd->host_UHSISupported) {
@ -3848,6 +3773,7 @@ voltsel:
* val1 = SFIELD(val1, HOSTCtrl2_1_8SIG_EN, 1);
* sdstd_wreg16(sd, SD3_HostCntrl2, val1);
*/
sd_info(("%s: Not sdio3.0: host_UHSISupported: %d; HC volts=%d\n",
__FUNCTION__, sd->host_UHSISupported, volts));
}
@ -5143,30 +5069,6 @@ sdioh_sdio_reset(sdioh_info_t *si)
return sdstd_client_init(si);
}
#ifdef BCMINTERNAL
#ifdef NOTUSED
static void
cis_fetch(sdioh_info_t *sd, int func, char *data, int len)
{
int count;
int offset;
char *end = data + len;
uint32 foo;
for (count = 0; count < 512 && data < end; count++) {
offset = sd->func_cis_ptr[func] + count;
if (sdstd_card_regread (sd, func, offset, 1, &foo) < 0) {
sd_err(("%s: regread failed\n", __FUNCTION__));
return;
}
data += sprintf(data, "%.2x ", foo & 0xff);
if (((count+1) % 16) == 0)
data += sprintf(data, "\n");
}
}
#endif /* NOTUSED */
#endif /* BCMINTERNAL */
static void
sd_map_dma(sdioh_info_t * sd)
{

View File

@ -1,7 +1,7 @@
/*
* 'Standard' SDIO HOST CONTROLLER driver
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -20,7 +20,7 @@
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmsdstd.h 833030 2019-08-02 17:22:42Z jl904071 $
* $Id: bcmsdstd.h 833030 2019-08-02 17:22:42Z $
*/
#ifndef _BCM_SD_STD_H
#define _BCM_SD_STD_H
@ -80,9 +80,6 @@ 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 */

View File

@ -1,7 +1,7 @@
/*
* 'Standard' SDIO HOST CONTROLLER driver - linux portion
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -515,8 +515,15 @@ static struct pci_device_id bcmsdh_pci_devid[] __devinitdata = {
class: 0,
class_mask: 0,
driver_data: 0,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0))
override_only: 0,
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) */
},
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0))
{ 0, 0, 0, 0, 0, 0, 0, 0}
#else
{ 0, 0, 0, 0, 0, 0, 0}
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) */
};
MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* Broadcom Secure Standard Library.
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -28,6 +28,7 @@
#else /* BCMDRIVER */
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#endif /* else BCMDRIVER */
#include <bcmstdlib_s.h>
@ -60,8 +61,8 @@
#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
@ -73,7 +74,7 @@
* than RSIZE_MAX, writes destsz zero bytes into the dest object.
*/
int
memmove_s(void *dest, size_t destsz, const void *src, size_t n)
BCMPOSTTRAPFN(memmove_s)(void *dest, size_t destsz, const void *src, size_t n)
{
int err = BCME_OK;
@ -88,13 +89,13 @@ memmove_s(void *dest, size_t destsz, const void *src, size_t n)
}
if (destsz < n) {
memset(dest, 0, destsz);
bzero(dest, destsz);
err = BCME_BADLEN;
goto exit;
}
if ((!src) || (((const char *)src + n) < (const char *)src)) {
memset(dest, 0, destsz);
bzero(dest, destsz);
err = BCME_BADARG;
goto exit;
}
@ -132,20 +133,20 @@ BCMPOSTTRAPFN(memcpy_s)(void *dest, size_t destsz, const void *src, size_t n)
}
if (destsz < n) {
memset(dest, 0, destsz);
bzero(dest, destsz);
err = BCME_BADLEN;
goto exit;
}
if ((!s) || ((s + n) < s)) {
memset(dest, 0, destsz);
bzero(dest, destsz);
err = BCME_BADARG;
goto exit;
}
/* overlap checking between dest and src */
if (!(((d + destsz) <= s) || (d >= (s + n)))) {
memset(dest, 0, destsz);
bzero(dest, destsz);
err = BCME_BADARG;
goto exit;
}
@ -204,7 +205,7 @@ exit:
* of course, the buffer size is zero). It does not pad
* out the result like strncpy() does.
*/
size_t strlcpy(char *dest, const char *src, size_t size)
size_t BCMPOSTTRAPFN(strlcpy)(char *dest, const char *src, size_t size)
{
size_t i;

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
* Contents are wifi-specific, used by any kernel or app-level
* software that might want wifi things as it grows.
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -29,7 +29,9 @@
#ifdef BCMDRIVER
#include <osl.h>
#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
#ifndef tolower
#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
#endif
#else
#include <stdio.h>
#include <stdlib.h>
@ -47,6 +49,7 @@
#endif
#include <802.11.h>
#include <802.11ac.h>
/* Definitions for D11AC capable (80MHz+) Chanspec type */
@ -184,6 +187,13 @@ static const uint8 wf_5g_160m_chans[] = {
#define WFC_BW_EQ(bw, val) (FALSE)
#endif
/* compare bandwidth based on WFC_NON_CONT_CHAN */
#ifdef WFC_NON_CONT_CHAN
#define WFC_NCBW_EQ(bw, val) WFC_2VALS_EQ(bw, val)
#else
#define WFC_NCBW_EQ(bw, val) (FALSE)
#endif
static void wf_chanspec_iter_firstchan(wf_chanspec_iter_t *iter);
static chanspec_bw_t wf_iter_next_bw(chanspec_bw_t bw);
static bool wf_chanspec_iter_next_2g(wf_chanspec_iter_t *iter);
@ -383,6 +393,88 @@ channel_6g_320mhz_to_id(uint ch)
return -1;
}
/**
* This function returns the the 5GHz 80MHz center channel for the given chanspec 80MHz ID
*
* @param chan_80MHz_id 80MHz chanspec ID
*
* @return Return the center channel number, or 0 on error.
*
*/
static uint8
wf_chspec_5G_id80_to_ch(uint8 chan_80MHz_id)
{
if (chan_80MHz_id < WF_NUM_5G_80M_CHANS) {
return wf_5g_80m_chans[chan_80MHz_id];
}
return 0;
}
/**
* This function returns the the 6GHz 80MHz center channel for the given chanspec 80MHz ID
*
* @param chan_80MHz_id 80MHz chanspec ID
*
* @return Return the center channel number, or 0 on error.
*
*/
static uint8
wf_chspec_6G_id80_to_ch(uint8 chan_80MHz_id)
{
uint8 ch = 0;
if (chan_80MHz_id < WF_NUM_6G_80M_CHANS) {
/* The 6GHz center channels have a spacing of 16
* starting from the first 80MHz center
*/
ch = CH_MIN_6G_80M_CHANNEL + (chan_80MHz_id * 16);
}
return ch;
}
/**
* This function returns the the 5GHz 160MHz center channel for the given chanspec 160MHz ID
*
* @param chan_160MHz_id 160MHz chanspec ID
*
* @return Return the center channel number, or 0 on error.
*
*/
static uint8
wf_chspec_5G_id160_to_ch(uint8 chan_160MHz_id)
{
if (chan_160MHz_id < WF_NUM_5G_160M_CHANS) {
return wf_5g_160m_chans[chan_160MHz_id];
}
return 0;
}
/**
* This function returns the the 6GHz 160MHz center channel for the given chanspec 160MHz ID
*
* @param chan_160MHz_id 160MHz chanspec ID
*
* @return Return the center channel number, or 0 on error.
*
*/
static uint8
wf_chspec_6G_id160_to_ch(uint8 chan_160MHz_id)
{
uint8 ch = 0;
if (chan_160MHz_id < WF_NUM_6G_160M_CHANS) {
/* The 6GHz center channels have a spacing of 32
* starting from the first 160MHz center
*/
ch = CH_MIN_6G_160M_CHANNEL + (chan_160MHz_id * 32);
}
return ch;
}
/**
* This function returns the the 6GHz 240MHz center channel for the given chanspec 240MHz ID
*
@ -521,6 +613,24 @@ wf_chspec_ntoa(chanspec_t chspec, char *buf)
/* bandwidth and primary20 sideband */
if (CHSPEC_IS20(chspec)) {
snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, pri_chan);
} else if (CHSPEC_IS8080(chspec)) {
/* 80+80 */
uint ch0;
uint ch1;
/* get the center channels for each frequency segment */
if (CHSPEC_IS5G(chspec)) {
ch0 = wf_chspec_5G_id80_to_ch(CHSPEC_CHAN0(chspec));
ch1 = wf_chspec_5G_id80_to_ch(CHSPEC_CHAN1(chspec));
} else if (CHSPEC_IS6G(chspec)) {
ch0 = wf_chspec_6G_id80_to_ch(CHSPEC_CHAN0(chspec));
ch1 = wf_chspec_6G_id80_to_ch(CHSPEC_CHAN1(chspec));
} else {
return NULL;
}
/* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */
snprintf(buf, CHANSPEC_STR_LEN, "%s%d/80+80/%d-%d", band, pri_chan, ch0, ch1);
} else if (CHSPEC_IS240(chspec)) {
/* 240 */
const char *bw;
@ -535,6 +645,24 @@ wf_chspec_ntoa(chanspec_t chspec, char *buf)
bw = wf_chspec_to_bw_str(chspec);
snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, pri_chan, bw);
} else if (CHSPEC_IS160160(chspec)) {
/* 160+160 */
uint ch0;
uint ch1;
/* get the center channels for each frequency segment */
if (CHSPEC_IS5G(chspec)) {
ch0 = wf_chspec_5G_id160_to_ch(CHSPEC_CHAN0(chspec));
ch1 = wf_chspec_5G_id160_to_ch(CHSPEC_CHAN1(chspec));
} else if (CHSPEC_IS6G(chspec)) {
ch0 = wf_chspec_6G_id160_to_ch(CHSPEC_CHAN0(chspec));
ch1 = wf_chspec_6G_id160_to_ch(CHSPEC_CHAN1(chspec));
} else {
return NULL;
}
/* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */
snprintf(buf, CHANSPEC_STR_LEN, "%s%d/160+160/%d-%d", band, pri_chan, ch0, ch1);
} else {
const char *bw;
const char *sb = "";
@ -796,6 +924,40 @@ wf_chspec_malformed(chanspec_t chanspec)
} else {
return TRUE;
}
} else if (WFC_NCBW_EQ(chspec_bw, WL_CHANSPEC_BW_160160)) {
uint ch0_id, ch1_id;
ch0_id = CHSPEC_CHAN0(chanspec);
ch1_id = CHSPEC_CHAN1(chanspec);
/* channel IDs in 160+160 must be in range */
if (CHSPEC_IS5G(chanspec) &&
(ch0_id >= WF_NUM_5G_160M_CHANS || ch1_id >= WF_NUM_5G_160M_CHANS)) {
/* bad 160MHz channel ID for the band */
return TRUE;
}
if (CHSPEC_IS6G(chanspec) &&
(ch0_id >= WF_NUM_6G_160M_CHANS || ch1_id >= WF_NUM_6G_160M_CHANS)) {
/* bad 160MHz channel ID for the band */
return TRUE;
}
} else if (WFC_NCBW_EQ(chspec_bw, WL_CHANSPEC_BW_8080)) {
uint ch0_id, ch1_id;
ch0_id = CHSPEC_CHAN0(chanspec);
ch1_id = CHSPEC_CHAN1(chanspec);
/* channel IDs in 80+80 must be in range */
if (CHSPEC_IS5G(chanspec) &&
(ch0_id >= WF_NUM_5G_80M_CHANS || ch1_id >= WF_NUM_5G_80M_CHANS)) {
/* bad 80MHz channel ID for the band */
return TRUE;
}
if (CHSPEC_IS6G(chanspec) &&
(ch0_id >= WF_NUM_6G_80M_CHANS || ch1_id >= WF_NUM_6G_80M_CHANS)) {
/* bad 80MHz channel ID for the band */
return TRUE;
}
} else if (chspec_bw == WL_CHANSPEC_BW_20 || chspec_bw == WL_CHANSPEC_BW_40 ||
chspec_bw == WL_CHANSPEC_BW_80 || chspec_bw == WL_CHANSPEC_BW_160) {
@ -827,13 +989,15 @@ wf_chspec_malformed(chanspec_t chanspec)
} else if (chspec_bw == WL_CHANSPEC_BW_40) {
if (chspec_sb > WL_CHANSPEC_CTL_SB_LLU)
return TRUE;
} else if (chspec_bw == WL_CHANSPEC_BW_80) {
} else if (chspec_bw == WL_CHANSPEC_BW_80 ||
WFC_NCBW_EQ(chspec_bw, WL_CHANSPEC_BW_8080)) {
/* both 80MHz and 80+80MHz use 80MHz side bands.
* 80+80 SB info is relative to the primary 80MHz sub-band.
*/
if (chspec_sb > WL_CHANSPEC_CTL_SB_LUU)
return TRUE;
} else if (chspec_bw == WL_CHANSPEC_BW_160) {
} else if (chspec_bw == WL_CHANSPEC_BW_160 ||
WFC_NCBW_EQ(chspec_bw, WL_CHANSPEC_BW_160160)) {
ASSERT(chspec_sb <= WL_CHANSPEC_CTL_SB_UUU);
} else if (WFC_BW_EQ(chspec_bw, WL_CHANSPEC_BW_240)) {
/* FIXME: define the max sideband index */
@ -918,6 +1082,45 @@ wf_chspec_valid(chanspec_t chanspec)
return wf_valid_320MHz_center_chan(chspec_ch, chspec_band);
} else if (WFC_NCBW_EQ(chspec_bw, WL_CHANSPEC_BW_8080)) {
uint16 ch0 = 0;
uint16 ch1 = 0;
/* get the center channels for each frequency segment */
if (CHSPEC_IS5G(chanspec)) {
ch0 = wf_chspec_5G_id80_to_ch(CHSPEC_CHAN0(chanspec));
ch1 = wf_chspec_5G_id80_to_ch(CHSPEC_CHAN1(chanspec));
} else if (CHSPEC_IS6G(chanspec)) {
ch0 = wf_chspec_6G_id80_to_ch(CHSPEC_CHAN0(chanspec));
ch1 = wf_chspec_6G_id80_to_ch(CHSPEC_CHAN1(chanspec));
} else {
return FALSE;
}
/* the two channels must be separated by more than 80MHz by VHT req */
if ((ch1 > ch0 + CH_80MHZ_APART) ||
(ch0 > ch1 + CH_80MHZ_APART))
return TRUE;
} else if (WFC_NCBW_EQ(chspec_bw, WL_CHANSPEC_BW_160160)) {
uint16 ch0 = 0;
uint16 ch1 = 0;
/* get the center channels for each frequency segment */
if (CHSPEC_IS5G(chanspec)) {
ch0 = wf_chspec_5G_id160_to_ch(CHSPEC_CHAN0(chanspec));
ch1 = wf_chspec_5G_id160_to_ch(CHSPEC_CHAN1(chanspec));
} else if (CHSPEC_IS6G(chanspec)) {
ch0 = wf_chspec_6G_id160_to_ch(CHSPEC_CHAN0(chanspec));
ch1 = wf_chspec_6G_id160_to_ch(CHSPEC_CHAN1(chanspec));
} else {
return FALSE;
}
/* the two channels must be separated by more than 160MHz by EHT req */
if ((ch1 > ch0 + CH_160MHZ_APART) ||
(ch0 > ch1 + CH_160MHZ_APART)) {
return TRUE;
}
}
return FALSE;
@ -2197,7 +2400,35 @@ wf_chspec_primary20_chan(chanspec_t chspec)
sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT;
}
if (CHSPEC_IS240(chspec)) {
if (CHSPEC_IS8080(chspec)) {
/* For an 80+80 MHz channel, the sideband 'sb' field is an 80 MHz sideband
* (LL, LU, UL, LU) for the 80 MHz frequency segment 0.
*/
/* use bw 80MHz for the primary channel lookup */
bw = WL_CHANSPEC_BW_80;
/* convert from channel index to channel number */
if (CHSPEC_IS5G(chspec)) {
center_chan = wf_chspec_5G_id80_to_ch(CHSPEC_CHAN0(chspec));
} else if (CHSPEC_IS6G(chspec)) {
center_chan = wf_chspec_6G_id80_to_ch(CHSPEC_CHAN0(chspec));
}
} else if (CHSPEC_IS160160(chspec)) {
/* For an 160+160 MHz channel, the sideband 'sb' field is an 160MHz sideband
* for the 160 MHz frequency segment 0.
*/
/* use bw 160MHz for the primary channel lookup */
bw = WL_CHANSPEC_BW_160;
/* convert from channel index to channel number */
if (CHSPEC_IS5G(chspec)) {
center_chan = wf_chspec_5G_id160_to_ch(CHSPEC_CHAN0(chspec));
} else if (CHSPEC_IS6G(chspec)) {
center_chan = wf_chspec_6G_id160_to_ch(CHSPEC_CHAN0(chspec));
}
} else if (CHSPEC_IS240(chspec)) {
/* use bw 240MHz for the primary channel lookup */
bw = WL_CHANSPEC_BW_240;
@ -2345,7 +2576,7 @@ wf_chspec_primary40_chspec(chanspec_t chspec)
ASSERT(!wf_chspec_malformed(chspec));
/* if the chanspec is > 80MHz, use the helper routine to find the primary 80 MHz channel */
if (CHSPEC_IS160(chspec)) {
if (CHSPEC_IS8080(chspec) || CHSPEC_IS160(chspec)) {
chspec = wf_chspec_primary80_chspec(chspec);
}
@ -2373,6 +2604,29 @@ wf_chspec_primary40_chspec(chanspec_t chspec)
return chspec40;
}
/**
* Return the chanspec band for a given frequency.
*
* @param freq frequency in MHz of the channel center
*
* @return Returns chanspec band of frequency (chanspec_band_t)
*/
chanspec_band_t
wf_mhz2chanspec_band(uint freq)
{
chanspec_band_t band = INVCHANSPEC;
if (freq >= 2400u && freq <= 2500u) {
band = WL_CHANSPEC_BAND_2G;
} else if (freq >= 5000u && freq < 5935u) {
band = WL_CHANSPEC_BAND_5G;
} else if (freq >= 5935u && freq <= 7205u) {
band = WL_CHANSPEC_BAND_6G;
}
return band;
}
/**
* Return the channel number for a given frequency and base frequency.
*
@ -2674,7 +2928,23 @@ wf_chspec_primary80_chspec(chanspec_t chspec)
if (CHSPEC_IS80(chspec)) {
chspec80 = chspec;
} else if (CHSPEC_IS160(chspec)) {
}
else if (CHSPEC_IS8080(chspec)) {
sb = CHSPEC_CTL_SB(chspec);
/* primary sub-band is stored in seg0 */
if (CHSPEC_IS5G(chspec)) {
center_chan = wf_chspec_5G_id80_to_ch(CHSPEC_CHAN0(chspec));
} else if (CHSPEC_IS6G(chspec)) {
center_chan = wf_chspec_6G_id80_to_ch(CHSPEC_CHAN0(chspec));
} else {
center_chan = INVCHANNEL;
}
/* Create primary 80MHz chanspec */
chspec80 = (CHSPEC_BAND(chspec) | WL_CHANSPEC_BW_80 | sb | center_chan);
}
else if (CHSPEC_IS160(chspec)) {
center_chan = CHSPEC_CHANNEL(chspec);
sb = CHSPEC_CTL_SB(chspec);
@ -2709,7 +2979,23 @@ wf_chspec_secondary80_chspec(chanspec_t chspec)
ASSERT(!wf_chspec_malformed(chspec));
if (CHSPEC_IS160(chspec)) {
if (CHSPEC_IS8080(chspec)) {
/* secondary sub-band is stored in seg1 */
if (CHSPEC_IS5G(chspec)) {
center_chan = wf_chspec_5G_id80_to_ch(CHSPEC_CHAN1(chspec));
} else if (CHSPEC_IS6G(chspec)) {
center_chan = wf_chspec_6G_id80_to_ch(CHSPEC_CHAN1(chspec));
} else {
center_chan = INVCHANNEL;
}
/* Create secondary 80MHz chanspec */
chspec80 = (CHSPEC_BAND(chspec) |
WL_CHANSPEC_BW_80 |
WL_CHANSPEC_CTL_SB_LL |
center_chan);
}
else if (CHSPEC_IS160(chspec)) {
center_chan = CHSPEC_CHANNEL(chspec);
if (CHSPEC_CTL_SB(chspec) < WL_CHANSPEC_CTL_SB_ULL) {
@ -2916,6 +3202,8 @@ channel_bw_to_width(chanspec_t chspec)
channel_width = VHT_OP_CHAN_WIDTH_80;
else if (CHSPEC_IS160(chspec))
channel_width = VHT_OP_CHAN_WIDTH_160;
else if (CHSPEC_IS8080(chspec))
channel_width = VHT_OP_CHAN_WIDTH_80_80;
else
channel_width = VHT_OP_CHAN_WIDTH_20_40;
@ -2924,11 +3212,6 @@ channel_bw_to_width(chanspec_t chspec)
uint wf_chspec_first_20_sb(chanspec_t chspec)
{
#if defined(WL_BW160MHZ)
if (CHSPEC_IS160(chspec)) {
return LLL_20_SB_160(CHSPEC_CHANNEL(chspec));
} else
#endif
if (CHSPEC_IS80(chspec)) {
return LL_20_SB(CHSPEC_CHANNEL(chspec));
} else if (CHSPEC_IS40(chspec)) {
@ -2949,6 +3232,56 @@ wf_create_chspec_sb(uint sb, uint center_channel, chanspec_bw_t bw, chanspec_ban
return wf_chspec_valid(chspec) ? chspec : INVCHANSPEC;
}
chanspec_t
wf_create_8080MHz_chspec_sb(uint sb, uint chan0, uint chan1, chanspec_band_t band)
{
int chan0_id, chan1_id, seg0, seg1;
chanspec_t chspec;
if (sb > (WL_CHANSPEC_CTL_SB_UUU >> WL_CHANSPEC_CTL_SB_SHIFT)) {
return INVCHANSPEC;
}
/* From here on sb is not an index, but value for SB field */
sb <<= WL_CHANSPEC_CTL_SB_SHIFT;
/* frequency segments need to be non-contiguous, so the channel
* separation needs to be greater than 80MHz
*/
if ((uint)ABS((int)(chan0 - chan1)) <= CH_80MHZ_APART) {
return INVCHANSPEC;
}
if (band == WL_CHANSPEC_BAND_5G) {
chan0_id = channel_80mhz_to_id(chan0);
chan1_id = channel_80mhz_to_id(chan1);
} else if (band == WL_CHANSPEC_BAND_6G) {
chan0_id = channel_6g_80mhz_to_id(chan0);
chan1_id = channel_6g_80mhz_to_id(chan1);
} else {
return INVCHANSPEC;
}
/* make sure the channel numbers were valid */
if ((chan0_id == -1) || (chan1_id == -1)) {
return INVCHANSPEC;
}
/* Optionally swapping channel IDs to make sure that control subchannel
* is in chan0
*/
if (sb < WL_CHANSPEC_CTL_SB_ULL) {
seg0 = chan0_id;
seg1 = chan1_id;
} else {
seg0 = chan1_id;
seg1 = chan0_id;
sb -= WL_CHANSPEC_CTL_SB_ULL;
}
chspec = ((seg0 << WL_CHANSPEC_CHAN0_SHIFT) |
(seg1 << WL_CHANSPEC_CHAN1_SHIFT) |
sb | WL_CHANSPEC_BW_8080 | band);
return wf_chspec_valid(chspec) ? chspec : INVCHANSPEC;
}
chanspec_t
wf_create_160160MHz_chspec_sb(uint sb, uint chan0, uint chan1, chanspec_band_t band)
{

View File

@ -3,7 +3,7 @@
* This file housing the functions use by
* wl driver.
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you

View File

@ -1,607 +0,0 @@
/*
* 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,274 +0,0 @@
/*
* 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,7 +1,7 @@
/*
* Driver O/S-independent utility routines
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -24,10 +24,6 @@
#include <typedefs.h>
#include <bcmdefs.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0))
#include <stdarg.h>
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) */
#ifdef BCMDRIVER
#include <osl.h>
#else /* !BCMDRIVER */
@ -428,14 +424,14 @@ int
bcm_unpack_xtlv_buf(void *ctx, const uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts,
bcm_xtlv_unpack_cbfn_t *cbfn)
{
int res = BCME_OK;
const bcm_xtlv_t *ptlv;
uint16 len;
uint16 type;
int res = BCME_OK;
int size;
const bcm_xtlv_t *ptlv;
int sbuflen = buflen;
const uint8 *data;
int hdr_size;
uint32 sbuflen = buflen;
uint32 hdr_size; /* size of tlv header */
uint32 size; /* size of tlv including header + data */
ASSERT(!buflen || tlv_buf);
ASSERT(!buflen || cbfn);
@ -447,12 +443,11 @@ bcm_unpack_xtlv_buf(void *ctx, const uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opt
bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts);
size = bcm_xtlv_size_for_data(len, opts);
sbuflen -= size;
/* check for buffer overrun */
if (sbuflen < 0) {
if (sbuflen < size) {
break;
}
sbuflen -= size;
if ((res = cbfn(ctx, data, type, len)) != BCME_OK) {
break;

1193
drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dbus.c Executable file → Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Dongle BUS interface for USB, OS independent
*
* Copyright (C) 1999-2016, Broadcom Corporation
*
* Copyright (C) 2022, 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 +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: dbus_usb.c 565557 2015-06-22 19:29:44Z $
* <<Broadcom-WL-IPTag/Dual:>>
*/
/**
@ -43,10 +36,21 @@
#include <bcmdevs.h>
#include <bcmendian.h>
#if defined(BCM_DNGL_EMBEDIMAGE)
#ifdef EMBED_IMAGE_43526a
#include "rtecdc_43526a.h"
#endif /* EMBED_IMAGE_43526a */
#ifdef EMBED_IMAGE_43526b
#include "rtecdc_43526b.h"
#endif /* EMBED_IMAGE_43526b */
#ifdef EMBED_IMAGE_GENERIC
#include "rtecdc.h"
#endif
#endif /* BCM_DNGL_EMBEDIMAGE */
uint dbus_msglevel = DBUS_ERROR_VAL;
module_param(dbus_msglevel, int, 0);
#define USB_DLIMAGE_RETRY_TIMEOUT 3000 /* retry Timeout */
#define USB_SFLASH_DLIMAGE_SPINWAIT 150 /* in unit of ms */
#define USB_SFLASH_DLIMAGE_LIMIT 2000 /* spinwait limit (ms) */
@ -56,6 +60,9 @@ module_param(dbus_msglevel, int, 0);
#define USB_DLGO_SPINWAIT 100 /* wait after DL_GO (ms) */
#define TEST_CHIP 0x4328
/* driver info, initialized when bcmsdh_register is called */
static dbus_driver_t drvinfo = {NULL, NULL, NULL, NULL};
typedef struct {
dbus_pub_t *pub;
@ -83,11 +90,11 @@ static void dbus_usb_rxerr_indicate(void *handle, bool on);
static int dbus_usb_resetcfg(usb_info_t *usbinfo);
#endif
static int dbus_usb_iovar_op(void *bus, const char *name,
void *params, int plen, void *arg, int len, bool set);
void *params, uint plen, void *arg, uint len, bool set);
static int dbus_iovar_process(usb_info_t* usbinfo, const char *name,
void *params, int plen, void *arg, int len, bool set);
void *params, int plen, void *arg, uint len, bool set);
static int dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid,
const char *name, void *params, int plen, void *arg, int len, int val_size);
const char *name, void *params, int plen, void *arg, uint len, int val_size);
static int dhdusb_downloadvars(usb_info_t *bus, void *arg, int len);
static int dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen);
@ -96,6 +103,9 @@ static int dbus_usb_dlneeded(void *bus);
static int dbus_usb_dlrun(void *bus);
static int dbus_usb_rdl_dwnld_state(usb_info_t *usbinfo);
#ifdef BCM_DNGL_EMBEDIMAGE
static bool dbus_usb_device_exists(void *bus);
#endif
/* OS specific */
extern bool dbus_usbos_dl_cmd(void *info, uint8 cmd, void *buffer, int buflen);
@ -135,12 +145,12 @@ enum {
};
const bcm_iovar_t dhdusb_iovars[] = {
{"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
{"dbus_msglevel", IOV_DBUS_MSGLEVEL, 0, IOVT_UINT32, 0 },
{"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 },
{"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
{"usb_lb_txfer", IOV_LOOPBACK_TX, 0, IOVT_BUFFER, 2 * sizeof(int) },
{NULL, 0, 0, 0, 0 }
{"vars", IOV_VARS, 0, 0, IOVT_BUFFER, 0 },
{"dbus_msglevel", IOV_DBUS_MSGLEVEL, 0, 0, IOVT_UINT32, 0 },
{"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, 0, IOVT_BOOL, 0 },
{"membytes", IOV_MEMBYTES, 0, 0, IOVT_BUFFER, 2 * sizeof(int) },
{"usb_lb_txfer", IOV_LOOPBACK_TX, 0, 0, IOVT_BUFFER, 2 * sizeof(int) },
{NULL, 0, 0, 0, 0, 0 }
};
/*
@ -148,10 +158,6 @@ const bcm_iovar_t dhdusb_iovars[] = {
* attach() is not called at probe and detach()
* can be called inside disconnect()
*/
static probe_cb_t probe_cb = NULL;
static disconnect_cb_t disconnect_cb = NULL;
static void *probe_arg = NULL;
static void *disc_arg = NULL;
static dbus_intf_t *g_dbusintf = NULL;
static dbus_intf_t dbus_usb_intf; /** functions called by higher layer DBUS into lower layer */
@ -161,8 +167,10 @@ static dbus_intf_t dbus_usb_intf; /** functions called by higher layer DBUS into
*/
static void *dbus_usb_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs);
static void dbus_usb_detach(dbus_pub_t *pub, void *info);
static void * dbus_usb_probe(void *arg, const char *desc, uint32 bustype,
uint16 bus_no, uint16 slot, uint32 hdrlen);
/* : g_usb_info needed for over-ridden functions
* since the bus argument is actually from dbus_usb_<os>.c.
*/
static void * dbus_usb_probe(uint16 bus_no, uint16 slot, uint32 hdrlen);
/* functions */
@ -171,12 +179,10 @@ static void * dbus_usb_probe(void *arg, const char *desc, uint32 bustype,
* lower level DBUS functions to call (in both dbus_usb.c and dbus_usb_os.c).
*/
static void *
dbus_usb_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no,
uint16 slot, uint32 hdrlen)
dbus_usb_probe(uint16 bus_no, uint16 slot, uint32 hdrlen)
{
DBUSTRACE(("%s(): \n", __FUNCTION__));
if (probe_cb) {
if (drvinfo.probe) {
if (g_dbusintf != NULL) {
/* First, initialize all lower-level functions as default
* so that dbus.c simply calls directly to dbus_usb_os.c.
@ -190,34 +196,60 @@ dbus_usb_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no,
dbus_usb_intf.dlstart = dbus_usb_dlstart;
dbus_usb_intf.dlneeded = dbus_usb_dlneeded;
dbus_usb_intf.dlrun = dbus_usb_dlrun;
#ifdef BCM_DNGL_EMBEDIMAGE
dbus_usb_intf.device_exists = dbus_usb_device_exists;
#endif
}
disc_arg = probe_cb(probe_arg, "DBUS USB", USB_BUS, bus_no, slot, hdrlen);
return disc_arg;
return drvinfo.probe(bus_no, slot, hdrlen);
}
return NULL;
}
static int
dbus_usb_suspend(void *handle)
{
DBUSTRACE(("%s(): \n", __FUNCTION__));
if (drvinfo.suspend)
return drvinfo.suspend(handle);
return BCME_OK;
}
static int
dbus_usb_resume(void *handle)
{
DBUSTRACE(("%s(): \n", __FUNCTION__));
if (drvinfo.resume)
drvinfo.resume(handle);
return 0;
}
static dbus_driver_t dhd_usb_dbus = {
dbus_usb_probe,
dbus_usb_disconnect,
dbus_usb_suspend,
dbus_usb_resume
};
/**
* On return, *intf contains this or lower-level DBUS functions to be called by higher
* level (dbus.c)
*/
int
dbus_bus_register(int vid, int pid, probe_cb_t prcb,
disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2)
dbus_bus_register(dbus_driver_t *driver, dbus_intf_t **intf)
{
int err;
DBUSTRACE(("%s(): \n", __FUNCTION__));
probe_cb = prcb;
disconnect_cb = discb;
probe_arg = prarg;
drvinfo = *driver;
*intf = &dbus_usb_intf;
err = dbus_bus_osl_register(vid, pid, dbus_usb_probe,
dbus_usb_disconnect, NULL, &g_dbusintf, param1, param2);
err = dbus_bus_osl_register(&dhd_usb_dbus, &g_dbusintf);
ASSERT(g_dbusintf);
return err;
@ -293,8 +325,8 @@ void
dbus_usb_disconnect(void *handle)
{
DBUSTRACE(("%s(): \n", __FUNCTION__));
if (disconnect_cb)
disconnect_cb(disc_arg);
if (drvinfo.remove)
drvinfo.remove(handle);
}
/**
@ -433,7 +465,7 @@ dbus_usb_state_change(void *handle, int state)
/** called by higher DBUS level (dbus.c) */
static int
dbus_usb_iovar_op(void *bus, const char *name,
void *params, int plen, void *arg, int len, bool set)
void *params, uint plen, void *arg, uint len, bool set)
{
int err = DBUS_OK;
@ -444,7 +476,7 @@ dbus_usb_iovar_op(void *bus, const char *name,
/** process iovar request from higher DBUS level */
static int
dbus_iovar_process(usb_info_t* usbinfo, 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;
@ -454,7 +486,6 @@ dbus_iovar_process(usb_info_t* usbinfo, const char *name,
DBUSTRACE(("%s: Enter\n", __FUNCTION__));
ASSERT(name);
ASSERT(len >= 0);
/* Get MUST have return space */
ASSERT(set || (arg && len));
@ -500,7 +531,7 @@ exit:
static int
dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
void *params, int plen, void *arg, int len, int val_size)
void *params, int plen, void *arg, uint len, int val_size)
{
int bcmerror = 0;
int32 int_val = 0;
@ -558,7 +589,6 @@ dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid, const
}
break;
case IOV_SVAL(IOV_SET_DOWNLOAD_STATE):
if (bool_val == TRUE) {
@ -700,6 +730,7 @@ dbus_usb_resetcfg(usb_info_t *usbinfo)
dbus_usbos_dl_cmd(osinfo, DL_RESETCFG, &id, sizeof(bootrom_id_t));
/* this wait may not be necessary */
dbus_usbos_wait(osinfo, USB_RESETCFG_SPINWAIT);
return DBUS_OK;
} else {
@ -750,13 +781,8 @@ dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen)
char *bulkchunk = NULL, *dlpos;
rdl_state_t state;
int err = DBUS_OK;
bootrom_id_t id;
uint16 wait, wait_time;
uint32 dl_trunk_size = RDL_CHUNK;
if (BCM4350_CHIP(usbinfo->pub->attrib.devid))
dl_trunk_size = RDL_CHUNK_MAX;
while (!bulkchunk) {
bulkchunk = MALLOC(osh, dl_trunk_size);
if (dl_trunk_size == RDL_CHUNK)
@ -777,10 +803,6 @@ dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen)
dlpos = fw;
dllen = fwlen;
/* Get chip id and rev */
id.chip = usbinfo->pub->attrib.devid;
id.chiprev = usbinfo->pub->attrib.chiprev;
DBUSTRACE(("enter %s: fwlen=%d\n", __FUNCTION__, fwlen));
dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t));
@ -789,6 +811,7 @@ dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen)
while ((sent < dllen)) {
/* Wait until the usb device reports it received all the bytes we sent */
/* add a timeout so we dont wait indefinetly */
if (sent < dllen) {
if ((dllen-sent) < dl_trunk_size)
sendlen = dllen-sent;
@ -813,26 +836,11 @@ dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen)
DBUSTRACE(("%s: sendlen %d\n", __FUNCTION__, sendlen));
}
wait = 0;
wait_time = USB_SFLASH_DLIMAGE_SPINWAIT;
while (!dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state,
sizeof(rdl_state_t))) {
if ((id.chip == 43236) && (id.chiprev == 0)) {
DBUSERR(("%s: 43236a0 SFlash delay, waiting for dongle crc check "
"completion!!!\n", __FUNCTION__));
dbus_usbos_wait(osinfo, wait_time);
wait += wait_time;
if (wait >= USB_SFLASH_DLIMAGE_LIMIT) {
DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__));
err = DBUS_ERR;
goto fail;
break;
}
} else {
DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__));
err = DBUS_ERR;
goto fail;
}
/* Wait for downloaded image crc check to complete in the dongle */
while (!dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t))) {
DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__));
err = DBUS_ERR;
goto fail;
}
state.state = ltoh32(state.state);
@ -888,58 +896,32 @@ dbus_usb_update_chipinfo(usb_info_t *usbinfo, uint32 chip)
bool retval = TRUE;
/* based on the CHIP Id, store the ram size which is needed for NVRAM download. */
switch (chip) {
case 0x4319:
usbinfo->rdlram_size = RDL_RAM_SIZE_4319;
usbinfo->rdlram_base_addr = RDL_RAM_BASE_4319;
break;
case 0x4329:
usbinfo->rdlram_size = RDL_RAM_SIZE_4329;
usbinfo->rdlram_base_addr = RDL_RAM_BASE_4329;
break;
case 43234:
case 43235:
case 43236:
usbinfo->rdlram_size = RDL_RAM_SIZE_43236;
usbinfo->rdlram_base_addr = RDL_RAM_BASE_43236;
break;
case 0x4328:
usbinfo->rdlram_size = RDL_RAM_SIZE_4328;
usbinfo->rdlram_base_addr = RDL_RAM_BASE_4328;
break;
case 0x4322:
usbinfo->rdlram_size = RDL_RAM_SIZE_4322;
usbinfo->rdlram_base_addr = RDL_RAM_BASE_4322;
break;
case 0x4360:
case 0xAA06:
usbinfo->rdlram_size = RDL_RAM_SIZE_4360;
usbinfo->rdlram_base_addr = RDL_RAM_BASE_4360;
break;
case 43242:
case 43243:
usbinfo->rdlram_size = RDL_RAM_SIZE_43242;
usbinfo->rdlram_base_addr = RDL_RAM_BASE_43242;
break;
case 43143:
usbinfo->rdlram_size = RDL_RAM_SIZE_43143;
usbinfo->rdlram_base_addr = RDL_RAM_BASE_43143;
break;
case 0x4350:
case 43556:
case 43558:
case 43569:
usbinfo->rdlram_size = RDL_RAM_SIZE_4350;
usbinfo->rdlram_base_addr = RDL_RAM_BASE_4350;
break;
case BCM4381_CHIP_ID:
usbinfo->rdlram_size = RDL_RAM_SIZE_4381;
usbinfo->rdlram_base_addr = RDL_RAM_BASE_4381;
break;
case BCM4382_CHIP_ID:
usbinfo->rdlram_size = RDL_RAM_SIZE_4382;
usbinfo->rdlram_base_addr = RDL_RAM_BASE_4382;
break;
case POSTBOOT_ID:
break;
@ -1032,6 +1014,9 @@ dbus_usb_dlrun(void *bus)
DBUSTRACE(("%s: Issue DL_GO\n", __FUNCTION__));
dbus_usbos_dl_cmd(osinfo, DL_GO, &state, sizeof(rdl_state_t));
/* : Need this for 4326 for some reason
* Same issue under both Linux/Windows
*/
if (usbinfo->pub->attrib.devid == TEST_CHIP)
dbus_usbos_wait(osinfo, USB_DLGO_SPINWAIT);
@ -1059,111 +1044,12 @@ dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp)
devid = usbinfo->pub->attrib.devid;
crev = usbinfo->pub->attrib.chiprev;
BCM_REFERENCE(crev);
*fw = NULL;
*fwlen = 0;
switch (devid) {
case BCM43236_CHIP_ID:
case BCM43235_CHIP_ID:
case BCM43234_CHIP_ID:
case BCM43238_CHIP_ID: {
if (crev == 3 || crev == 2 || crev == 1) {
#ifdef EMBED_IMAGE_43236b
*fw = (uint8 *)dlarray_43236b;
*fwlen = sizeof(dlarray_43236b);
#endif
}
} break;
case BCM4360_CHIP_ID:
case BCM4352_CHIP_ID:
case BCM43526_CHIP_ID:
#ifdef EMBED_IMAGE_43526a
if (crev <= 2) {
*fw = (uint8 *)dlarray_43526a;
*fwlen = sizeof(dlarray_43526a);
}
#endif
#ifdef EMBED_IMAGE_43526b
if (crev > 2) {
*fw = (uint8 *)dlarray_43526b;
*fwlen = sizeof(dlarray_43526b);
}
#endif
break;
case BCM43242_CHIP_ID:
#ifdef EMBED_IMAGE_43242a0
*fw = (uint8 *)dlarray_43242a0;
*fwlen = sizeof(dlarray_43242a0);
#endif
break;
case BCM43143_CHIP_ID:
#ifdef EMBED_IMAGE_43143a0
*fw = (uint8 *)dlarray_43143a0;
*fwlen = sizeof(dlarray_43143a0);
#endif
#ifdef EMBED_IMAGE_43143b0
*fw = (uint8 *)dlarray_43143b0;
*fwlen = sizeof(dlarray_43143b0);
#endif
break;
case BCM4350_CHIP_ID:
case BCM4354_CHIP_ID:
case BCM43556_CHIP_ID:
case BCM43558_CHIP_ID:
case BCM43566_CHIP_ID:
case BCM43568_CHIP_ID:
case BCM43570_CHIP_ID:
case BCM4358_CHIP_ID:
#ifdef EMBED_IMAGE_4350a0
if (crev == 0) {
*fw = (uint8 *)dlarray_4350a0;
*fwlen = sizeof(dlarray_4350a0);
}
#endif
#ifdef EMBED_IMAGE_4350b0
if (crev == 1) {
*fw = (uint8 *)dlarray_4350b0;
*fwlen = sizeof(dlarray_4350b0);
}
#endif
#ifdef EMBED_IMAGE_4350b1
if (crev == 2) {
*fw = (uint8 *)dlarray_4350b1;
*fwlen = sizeof(dlarray_4350b1);
}
#endif
#ifdef EMBED_IMAGE_43556b1
if (crev == 2) {
*fw = (uint8 *)dlarray_43556b1;
*fwlen = sizeof(dlarray_43556b1);
}
#endif
#ifdef EMBED_IMAGE_4350c0
if (crev == 3) {
*fw = (uint8 *)dlarray_4350c0;
*fwlen = sizeof(dlarray_4350c0);
}
#endif /* EMBED_IMAGE_4350c0 */
#ifdef EMBED_IMAGE_4350c1
if (crev == 4) {
*fw = (uint8 *)dlarray_4350c1;
*fwlen = sizeof(dlarray_4350c1);
}
#endif /* EMBED_IMAGE_4350c1 */
break;
case BCM43569_CHIP_ID:
#ifdef EMBED_IMAGE_43569a0
if (crev == 0) {
*fw = (uint8 *)dlarray_43569a0;
*fwlen = sizeof(dlarray_43569a0);
}
#endif /* EMBED_IMAGE_43569a0 */
break;
default:
#ifdef EMBED_IMAGE_GENERIC
*fw = (uint8 *)dlarray;
@ -1172,3 +1058,31 @@ dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp)
break;
}
} /* dbus_bus_fw_get */
#ifdef BCM_DNGL_EMBEDIMAGE
static bool
dbus_usb_device_exists(void *bus)
{
usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t);
void *osinfo;
bootrom_id_t id;
DBUSTRACE(("%s\n", __FUNCTION__));
if (usbinfo == NULL)
return FALSE;
osinfo = usbinfo->usbosl_info;
ASSERT(osinfo);
id.chip = 0xDEAD;
/* Query device to see if we get a response */
dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t));
usbinfo->pub->attrib.devid = id.chip;
if (id.chip == 0xDEAD)
return FALSE;
else
return TRUE;
}
#endif /* BCM_DNGL_EMBEDIMAGE */

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

View File

@ -1,228 +0,0 @@
/*
* 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,7 +1,7 @@
/*
* Bit packing and Base64 utils for EWP
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you

View File

@ -4,7 +4,7 @@
* Provides type definitions and function prototypes used to link the
* DHD OS, bus, and protocol modules.
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -31,8 +31,6 @@
extern int dbus_up(struct dhd_bus *pub);
extern int dbus_stop(struct dhd_bus *pub);
extern int dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len);
extern int dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len);
/*
* Exported from dhd bus module (dhd_usb, dhd_sdio)
*/
@ -72,6 +70,7 @@ extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp);
#ifdef BCMPCIE
extern uint16 dhd_prot_get_rxbufpost_sz(dhd_pub_t *dhd);
extern uint16 dhd_prot_get_rxbufpost_alloc_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);
@ -111,6 +110,7 @@ extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
/* Add bus dump output to a buffer */
extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
extern void dhd_bus_dump_flowring(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
/* Clear any bus counters */
extern void dhd_bus_clearcounts(dhd_pub_t *dhdp);
@ -198,6 +198,7 @@ enum {
#endif /* D2H_MINIDUMP */
DNGL_TO_HOST_TRAP_ADDR,
HOST_SCB_ADDR, /* update host scb base address to dongle */
HOST_CAP2, /* Host capability 2 flags */
};
typedef void (*dhd_mb_ring_t) (struct dhd_bus *, uint32);
@ -225,7 +226,8 @@ extern void dhd_bus_flow_ring_delete_response(struct dhd_bus *bus, uint16 flowid
extern int dhd_bus_flow_ring_flush_request(struct dhd_bus *bus, void *flow_ring_node);
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 int dhd_bus_schedule_queue(struct dhd_bus *bus, uint16 flow_id, bool txs,
uint32 bound, bool *is_qempty);
#ifdef IDLE_TX_FLOW_MGMT
extern void dhd_bus_flow_ring_resume_response(struct dhd_bus *bus, uint16 flowid, int32 status);
@ -252,8 +254,6 @@ extern void dhd_bus_aer_config(struct dhd_bus *bus);
static INLINE void dhd_bus_aer_config(struct dhd_bus *bus) { }
#endif /* LINUX || linux */
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);
@ -273,7 +273,6 @@ extern void dhd_bus_handle_mb_data(struct dhd_bus *bus, uint32 d2h_mb_data);
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);
@ -298,11 +297,12 @@ 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 bool dhd_bus_get_read_shm(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
#if defined(CONFIG_ARCH_MSM) && defined(CONFIG_SEC_PCIE_L1SS)
extern void dhd_bus_inform_ep_loaded_to_rc(dhd_pub_t *dhdp, bool up);
#endif /* CONFIG_ARCH_MSM */
#endif /* CONFIG_ARCH_MSM && CONFIG_SEC_PCIE_L1SS */
extern int dhd_bus_checkdied(struct dhd_bus *bus, char *data, uint size);
#else
#define dhd_bus_dump_console_buffer(x)
@ -313,7 +313,8 @@ static INLINE bool dhd_bus_check_driver_up(void) { return FALSE; }
static INLINE void dhd_bus_set_linkdown(dhd_pub_t *dhdp, bool val) { }
static 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; }
static INLINE bool dhd_bus_get_read_shm(dhd_pub_t *dhdp) { return 0; }
static 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)
@ -322,14 +323,15 @@ void dhdpcie_get_etd_preserve_logs(dhd_pub_t *dhd, uint8 *ext_trap_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 */
extern uint16 dhd_get_chiprev(struct dhd_bus *bus);
#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);
extern int dhd_bus_set_get_bus_wake(dhd_pub_t * dhd, int set);
#if defined(BCMPCIE)
extern int dhd_bus_set_get_bus_wake_pkt_dump(dhd_pub_t *dhd, int wake_pkt_dump);
#endif /* BCMPCIE */
#endif /* DHD_WAKE_STATUS */
#ifdef BT_OVER_SDIO
@ -348,26 +350,18 @@ 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 bool dhd_bus_is_aspm_enab_rc_ep(struct dhd_bus *bus);
extern void dhd_bus_l1ss_enable_rc_ep(struct dhd_bus *bus, bool enable);
extern bool dhd_bus_is_l1ss_enab_rc_ep(struct dhd_bus *bus);
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 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);
extern void dhdpcie_busbusy_wait(dhd_pub_t *dhdp);
extern int dhd_dump_flowrings(dhd_pub_t *dhdp, char *buf, int buflen);
#endif /* BCMPCIE */
extern bool dhd_bus_force_bt_quiesce_enabled(struct dhd_bus *bus);
@ -414,7 +408,9 @@ 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 */
#ifndef BCMDBUS
extern int dhd_socram_dump(struct dhd_bus *bus);
#endif /* BCMDBUS */
extern int dhdpcie_get_max_eventbufpost(struct dhd_bus *bus);
@ -422,4 +418,15 @@ extern int dhdpcie_get_max_eventbufpost(struct dhd_bus *bus);
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 */
extern bool dhd_bus_init_done(struct dhd_bus *bus);
extern void dhdpcie_db7_trap(struct dhd_bus *bus);
#if defined(NDIS)
void * dhd_bus_get_socram_buf(struct dhd_bus *bus, struct dhd_pub *dhdp);
#endif
void dhd_bus_set_signature_path(struct dhd_bus *bus, char *sig_path);
#endif /* _dhd_bus_h_ */

View File

@ -1,224 +0,0 @@
#ifndef _DHD_BUZZZ_H_INCLUDED_
#define _DHD_BUZZZ_H_INCLUDED_
*/
* 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$
*/
#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

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
#ifdef CCODE_LIST
#ifdef CONFIG_COMPAT
#include <linux/compat.h>
@ -16,7 +16,7 @@
#define CCODE_4359C0
#endif
#if defined(BCMPCIE)
#define CCODE_4375B4
//#define CCODE_4375B4
#endif
#ifdef BCMDBUS
#define CCODE_4358U
@ -232,7 +232,7 @@ const ccode_list_map_t ccode_list_map[] = {
{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"},
{BCM4375_CHIP_ID, 5, ccode_4375b4, ""},
#endif
#ifdef BCMDBUS
{BCM43569_CHIP_ID, 2, ccode_4358u, "XW/0"},
@ -264,9 +264,11 @@ dhd_ccode_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec)
}
}
if (bcmerror && ccode_ww && strlen(ccode_ww)>=4) {
memcpy(cspec->ccode, ccode_ww, 2);
cspec->rev = (int)simple_strtol(ccode_ww+3, NULL, 0);
if (dhd->op_mode != DHD_FLAG_MFG_MODE) {
if (bcmerror && ccode_ww && strlen(ccode_ww)>=4) {
memcpy(cspec->ccode, ccode_ww, 2);
cspec->rev = (int)simple_strtol(ccode_ww+3, NULL, 0);
}
}
return bcmerror;

View File

@ -1,7 +1,7 @@
/*
* DHD Protocol Module for CDC and BDC.
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -71,9 +71,6 @@ typedef struct dhd_prot {
uint16 reqid;
uint8 pending;
uint32 lastcmd;
#ifdef BCMDBUS
uint ctl_completed;
#endif /* BCMDBUS */
uint8 bus_header[BUS_HEADER_LEN];
cdc_ioctl_t msg;
unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN];
@ -89,9 +86,6 @@ dhd_prot_get_ioctl_trans_id(dhd_pub_t *dhdp)
static int
dhdcdc_msg(dhd_pub_t *dhd)
{
#ifdef BCMDBUS
int timeout = 0;
#endif /* BCMDBUS */
int err = 0;
dhd_prot_t *prot = dhd->prot;
int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t);
@ -108,46 +102,8 @@ dhdcdc_msg(dhd_pub_t *dhd)
len = CDC_MAX_MSG_SIZE;
/* Send request */
#ifdef BCMDBUS
prot->ctl_completed = FALSE;
err = dbus_send_ctl(dhd->bus, (void *)&prot->msg, len);
if (err) {
DHD_ERROR(("dbus_send_ctl error=0x%x\n", err));
DHD_OS_WAKE_UNLOCK(dhd);
return err;
}
#else
err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len);
#endif /* BCMDBUS */
#ifdef BCMDBUS
timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed);
if ((!timeout) || (!prot->ctl_completed)) {
DHD_ERROR(("Txctl timeout %d ctl_completed %d\n",
timeout, prot->ctl_completed));
DHD_ERROR(("Txctl wait timed out\n"));
err = -1;
}
#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) {
prot->ctl_completed = FALSE;
if (dbus_poll_intr(dhd->dbus)) {
DHD_ERROR(("dbus_poll_intr not submitted\n"));
} else {
/* interrupt polling is sucessfully submitted. Wait for dongle to send
* interrupt
*/
timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed);
if (!timeout) {
DHD_ERROR(("intr poll wait timed out\n"));
}
}
}
#endif /* defined(BCMDBUS) && defined(INTR_EP_ENABLE) */
DHD_OS_WAKE_UNLOCK(dhd);
return err;
}
@ -155,39 +111,34 @@ dhdcdc_msg(dhd_pub_t *dhd)
static int
dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
{
#ifdef BCMDBUS
int timeout = 0;
#endif /* BCMDBUS */
int ret;
int cdc_len = len + sizeof(cdc_ioctl_t);
dhd_prot_t *prot = dhd->prot;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
/*
* prot->msg is the buffer used to send the ioctl msg in dhdcdc_msg and the same is
* used for receiving the ioctl response.
* As this buffer is not cleared after sending message and before re-using for receive
* operation, problems are seen when bus errors occur.
* Example:- An error is seen on the bus where a 0 byte pkt is received.
* the bus-controller "layer below cdc" does not update the buffer in this 0 byte pkt case.
* bus-controller layer calls the completion callback without any error and with the
* same buffer.(no change)
* This issue is seen on DBUS/USB + FPGA platforms
* In this function if there is no update to the buffer, the stale id field of sent msg
* matches to expected ID and further processing is done thinking that
* proper response is received.
* This is a generic problem and its a good idea to clear the buffer or atleast
* the buffer's key value (ioctl ID within flags field in this case) before re-using it.
*
* To ensure that a new content is indeed received from the bus making flags = 0.
* Note that ID=0 is invalid value.
*/
prot->msg.flags = 0;
do {
#ifdef BCMDBUS
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));
goto done;
}
timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed);
if ((!timeout) || (!prot->ctl_completed)) {
DHD_ERROR(("Rxctl timeout %d ctl_completed %d\n",
timeout, prot->ctl_completed));
ret = -ETIMEDOUT;
goto done;
}
/* 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);
#endif /* BCMDBUS */
if (ret < 0)
break;
} while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id);
@ -197,9 +148,6 @@ dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
ret = len;
}
#ifdef BCMDBUS
done:
#endif /* BCMDBUS */
return ret;
}
@ -230,6 +178,12 @@ dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uin
}
}
if (ifidx >= DHD_MAX_IFS) {
DHD_ERROR(("%s: IF index %d Invalid for the dongle FW\n",
__FUNCTION__, ifidx));
return -EIO;
}
memset(msg, 0, sizeof(cdc_ioctl_t));
#ifdef BCMSPI
@ -343,16 +297,15 @@ dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8
}
}
#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));
}
if (ifidx >= DHD_MAX_IFS) {
DHD_ERROR(("%s: IF index %d Invalid for the dongle FW\n",
__FUNCTION__, ifidx));
return -EIO;
}
memset(msg, 0, sizeof(cdc_ioctl_t));
msg->cmd = htol32(cmd);
@ -403,24 +356,6 @@ done:
return ret;
}
#ifdef BCMDBUS
int
dhd_prot_ctl_complete(dhd_pub_t *dhd)
{
dhd_prot_t *prot;
if (dhd == NULL)
return BCME_ERROR;
prot = dhd->prot;
ASSERT(prot);
prot->ctl_completed = TRUE;
dhd_os_ioctl_resp_wake(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)
@ -516,6 +451,19 @@ dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
#endif
}
void
dhd_prot_counters(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf,
bool print_ringinfo, bool print_pktidinfo)
{
return;
}
void
dhd_bus_counters(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
{
return;
}
/* The FreeBSD PKTPUSH could change the packet buf pinter
so we need to make it changable
*/
@ -640,6 +588,17 @@ exit:
return 0;
}
#ifdef DHD_LOSSLESS_ROAMING
int dhd_update_sdio_data_prio_map(dhd_pub_t *dhdp)
{
const uint8 prio2tid[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
bcopy(prio2tid, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO);
return BCME_OK;
}
#endif // DHD_LOSSLESS_ROAMING
int
dhd_prot_attach(dhd_pub_t *dhd)
{

View File

@ -1,7 +1,7 @@
/*
* Linux cfg80211 driver - Dongle Host Driver (DHD) related
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -57,7 +57,6 @@ static int dhd_dongle_up = FALSE;
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);
@ -66,7 +65,6 @@ static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, s32
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 */
/**
@ -142,20 +140,13 @@ 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);
}
@ -233,7 +224,6 @@ 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)
{
s32 err = 0;
@ -271,7 +261,6 @@ dongle_glom_out:
}
#endif /* BCMSDIO */
#endif /* !CUSTOMER_HW6 */
#endif /* !OEM_ANDROID */
s32
@ -293,12 +282,12 @@ wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
WL_ERR(("roam_off error (%d)\n", err));
goto dongle_rom_out;
}
ROAMOFF_DBG_SAVE(ndev, SET_ROAM_FILS_TOGGLE, roamvar);
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)
@ -494,7 +483,6 @@ static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode)
dongle_filter_out:
return err;
}
#endif /* !CUSTOMER_HW6 */
#endif /* !OEM_ANDROID */
s32 dhd_config_dongle(struct bcm_cfg80211 *cfg)
@ -527,7 +515,6 @@ s32 dhd_config_dongle(struct bcm_cfg80211 *cfg)
}
#ifndef OEM_ANDROID
#ifndef CUSTOMER_HW6
err = wl_dongle_power(ndev, PM_FAST);
if (unlikely(err)) {
WL_ERR(("wl_dongle_power failed\n"));
@ -548,7 +535,6 @@ s32 dhd_config_dongle(struct bcm_cfg80211 *cfg)
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:
@ -595,3 +581,35 @@ done:
DHD_OS_WAKE_UNLOCK(dhd);
return ret;
}
int
dhd_set_wsec_info(dhd_pub_t *dhd, uint32 data, int tag)
{
struct net_device *ndev;
uint32 wsec_info = data;
int ret = BCME_OK;
ndev = dhd_linux_get_primary_netdev(dhd);
if (!ndev) {
WL_ERR(("Cannot find primary netdev\n"));
return -ENODEV;
}
BCM_REFERENCE(wsec_info);
#if defined(WL_CFG80211)
ret = wl_cfg80211_set_wsec_info(ndev, &wsec_info, sizeof(wsec_info), tag);
if (unlikely(ret)) {
WL_ERR(("Set wsec_info tag 0x%04x failed \n", tag));
}
#endif /* WL_CFG80211 */
return ret;
}
#ifdef RPM_FAST_TRIGGER
void
dhd_trigger_rpm_fast(struct bcm_cfg80211 *cfg)
{
dhd_pub_t *dhd = (dhd_pub_t *)cfg->pub;
dhdpcie_trigger_rpm_fast(dhd);
}
#endif /* RPM_FAST_TRIGGER */

View File

@ -1,7 +1,7 @@
/*
* Linux cfg80211 driver - Dongle Host Driver (DHD) related
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -46,4 +46,8 @@ 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);
int dhd_set_wsec_info(dhd_pub_t *dhd, uint32 data, int tag);
#ifdef RPM_FAST_TRIGGER
void dhd_trigger_rpm_fast(struct bcm_cfg80211 *cfg);
#endif /* RPM_FAST_TRIGGER */
#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

@ -1,4 +1,3 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _dhd_config_
#define _dhd_config_
@ -28,7 +27,7 @@
//#define CONFIG_PATH_AUTO_SELECT
#endif
extern char firmware_path[MOD_PARAM_PATHLEN];
#if defined(BCMSDIO) || defined(BCMPCIE)
#if defined(BCMSDIO)
extern uint dhd_rxbound;
extern uint dhd_txbound;
#endif
@ -68,12 +67,6 @@ typedef struct wl_chip_nv_path_list_ctrl {
struct wl_chip_nv_path *m_chip_nv_path_head;
} wl_chip_nv_path_list_ctrl_t;
#define MAX_CTRL_CHANSPECS 256
typedef struct wl_channel_list {
uint32 count;
uint32 channel[MAX_CTRL_CHANSPECS];
} wl_channel_list_t;
typedef struct wmes_param {
int aifsn[AC_COUNT];
int ecwmin[AC_COUNT];
@ -126,7 +119,8 @@ enum war_flags {
FW_REINIT_INCSA = (1 << (1)),
FW_REINIT_EMPTY_SCAN = (1 << (2)),
P2P_AP_MAC_CONFLICT = (1 << (3)),
RESEND_EAPOL_PKT = (1 << (4))
RESEND_EAPOL_PKT = (1 << (4)),
FW_REINIT_RXF0OVFL = (1 << (5))
};
enum in4way_flags {
@ -171,25 +165,27 @@ enum conn_state {
CONN_STATE_AUTH_SAE_M2 = 3,
CONN_STATE_AUTH_SAE_M3 = 4,
CONN_STATE_AUTH_SAE_M4 = 5,
CONN_STATE_REQID = 6,
CONN_STATE_RSPID = 7,
CONN_STATE_WSC_START = 8,
CONN_STATE_WPS_M1 = 9,
CONN_STATE_WPS_M2 = 10,
CONN_STATE_WPS_M3 = 11,
CONN_STATE_WPS_M4 = 12,
CONN_STATE_WPS_M5 = 13,
CONN_STATE_WPS_M6 = 14,
CONN_STATE_WPS_M7 = 15,
CONN_STATE_WPS_M8 = 16,
CONN_STATE_WSC_DONE = 17,
CONN_STATE_4WAY_M1 = 18,
CONN_STATE_4WAY_M2 = 19,
CONN_STATE_4WAY_M3 = 20,
CONN_STATE_4WAY_M4 = 21,
CONN_STATE_CONNECTED = 22,
CONN_STATE_GROUPKEY_M1 = 23,
CONN_STATE_GROUPKEY_M2 = 24,
CONN_STATE_ASSOCIATED = 6,
CONN_STATE_REQID = 7,
CONN_STATE_RSPID = 8,
CONN_STATE_WSC_START = 9,
CONN_STATE_WPS_M1 = 10,
CONN_STATE_WPS_M2 = 11,
CONN_STATE_WPS_M3 = 12,
CONN_STATE_WPS_M4 = 13,
CONN_STATE_WPS_M5 = 14,
CONN_STATE_WPS_M6 = 15,
CONN_STATE_WPS_M7 = 16,
CONN_STATE_WPS_M8 = 17,
CONN_STATE_WSC_DONE = 18,
CONN_STATE_4WAY_M1 = 19,
CONN_STATE_4WAY_M2 = 20,
CONN_STATE_4WAY_M3 = 21,
CONN_STATE_4WAY_M4 = 22,
CONN_STATE_ADD_KEY = 23,
CONN_STATE_CONNECTED = 24,
CONN_STATE_GROUPKEY_M1 = 25,
CONN_STATE_GROUPKEY_M2 = 26,
};
enum enq_pkt_type {
@ -218,10 +214,10 @@ typedef struct dhd_conf {
#endif
wl_chip_nv_path_list_ctrl_t nv_by_chip;
country_list_t *country_head;
int ioctl_ver;
int band;
int bw_cap[2];
wl_country_t cspec;
wl_channel_list_t channels;
uint roam_off;
uint roam_off_suspend;
int roam_trigger[2];
@ -297,6 +293,8 @@ typedef struct dhd_conf {
int d2h_intr_method;
int d2h_intr_control;
int enq_hdr_pkt;
int aspm;
int l1ss;
#endif
int dpc_cpucore;
int rxf_cpucore;
@ -345,6 +343,9 @@ typedef struct dhd_conf {
uint war;
#ifdef WL_EXT_WOWL
uint wowl;
#ifdef BCMDBUS
uint wowl_dngldown;
#endif
#endif
#ifdef GET_CUSTOM_MAC_FROM_CONFIG
char hw_ether[62];
@ -395,23 +396,27 @@ void dhd_conf_get_otp(dhd_pub_t *dhd, bcmsdh_info_t *sdh, si_t *sih);
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);
bool dhd_conf_legacy_otp_chip(dhd_pub_t *dhd);
#endif
#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
#ifdef WL_CFG80211
bool dhd_conf_legacy_chip_check(dhd_pub_t *dhd);
bool dhd_conf_new_chip_check(dhd_pub_t *dhd);
bool dhd_conf_extsae_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, int ifidx, uint cmd, char *name,
int val, int def, bool down);
int dhd_conf_get_band(dhd_pub_t *dhd);
int dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec);
bool dhd_conf_same_country(dhd_pub_t *dhd, char *buf);
int dhd_conf_country(dhd_pub_t *dhd, char *cmd, char *buf);
int dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec);
int dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec);
#ifdef CCODE_LIST
int dhd_ccode_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec);
#endif
int dhd_conf_fix_country(dhd_pub_t *dhd);
bool dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel);
void dhd_conf_set_wme(dhd_pub_t *dhd, int ifidx, int mode);
void dhd_conf_set_mchan_bw(dhd_pub_t *dhd, int go, int source);
void dhd_conf_add_pkt_filter(dhd_pub_t *dhd);
@ -422,6 +427,7 @@ int dhd_conf_set_chiprev(dhd_pub_t *dhd, uint chip, uint chiprev);
uint dhd_conf_get_chip(void *context);
uint dhd_conf_get_chiprev(void *context);
int dhd_conf_get_pm(dhd_pub_t *dhd);
int dhd_conf_reg2args(dhd_pub_t *dhd, char *cmd, bool set, uint32 index, uint32 *val);
int dhd_conf_check_hostsleep(dhd_pub_t *dhd, int cmd, void *buf, int len,
int *hostsleep_set, int *hostsleep_val, int *ret);
void dhd_conf_get_hostsleep(dhd_pub_t *dhd,
@ -440,6 +446,7 @@ void dhd_conf_tput_monitor(dhd_pub_t *dhd);
uint dhd_conf_get_insuspend(dhd_pub_t *dhd, uint mask);
int dhd_conf_set_suspend_resume(dhd_pub_t *dhd, int suspend);
void dhd_conf_postinit_ioctls(dhd_pub_t *dhd);
void dhd_conf_preinit_ioctls_sta(dhd_pub_t *dhd, int ifidx);
int dhd_conf_preinit(dhd_pub_t *dhd);
int dhd_conf_reset(dhd_pub_t *dhd);
int dhd_conf_attach(dhd_pub_t *dhd);
@ -449,7 +456,10 @@ int wl_pattern_atoh(char *src, char *dst);
int dhd_conf_suspend_resume_sta(dhd_pub_t *dhd, int ifidx, int suspend);
/* Add to adjust 802.1x priority */
extern void pktset8021xprio(void *pkt, int prio);
#ifdef BCMSDIO
#if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS)
extern int dhd_bus_sleep(dhd_pub_t *dhdp, bool sleep, uint32 *intstatus);
#endif
#ifdef WL_EXT_WOWL
int dhd_conf_wowl_dngldown(dhd_pub_t *dhd);
#endif
#endif /* _dhd_config_ */

View File

@ -1,7 +1,7 @@
/*
* Broadcom Dongle Host Driver (DHD)
* Broadcom Dongle Host Driver (DHD), Channel State information Module
*
* Copyright (C) 1999-2018, Broadcom.
* Copyright (C) 2023, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -17,12 +17,13 @@
* 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 $
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id$
*/
#ifdef CSI_SUPPORT
#include <osl.h>
#include <bcmutils.h>
@ -38,182 +39,789 @@
#include <dhd.h>
#include <dhd_dbg.h>
#include <dhd_csi.h>
#include <wldev_common.h>
#include <dhd_linux.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 SYNA_ALIGN_BYTES (sizeof(uint32))
#define SYNA_ALIGN_PADDING (SYNA_ALIGN_BYTES -1LL)
#define SYNA_ALIGN_MASK (~SYNA_ALIGN_PADDING)
#define SYNA_ALIGN(value) \
(\
(SYNA_ALIGN_PADDING + ((long long int)(value))) \
& SYNA_ALIGN_MASK \
)
#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \
(ts).tv_nsec / NSEC_PER_USEC)
static const uint8 _gpMAC_zero[6] = {0, 0, 0, 0, 0, 0};
#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)
static int dhd_csi_data_append(uint32 remain_length, uint32 data_length,
const uint8 *pData, struct csi_cfr_node *ptr)
{
int ret = BCME_OK;
bool is_new = TRUE;
cfr_dump_data_t *p_event;
cfr_dump_list_t *ptr, *next, *new;
struct syna_csi_header *pEntry = NULL;
int error_status = 0;
int ret = BCME_OK;
int append_len = 0;
NULL_CHECK(dhd, "dhd is NULL", ret);
if ((!pData) || (!ptr) || (ptr->pNode != ptr)) {
DHD_ERROR(("%s-%d: *Error, invalid parameter, "
"pData=0x%px, ptr=0x%px, pNode=0x%px\n",
__func__, __LINE__,
pData, ptr, ptr?(ptr->pNode):(NULL)));
ret = BCME_BADARG;
goto done;
} else {
pEntry = (struct syna_csi_header *)&(ptr->entry);
error_status = SYNA_CSI_FLAG_ERROR_MASK & pEntry->flags;
}
/* find the append length */
if (remain_length) {
append_len = data_length
- pEntry->data_length
- remain_length;
} else if (pEntry->remain_length) {
append_len = pEntry->remain_length;
} else if (SYNA_CSI_CFR_NODE_FREE_LEN(ptr) >= data_length) {
append_len = data_length;
}
DHD_TRACE(("Enter %s\n", __FUNCTION__));
DHD_TRACE(("%s-%d: data_length=%d, remain=%d, append=%d "
"pNode: pEntry=0x%px, global_id=%d, flags=0x%x, "
"data_len=%d, remain_len=%d, copied_len=%d\n",
__func__, __LINE__,
data_length, remain_length, append_len,
pEntry, pEntry->global_id, pEntry->flags,
pEntry->data_length,
pEntry->remain_length, pEntry->copied_length));
/* copy and update */
if (append_len) {
memcpy((pEntry->data_length + ((uint8 *)pEntry->data)),
pData, append_len);
pEntry->data_length += append_len;
if ((!error_status)
&& (!remain_length)
&& (pEntry->checksum)) {
uint16 checksum = 0;
uint i;
pData = (uint8 *)pEntry->data;
for (i = 0; i < data_length; i++) {
checksum += pData[i];
}
if (checksum != pEntry->checksum) {
DHD_ERROR(("%s-%d: *Error, global_id=%d, "
"checksum=0x%X mismatch to FW=0x%X, "
"data_length=%d, remain_length=%d, "
"pData=0x%px\n",
__func__, __LINE__,
pEntry->global_id,
checksum, pEntry->checksum,
data_length, remain_length, pData));
pEntry->flags |= SYNA_CSI_FLAG_ERROR_CHECKSUM;
}
}
} else if (!error_status) {
DHD_ERROR(("%s-%d: *Error, no data append, "
"total_size=%d, free_len=%d, "
"in_data_length=%d, in_remain_length=%d, "
" Node: global_id=%d, flags=0x%X, "
"data_length=%d, remain_length=%d\n",
__func__, __LINE__,
ptr->total_size,
(int)SYNA_CSI_CFR_NODE_FREE_LEN(ptr),
data_length, remain_length,
pEntry->global_id, pEntry->flags,
pEntry->data_length, pEntry->remain_length));
} else {
DHD_ERROR(("%s-%d: *Warning, error report frame, "
"size=%d, free=%d, "
"in_data_length=%d, in_remain_length=%d, "
" Node: global_id=%d, flags=0x%X%s, "
"data_length=%d, remain_length=%d\n",
__func__, __LINE__,
ptr->total_size,
(int)SYNA_CSI_CFR_NODE_FREE_LEN(ptr),
data_length, remain_length,
pEntry->global_id, pEntry->flags,
(SYNA_CSI_FLAG_ERROR_CHECKSUM & pEntry->flags)
? "(error_checksum)"
: (SYNA_CSI_FLAG_ERROR_NO_ACK & pEntry->flags)
? "(error_no_ack)"
: (SYNA_CSI_FLAG_ERROR_READ & pEntry->flags)
? "(error_read)"
: (SYNA_CSI_FLAG_ERROR_PS & pEntry->flags)
? "(error_ps)"
: (SYNA_CSI_FLAG_ERROR_GENERIC & pEntry->flags)
? "(error_generic)"
: "",
pEntry->data_length, pEntry->remain_length));
}
/* make this as final step to avoid packet early retrieved */
pEntry->copied_length = 0;
pEntry->remain_length = remain_length;
ret = append_len;
done:
return ret;
}
static int dhd_csi_data_new_v0(dhd_pub_t *dhdp, const wl_event_msg_t *event,
struct dhd_cfr_header_v0 *pEvent)
{
struct csi_cfr_node *ptr = NULL;
struct syna_csi_header *pEntry = NULL;
struct timespec64 ts;
dhd_if_t *ifp = NULL;
int ret = BCME_ERROR;
uint total_size = 0;
u32 chanspec = 0;
uint32 remain_length = 0;
uint32 data_length = 0;
uint8 *pData = NULL;
ktime_get_real_ts64(&ts);
total_size = SYNA_CSI_CFR_NODE_LEN + ltoh32_ua(&(pEvent->cfr_dump_length));
ptr = (struct csi_cfr_node *)MALLOCZ(dhdp->osh, total_size);
if (!ptr) {
DHD_ERROR(("%s-%d: *Error, malloc %d for cfr dump list error\n",
__func__, __LINE__, total_size));
return BCME_NOMEM;
}
ptr->pNode = ptr; /* Not useful */
ptr->total_size = total_size;
pEntry = &(ptr->entry);
DHD_TRACE(("%s-%d: ptr=0x%p, ptr=0x%px, pEntry=0x%px, "
"delta=%d, header_size=%d\n",
__func__, __LINE__, ptr, ptr, pEntry,
(int)((uintptr)pEntry - (uintptr)ptr),
(int)SYNA_CSI_CFR_NODE_LEN));
/* process one by one for alignment consideration */
pEntry->magic_flag = CONST_SYNA_CSI_MAGIC_FLAG;
pEntry->version = CONST_SYNA_CSI_COMMON_HEADER_VERSION;
pEntry->format_type = SYNA_CSI_FORMAT_Q8;
pEntry->fc = 0;
if (pEvent->status) {
pEntry->flags |= SYNA_CSI_FLAG_ERROR_GENERIC;
}
memcpy(pEntry->client_ea, pEvent->peer_macaddr, ETHER_ADDR_LEN);
ifp = dhd_get_ifp(dhdp, event->ifidx);
if (!ifp) {
DHD_ERROR(("%s-%d: *Error, get ifp error\n",
__func__, __LINE__));
} else {
memcpy(pEntry->bsscfg_ea, ifp->mac_addr, ETHER_ADDR_LEN);
}
if ((ret = dhd_iovar(dhdp, event->ifidx, "chanspec",
NULL, 0, (char*)&chanspec,
sizeof(chanspec), FALSE) != BCME_OK)) {
pEntry->band = SYNA_CSI_BAND_UNKNOWN;
pEntry->bandwidth = SYNA_CSI_BW_UNKNOWN;
pEntry->channel = 0;
} else {
switch (CHSPEC_BAND(chanspec)) {
case WL_CHANSPEC_BAND_2G:
pEntry->band = SYNA_CSI_BAND_2G;
break;
case WL_CHANSPEC_BAND_5G:
pEntry->band = SYNA_CSI_BAND_5G;
break;
case WL_CHANSPEC_BAND_6G:
pEntry->band = SYNA_CSI_BAND_6G;
break;
default:
pEntry->band = SYNA_CSI_BAND_UNKNOWN;
break;
}
switch (CHSPEC_BW(chanspec)) {
case WL_CHANSPEC_BW_20:
pEntry->bandwidth = SYNA_CSI_BW_20MHz;
break;
case WL_CHANSPEC_BW_40:
pEntry->bandwidth = SYNA_CSI_BW_40MHz;
break;
case WL_CHANSPEC_BW_80:
pEntry->bandwidth = SYNA_CSI_BW_80MHz;
break;
case WL_CHANSPEC_BW_160:
pEntry->bandwidth = SYNA_CSI_BW_160MHz;
break;
case WL_CHANSPEC_BW_320:
pEntry->bandwidth = SYNA_CSI_BW_320MHz;
break;
default:
pEntry->bandwidth = SYNA_CSI_BAND_UNKNOWN;
break;
}
pEntry->channel = CHSPEC_CHANNEL(chanspec);
}
pEntry->num_txstream = pEvent->sts;
pEntry->num_rxchain = pEvent->num_rx;
pEntry->num_subcarrier = ltoh16_ua(&(pEvent->num_carrier));
pEntry->report_tsf = (uint64)TIMESPEC64_TO_US(ts);
pEntry->rssi = pEvent->rssi;
pEntry->data_length = 0;
pEntry->remain_length = 0;
pEntry->copied_length = 0;
DHD_TRACE(("%s-%d: Entry data_size=%d, remain_size=%d, @%llu\n",
__func__, __LINE__,
ltoh32_ua(&(pEvent->cfr_dump_length)),
ltoh32_ua(&(pEvent->remain_length)),
ltoh64_ua(&(pEntry->report_tsf))));
remain_length = ltoh32_ua(&(pEvent->remain_length));
data_length = ltoh32_ua(&(pEvent->cfr_dump_length));
pData = (uint8 *)pEvent->data;
ret = dhd_csi_data_append(remain_length, data_length, pData, ptr);
if (0 <= ret) {
INIT_LIST_HEAD(&(ptr->list));
mutex_lock(&dhdp->csi_lock);
list_add_tail(&(ptr->list), &dhdp->csi_list);
dhdp->csi_count++;
mutex_unlock(&dhdp->csi_lock);
} else {
MFREE(dhdp->osh, ptr, total_size);
}
return ret;
}
static int dhd_csi_data_new_v1(dhd_pub_t *dhdp, const wl_event_msg_t *event,
struct dhd_cfr_header_v1 *pEvent)
{
struct csi_cfr_node *ptr = NULL;
struct syna_csi_header *pEntry = NULL;
dhd_if_t *ifp = NULL;
int ret = BCME_ERROR;
uint total_size = 0;
u32 chanspec = 0;
uint32 remain_length = 0;
uint32 data_length = 0;
uint8 *pData = NULL;
total_size = SYNA_CSI_CFR_NODE_LEN + ltoh32_ua(&(pEvent->cfr_dump_length));
ptr = (struct csi_cfr_node *)MALLOCZ(dhdp->osh, total_size);
if (!ptr) {
DHD_ERROR(("%s-%d: *Error, malloc %d for cfr dump list error\n",
__func__, __LINE__, total_size));
return BCME_NOMEM;
}
ptr->pNode = ptr; /* Not useful */
ptr->total_size = total_size;
pEntry = &(ptr->entry);
DHD_TRACE(("%s-%d: ptr=0x%p, ptr=0x%px, pEntry=0x%px, "
"delta=%d, header_size=%d\n",
__func__, __LINE__, ptr, ptr, pEntry,
(int)((uintptr)pEntry - (uintptr)ptr),
(int)SYNA_CSI_CFR_NODE_LEN));
/* process one by one for alignment consideration */
pEntry->magic_flag = CONST_SYNA_CSI_MAGIC_FLAG;
pEntry->version = CONST_SYNA_CSI_COMMON_HEADER_VERSION;
pEntry->format_type = SYNA_CSI_FORMAT_Q8;
pEntry->fc = pEvent->fc;
if (pEvent->status) {
pEntry->flags |= SYNA_CSI_FLAG_ERROR_GENERIC;
}
memcpy(pEntry->client_ea, pEvent->peer_macaddr, ETHER_ADDR_LEN);
ifp = dhd_get_ifp(dhdp, event->ifidx);
if (!ifp) {
DHD_ERROR(("%s-%d: *Error, get ifp error\n",
__func__, __LINE__));
} else {
memcpy(pEntry->bsscfg_ea, ifp->mac_addr, ETHER_ADDR_LEN);
}
if ((ret = dhd_iovar(dhdp, event->ifidx, "chanspec",
NULL, 0, (char*)&chanspec, sizeof(chanspec), FALSE) != BCME_OK)) {
pEntry->band = SYNA_CSI_BAND_UNKNOWN;
pEntry->bandwidth = SYNA_CSI_BW_UNKNOWN;
pEntry->channel = 0;
} else {
switch (CHSPEC_BAND(chanspec)) {
case WL_CHANSPEC_BAND_2G:
pEntry->band = SYNA_CSI_BAND_2G;
break;
case WL_CHANSPEC_BAND_5G:
pEntry->band = SYNA_CSI_BAND_5G;
break;
case WL_CHANSPEC_BAND_6G:
pEntry->band = SYNA_CSI_BAND_6G;
break;
default:
pEntry->band = SYNA_CSI_BAND_UNKNOWN;
break;
}
switch (CHSPEC_BW(chanspec)) {
case WL_CHANSPEC_BW_20:
pEntry->bandwidth = SYNA_CSI_BW_20MHz;
break;
case WL_CHANSPEC_BW_40:
pEntry->bandwidth = SYNA_CSI_BW_40MHz;
break;
case WL_CHANSPEC_BW_80:
pEntry->bandwidth = SYNA_CSI_BW_80MHz;
break;
case WL_CHANSPEC_BW_160:
pEntry->bandwidth = SYNA_CSI_BW_160MHz;
break;
case WL_CHANSPEC_BW_320:
pEntry->bandwidth = SYNA_CSI_BW_320MHz;
break;
default:
pEntry->bandwidth = SYNA_CSI_BAND_UNKNOWN;
break;
}
pEntry->channel = CHSPEC_CHANNEL(chanspec);
}
pEntry->num_txstream = pEvent->sts;
pEntry->num_rxchain = pEvent->num_rx;
pEntry->num_subcarrier = ltoh16_ua(&(pEvent->num_carrier));
pEntry->report_tsf = ltoh64_ua(&(pEvent->cfr_timestamp));
pEntry->rssi = pEvent->rssi;
pEntry->data_length = 0;
pEntry->remain_length = 0;
pEntry->copied_length = 0;
DHD_TRACE(("%s-%d: Entry data_size=%d, remain_size=%d, @%llu\n",
__func__, __LINE__,
ltoh32_ua(&(pEvent->cfr_dump_length)),
ltoh32_ua(&(pEvent->remain_length)),
ltoh64_ua(&(pEntry->report_tsf))));
remain_length = ltoh32_ua(&(pEvent->remain_length));
data_length = ltoh32_ua(&(pEvent->cfr_dump_length));
pData = (uint8 *)pEvent->data;
ret = dhd_csi_data_append(remain_length, data_length, pData, ptr);
if (0 <= ret) {
INIT_LIST_HEAD(&(ptr->list));
mutex_lock(&dhdp->csi_lock);
list_add_tail(&(ptr->list), &dhdp->csi_list);
dhdp->csi_count++;
mutex_unlock(&dhdp->csi_lock);
} else {
MFREE(dhdp->osh, ptr, total_size);
}
return ret;
}
static int dhd_csi_data_new_v2(dhd_pub_t *dhdp, const wl_event_msg_t *event,
struct dhd_cfr_header_v2 *pEvent)
{
struct csi_cfr_node *ptr = NULL;
struct syna_csi_header *pEntry = NULL;
int ret = BCME_ERROR;
uint total_size = 0;
uint32 remain_length = 0;
uint32 data_length = 0;
uint8 *pData = NULL;
if (SYNA_ALIGN_PADDING & (uintptr)pEvent) {
DHD_ERROR(("%s-%d: *Error, pEvent=0x%px is not aligned!",
__func__, __LINE__, pEvent));
}
total_size = SYNA_CSI_CFR_NODE_LEN + pEvent->data_length;
ptr = (struct csi_cfr_node *)MALLOCZ(dhdp->osh, total_size);
if (!ptr) {
DHD_ERROR(("%s-%d: *Error, malloc %d for cfr dump list error\n",
__func__, __LINE__, total_size));
return BCME_NOMEM;
}
ptr->pNode = ptr; /* Not useful */
ptr->total_size = total_size;
pEntry = &(ptr->entry);
DHD_TRACE(("%s-%d: ptr=0x%p, ptr=0x%px, pEntry=0x%px, "
"delta=%d, header_size=%d\n",
__func__, __LINE__, ptr, ptr, pEntry,
(int)((uintptr)pEntry - (uintptr)ptr),
(int)SYNA_CSI_CFR_NODE_LEN));
/* process one by one for alignment consideration */
memcpy(pEntry, pEvent, sizeof(struct syna_csi_header));
pEntry->magic_flag = CONST_SYNA_CSI_MAGIC_FLAG;
pEntry->version = CONST_SYNA_CSI_COMMON_HEADER_VERSION;
if ((pEvent->status_compat)
&& (!(SYNA_CSI_FLAG_ERROR_MASK & pEntry->flags))) {
pEntry->flags |= SYNA_CSI_FLAG_ERROR_GENERIC;
DHD_ERROR(("%s-%d: *Warning, status=0x%X, "
" global_id=%d!\n",
__func__, __LINE__,
pEvent->status_compat,
pEvent->global_id));
}
if (!pEntry->format_type) {
pEntry->format_type = SYNA_CSI_FORMAT_Q8;
}
if (!memcmp(_gpMAC_zero, pEntry->bsscfg_ea, ETHER_ADDR_LEN)) {
dhd_if_t *ifp = dhd_get_ifp(dhdp, event->ifidx);
if (!ifp) {
DHD_ERROR(("%s-%d: *Error, get ifp error\n",
__func__, __LINE__));
} else {
memcpy(pEntry->bsscfg_ea, ifp->mac_addr, ETHER_ADDR_LEN);
}
}
if (!pEntry->report_tsf) {
struct timespec64 ts;
ktime_get_real_ts64(&ts);
pEntry->report_tsf = (uint64)TIMESPEC64_TO_US(ts);
}
pEntry->data_length = 0;
pEntry->remain_length = 0;
pEntry->copied_length = 0;
pEntry->checksum = pEvent->checksum;
DHD_TRACE(("%s-%d: Entry data_size=%d, remain_size=%d, @%llu\n",
__func__, __LINE__,
pEvent->data_length,
pEvent->remain_length,
pEntry->report_tsf));
remain_length = pEvent->remain_length;
data_length = pEvent->data_length;
pData = (uint8 *)pEvent->data;
ret = dhd_csi_data_append(remain_length, data_length, pData, ptr);
if (0 <= ret) {
INIT_LIST_HEAD(&(ptr->list));
mutex_lock(&dhdp->csi_lock);
list_add_tail(&(ptr->list), &dhdp->csi_list);
dhdp->csi_count++;
mutex_unlock(&dhdp->csi_lock);
} else {
MFREE(dhdp->osh, ptr, total_size);
}
return ret;
}
int dhd_csi_event_handler(dhd_pub_t *dhdp, const wl_event_msg_t *event, void *event_data)
{
union dhd_cfr_header *pEvent = NULL;
struct csi_cfr_node *ptr = NULL, *next = NULL, *save_ptr = NULL;
const uint8 *pMAC = NULL, *pData = NULL;
uint8 version = 0xff;
uint32 data_length = 0, remain_length = 0, header_length = 0;
int ret = BCME_OK;
NULL_CHECK(dhdp, "dhdp is NULL", ret);
DHD_TRACE(("%s-%d: Enter\n", __func__, __LINE__));
if (!event_data) {
DHD_ERROR(("%s: event_data is NULL\n", __FUNCTION__));
return -EINVAL;
DHD_ERROR(("%s-%d: event_data is NULL\n",
__func__, __LINE__));
ret = BCME_BADARG;
goto done;
}
p_event = (cfr_dump_data_t *)event_data;
pEvent = (union dhd_cfr_header *)event_data;
if (pEvent->header_v0.status) {
DHD_ERROR(("%s-%d: *Warning, status=0x%X "
" may indicate error!\n",
__func__, __LINE__,
pEvent->header_v0.status));
/* TODO: do need to abandon this scenario? */
}
version = pEvent->header_v0.version;
switch (version) {
case CSI_VERSION_V0:
pMAC = pEvent->header_v0.peer_macaddr;
header_length = sizeof(struct dhd_cfr_header_v0);
remain_length = ltoh32_ua(&(pEvent->header_v0.remain_length));
data_length = ltoh32_ua(&(pEvent->header_v0.cfr_dump_length));
pData = (uint8 *)pEvent->header_v0.data;
break;
case CSI_VERSION_V1:
pMAC = pEvent->header_v1.peer_macaddr;
header_length = sizeof(struct dhd_cfr_header_v1);
remain_length = ltoh32_ua(&(pEvent->header_v1.remain_length));
data_length = ltoh32_ua(&(pEvent->header_v1.cfr_dump_length));
pData = (uint8 *)pEvent->header_v1.data;
break;
case CSI_VERSION_V2:
pMAC = pEvent->header_v2.client_ea;
header_length = sizeof(struct dhd_cfr_header_v2);
remain_length = pEvent->header_v2.remain_length;
data_length = pEvent->header_v2.data_length;
pData = (uint8 *)pEvent->header_v2.data;
break;
default:
DHD_ERROR(("%s-%d: CSI version=%d error\n",
__func__, __LINE__, version));
ret = BCME_BADOPTION;
goto done;
break;
}
if (header_length <= remain_length) {
remain_length -= header_length;
}
if (CONST_CSI_MAXIMUM_DATA_BYTES < remain_length) {
DHD_ERROR(("%s-%d: *Error, drop too big length, "
"global_id=%d, version=%d, status=%d, "
"data_length=%d(0x%X), remain_length=%d(0x%X) > %d\n",
__func__, __LINE__,
pEvent->header_v2.global_id,
version, pEvent->header_v2.status_compat,
data_length, data_length,
remain_length, remain_length,
(int)CONST_CSI_MAXIMUM_DATA_BYTES));
prhex("TOO_BIG_LENGTH", (uchar *)pEvent, 128);
ret = BCME_BADLEN;
goto done;
}
mutex_lock(&dhdp->csi_lock);
/* 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 (!list_empty(&dhdp->csi_list)) {
list_for_each_entry_safe(ptr, next, &dhdp->csi_list, list) {
struct syna_csi_header *pEntry = &(ptr->entry);
/* check if is new */
if (bcmp(&pEntry->client_ea, pMAC, ETHER_ADDR_LEN) == 0) {
if (pEntry->remain_length > 0) {
save_ptr = ptr;
break;
}
}
}
}
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"));
}
/* check if need to drop head packet */
if ((!save_ptr) && (dhdp->csi_count >= MAX_CSI_BUF_NUM)) {
DHD_ERROR(("%s-%d: CSI data is full, drop pkt \n",
__func__, __LINE__));
ptr = list_first_entry(&dhdp->csi_list, struct csi_cfr_node, list);
list_del_init(&ptr->list);
MFREE(dhdp->osh, ptr, ptr->total_size);
dhdp->csi_count--;
}
mutex_unlock(&dhdp->csi_lock);
/* try to append new node if needs */
DHD_TRACE(("%s-%d: save_ptr=0x%px, version=%d\n",
__func__, __LINE__, save_ptr, version));
if (!save_ptr) {
switch (version) {
case CSI_VERSION_V0:
ret = dhd_csi_data_new_v0(dhdp, event, &(pEvent->header_v0));
break;
case CSI_VERSION_V1:
ret = dhd_csi_data_new_v1(dhdp, event, &(pEvent->header_v1));
break;
case CSI_VERSION_V2:
ret = dhd_csi_data_new_v2(dhdp, event, &(pEvent->header_v2));
break;
default:
DHD_ERROR(("%s-%d: CSI version=%d error\n",
__func__, __LINE__, version));
ret = BCME_BADOPTION;
goto done;
break;
}
} else {
ret = dhd_csi_data_append(remain_length, data_length, pData, save_ptr);
}
done:
return ret;
}
int
dhd_csi_init(dhd_pub_t *dhd)
static void
dhd_csi_clean_list(dhd_pub_t *dhdp)
{
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;
struct csi_cfr_node *ptr, *next;
int num = 0;
if (!dhd) {
DHD_ERROR(("NULL POINTER: %s\n", __FUNCTION__));
if (!dhdp) {
DHD_ERROR(("%s-%d: *Error, NULL POINTER\n",
__func__, __LINE__));
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));
}
mutex_lock(&dhdp->csi_lock);
if (!list_empty(&dhdp->csi_list)) {
list_for_each_entry_safe(ptr, next, &dhdp->csi_list, list) {
list_del(&ptr->list);
num++;
MFREE(dhdp->osh, ptr, ptr->total_size);
}
}
dhd->csi_count = 0;
DHD_TRACE(("Clean up %d record\n", num));
dhdp->csi_count = 0;
mutex_unlock(&dhdp->csi_lock);
DHD_TRACE(("%s-%d: Clean up %d record\n",
__func__, __LINE__, num));
}
int dhd_csi_config(dhd_pub_t *dhdp, char *pBuf, uint length, bool is_set)
{
int ret = BCME_OK;
if ((!dhdp) || (!pBuf) || (sizeof(uint32) > length)) {
DHD_ERROR(("%s-%d: *Error, Bad argument\n",
__func__, __LINE__));
ret = BCME_BADARG;
goto done;
}
if (is_set) {
uint value = *((uint *)pBuf);
if (SYNA_CSI_DATA_MODE_LAST <= value) {
ret = BCME_BADOPTION;
goto done;
} else if (SYNA_CSI_DATA_MODE_NONE != value) {
dhdp->csi_data_send_manner = value;
dhd_csi_clean_list(dhdp);
}
} else {
memcpy(pBuf, &dhdp->csi_data_send_manner, sizeof(uint32));
}
done:
return ret;
}
int dhd_csi_init(dhd_pub_t *dhdp)
{
int err = BCME_OK;
mutex_init(&dhdp->csi_lock);
mutex_lock(&dhdp->csi_lock);
NULL_CHECK(dhdp, "dhdp is NULL", err);
INIT_LIST_HEAD(&dhdp->csi_list);
dhdp->csi_count = 0;
mutex_unlock(&dhdp->csi_lock);
return err;
}
int
dhd_csi_dump_list(dhd_pub_t *dhd, char *buf)
dhd_csi_deinit(dhd_pub_t *dhdp)
{
int ret = BCME_OK;
cfr_dump_list_t *ptr, *next;
uint8 * pbuf = buf;
int num = 0;
int length = 0;
int err = BCME_OK;
NULL_CHECK(dhd, "dhd is NULL", ret);
NULL_CHECK(dhdp, "dhdp is NULL", err);
/* 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));
dhd_csi_clean_list(dhdp);
mutex_destroy(&dhdp->csi_lock);
return err;
}
int dhd_csi_retrieve_queue_data(dhd_pub_t *dhdp, char *buf, uint count)
{
struct csi_cfr_node *ptr = NULL, *next = NULL;
int ret = BCME_OK;
char *pbuf = buf;
int num = 0;
int copy_len = 0;
int left_data = 0;
int total_copy_len = 0;
NULL_CHECK(dhdp, "dhdp is NULL", ret);
mutex_lock(&dhdp->csi_lock);
if (!list_empty(&dhdp->csi_list)) {
list_for_each_entry_safe(ptr, next, &dhdp->csi_list, list) {
struct syna_csi_header *pEntry = &(ptr->entry);
if (pEntry->remain_length) {
DHD_ERROR(("%s-%d: *Warning, data not ready "
"for %02X:%02X:%02X:%02X:%02X:%02X,"
"global_id=%d, data_length=%d, "
"remain_length=%d\n",
__func__, __LINE__,
pEntry->client_ea[0],
pEntry->client_ea[1],
pEntry->client_ea[2],
pEntry->client_ea[3],
pEntry->client_ea[4],
pEntry->client_ea[5],
pEntry->global_id,
pEntry->data_length,
pEntry->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++;
left_data = SYNA_CSI_PKT_TOTAL_LEN(pEntry)
- pEntry->copied_length;
copy_len = count;
if (0 > left_data) {
DHD_ERROR(("%s-%d: *Error, invalid case, "
"total_len=%d, data_len=%d, "
"remain_len=%d, copied_len=%d\n",
__func__, __LINE__,
(int)SYNA_CSI_PKT_TOTAL_LEN(pEntry),
pEntry->data_length,
pEntry->remain_length,
pEntry->copied_length));
copy_len = 0;
} else if (copy_len > left_data) {
copy_len = left_data;
}
DHD_TRACE(("%s-%d: Packet[%d]: "
"left_room=%d, copy_len=%d, "
"pNode_data_len=%d, pNode_reamin_len=%d, "
"pNode_copied_len=%d, csi_count=%d\n",
__func__, __LINE__,
num, count, copy_len,
pEntry->data_length,
pEntry->remain_length,
pEntry->copied_length,
dhdp->csi_count));
if (0 < copy_len) {
memcpy(pbuf,
pEntry->copied_length + (uint8 *)pEntry,
copy_len);
pEntry->copied_length += copy_len;
count -= copy_len;
pbuf += copy_len;
num++;
}
if (pEntry->copied_length >= SYNA_CSI_PKT_TOTAL_LEN(pEntry)) {
list_del(&ptr->list);
MFREE(dhdp->osh, ptr, ptr->total_size);
dhdp->csi_count--;
}
if (0 >= copy_len) {
break;
}
}
}
DHD_TRACE(("dump %d record %d bytes\n", num, length));
mutex_unlock(&dhdp->csi_lock);
total_copy_len = pbuf - buf;
DHD_TRACE(("%s-%d: dump %d record %d bytes\n",
__func__, __LINE__, num, total_copy_len));
return length;
return total_copy_len;
}
#endif /* CSI_SUPPORT */

View File

@ -1,7 +1,8 @@
/*
* Broadcom Dongle Host Driver (DHD), CSI
* Broadcom Dongle Host Driver (DHD), Linux-specific network interface.
* Basically selected code segments from usb-cdc.c and usb-rndis.c
*
* Copyright (C) 1999-2018, Broadcom.
* Copyright (C) 2023, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -17,27 +18,252 @@
* 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 $
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id$
*/
#ifndef __DHD_CSI_H__
#define __DHD_CSI_H__
/* definition for structure and API between APPP and driver */
/* **** SYNA CSI header interface with driver **** */
enum syna_csi_data_mode_type {
SYNA_CSI_DATA_MODE_NONE = 0,
/* upper layer will fetch data by sysfs */
SYNA_CSI_DATA_MODE_SYSFS,
/* upper layer will fetch data by UDP socket */
SYNA_CSI_DATA_MODE_UDP_SOCKET,
SYNA_CSI_DATA_MODE_LAST
};
enum syna_csi_format_type {
SYNA_CSI_FORMAT_UNKNOWN = 0,
SYNA_CSI_FORMAT_Q8, /* (9,9,5) Q8 floating point
* BCM4358/4359
*/
SYNA_CSI_FORMAT_Q13, /* (14,14) Q13 fixed point
* BCM4339/43455/43456/43458
*/
SYNA_CSI_FORMAT_Q11, /* (12,12,6) Q11 floating point
* BCM4360/4366
*/
SYNA_CSI_FORMAT_LAST
};
/* (9,9,5) Q8 floating point data format */
#define _Q8_REAL_MA(t) (0x000ff &((t)>>14))
#define _Q8_REAL_SI(t) (0x00001 &((t)>>22))
#define _Q8_IMAGE_MA(t) (0x000ff &((t)>> 5))
#define _Q8_IMAGE_SI(t) (0x00001 &((t)>>13))
#define SYNA_CSI_DATA_Q8_REAL(t) \
(((0 < _Q8_REAL_SI(t)) \
? (-1) \
: (1)) \
* ((int32)_Q8_REAL_MA(t)) \
)
#define SYNA_CSI_DATA_Q8_IMAGE(t) \
(((0 < _Q8_IMAGE_SI(t)) \
? (-1) \
: (1)) \
* ((int32)_Q8_IMAGE_MA(t)) \
)
#define SYNA_CSI_DATA_Q8_EXP(t) \
(((int8)(0xf8 \
& ((t) << 3))) \
>> 3 \
)
/* (14,14) Q13 fixed point data format */
#define SYNA_CSI_DATA_Q13_REAL(t) \
(((int32)(0xfff30000 \
& ((t) << 4))) \
>> (14 + 4) \
)
#define SYNA_CSI_DATA_Q13_IMAGE(t) \
(((int32)(0xfff30000 \
& ((t) << 18))) \
>> (0 + 18) \
)
/* (12,12,6) Q11 floating point */
#define _Q11_REAL_MA(t) (0x007ff &((t)>>18))
#define _Q11_REAL_SI(t) (0x00001 &((t)>>29))
#define _Q11_IMAGE_MA(t) (0x007ff &((t)>> 6))
#define _Q11_IMAGE_SI(t) (0x00001 &((t)>>17))
#define SYNA_CSI_DATA_Q11_REAL(t) \
(((0 < _Q11_REAL_SI(t)) \
? (-1) \
: (1)) \
* ((int32)_Q11_REAL_MA(t)) \
)
#define SYNA_CSI_DATA_Q11_IMAGE(t) \
(((0 < _Q11_IMAGE_SI(t)) \
? (-1) \
: (1)) \
* ((int32)_Q11_IMAGE_MA(t)) \
)
#define SYNA_CSI_DATA_Q11_EXP(t) \
(((int8)(0xfc \
& ((t) << 2))) \
>> 2 \
)
enum syna_csi_error_status {
SYNA_CSI_ERROR_NONE,
SYNA_CSI_ERROR_GENERIC, /* generic error */
SYNA_CSI_ERROR_NO_ACK, /* peer doesn't ACK */
SYNA_CSI_ERROR_READ, /* read data error */
SYNA_CSI_ERROR_PS, /* peer device under powersaving */
SYNA_CSI_ERROR_LAST
};
enum syna_csi_flag {
/* bit 0 ~ bit 15 are for error information */
SYNA_CSI_FLAG_ERROR_MASK = 0x0FFFF,
SYNA_CSI_FLAG_ERROR_CHECKSUM = (1 << 0),
SYNA_CSI_FLAG_ERROR_GENERIC = (1 << SYNA_CSI_ERROR_GENERIC),
SYNA_CSI_FLAG_ERROR_NO_ACK = (1 << SYNA_CSI_ERROR_NO_ACK),
SYNA_CSI_FLAG_ERROR_READ = (1 << SYNA_CSI_ERROR_READ),
SYNA_CSI_FLAG_ERROR_PS = (1 << SYNA_CSI_ERROR_PS),
/* subcarrier real position along FFT index: (total N=2*M subcarries)
* -M, -(M-1), -(M-2), -(M-3),...,-1, 0, 1, 2,...M-1, M
*
* Data Output order with positive part first(*default*):
* 0, 1, 2,...M-1, M, -M, -(M-1), -(M-2), -(M-3),...,-1,
*
* Data Output order with negative part first:
* -M, -(M-1), -(M-2), -(M-3),...,-1, 0, 1, 2,...M-1, M
*/
SYNA_CSI_FLAG_FFT_NEGATIVE_FIRST = (1 << 16),
SYNA_CSI_FLAG_LAST
};
enum syna_csi_band_type {
SYNA_CSI_BAND_UNKNOWN = 0,
SYNA_CSI_BAND_2G,
SYNA_CSI_BAND_5G,
SYNA_CSI_BAND_6G,
SYNA_CSI_BAND_LAST
};
enum syna_csi_bandwidth_type {
SYNA_CSI_BW_UNKNOWN = 0x000,
SYNA_CSI_BW_5MHz = 0x001,
SYNA_CSI_BW_10MHz = 0x002,
SYNA_CSI_BW_20MHz = 0x004,
SYNA_CSI_BW_40MHz = 0x008,
SYNA_CSI_BW_80MHz = 0x010,
SYNA_CSI_BW_160MHz = 0x020,
SYNA_CSI_BW_320MHz = 0x040,
SYNA_CSI_BW_LAST
};
/* 'SYNA' -> 'A'53, 'N'59, 'Y'4e, 'S'41 */
#define CONST_SYNA_CSI_MAGIC_FLAG 0x414E5953
/* CSI API common header structure (8 bytes alignment for 64bit system) */
/* below is version 1 'syna_csi_header' */
#define CONST_SYNA_CSI_COMMON_HEADER_VERSION 0x01
struct syna_csi_header {
/* byte 0 ~ 3 */
uint32 magic_flag; /* flag for protecting and detecting header */
/* byte 4 ~ 7 */
uint8 version; /* header version of this structure */
uint8 format_type; /* data format type of current CSI packet,
* enumerated in 'syna_csi_format_type'
*/
uint8 fc; /* packet frame control type of current
* CSI data for further checking if it
* is correct expected result
*/
uint8 flags; /* flag may use for extra emendation
* which enumerated as 'syna_csi_flag'
*/
/* byte 8 ~ 19 */
uint8 client_ea[6]; /* client MAC address */
uint8 bsscfg_ea[6]; /* BSSCFG address of current interface */
/* byte 20 ~ 23 */
uint8 band; /* enumerated in 'syna_csi_band_type' */
uint8 bandwidth; /* enumerated in 'syna_csi_bandwidth_type' */
uint16 channel; /* channel number of corresponding band */
/* byte 24 ~ 31 */
uint64 report_tsf; /* current CSI DATA RX timestamp */
/* byte 32 ~ 35 */
uint8 num_txstream; /* peer side TX spatial steams */
uint8 num_rxchain; /* number of RX side chain/antenna */
uint16 num_subcarrier; /* Number of subcarrier */
/* byte 36 ~ 39 */
int8 rssi; /* average RSSI, and goto check the
* 'rssi_ant' if this 'rssi' is zero
*/
int8 noise; /* average noise */
int16 global_id; /* CSI frame global ID */
/* byte 40 ~ 47 */
int8 rssi_ant[8]; /* RSSI of each RX chain/antenna
* (Depends on solution, and some
* chipsets may only provide 'rssi'
* rather than 'rssi_ant')
*/
/* byte 48 ~ 55 */
uint64 padding_future; /* reserved */
/* byte 56 ~ 63 */
uint16 data_length; /* the bytes of 'data[]' */
uint16 remain_length; /* remain length of not received data */
uint16 copied_length; /* the length has been copied to user */
uint16 checksum; /* 'data[]' checksum, 0 - not used */
/* byte 64 ~ End */
uint32 data[0]; /* variable length according to the
* 'data_length', but the minimal
* valid data length will be
* decided by the 'num_txchains'
* 'num_rxchain' 'num_subcarrier'.
* For example, the index quantity
* of 'uint32' in the 11N 80MHz can
* be got via:
* 256 SubCarriers * 2 TXStream * 2 RXChain
* Note: 'data_length' is bytes quantity,
* and the 'data[]' array index range should
* be 0 ~ (data_length/4 - 1)
*/
};
#define SYNA_CSI_PKT_TOTAL_LEN(ptr) \
(sizeof(struct syna_csi_header) \
+ ((struct syna_csi_header *)(ptr))->data_length \
)
/* definition for structure and functions between driver and FW */
/* Maxinum csi file dump size */
#define MAX_CSI_FILESZ (32 * 1024)
/* Maxinum subcarrier number */
#define MAXINUM_CFR_DATA 256 * 4
#define MAXIMUM_CFR_DATA 2048
#define CSI_DUMP_PATH "/sys/bcm-dhd/csi"
#define MAX_EVENT_SIZE 1400
/* maximun csi number stored at dhd */
#define MAX_CSI_NUM 8
#define MAX_CSI_NUM 16
#define MAX_CSI_BUF_NUM 1024
typedef struct cfr_dump_header {
/* 0 - successful; 1 - Failed */
uint8 status;
/* CSI VERSION */
#define CSI_VERSION_V0 0 /* V0 */
#define CSI_VERSION_V1 1 /* V1 */
#define CSI_VERSION_V2 2 /* V2 */
struct dhd_cfr_header_v0 {
uint8 status:4; /* bit3-0 */
uint8 version:4; /* bit7-4 */
/* Peer MAC address */
uint8 peer_macaddr[6];
/* Number of Space Time Streams */
@ -52,25 +278,189 @@ typedef struct cfr_dump_header {
uint32 remain_length;
/* RSSI */
int8 rssi;
} __attribute__((packed)) cfr_dump_header_t;
uint32 data[0];
} __attribute__ ((packed));
typedef struct cfr_dump_data {
cfr_dump_header_t header;
uint32 data[MAXINUM_CFR_DATA];
} cfr_dump_data_t;
struct dhd_cfr_header_v1 {
uint8 status:4; /* bit3-0 */
uint8 version:4; /* bit7-4 */
/* 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;
typedef struct {
struct list_head list;
cfr_dump_data_t entry;
} cfr_dump_list_t;
/* Chip id. 1 for BCM43456/8 */
uint8 chip_id;
/* Frame control field */
uint8 fc;
/* Time stamp when CFR capture is taken,
* in microseconds since the epoch
*/
uint64 cfr_timestamp;
int dhd_csi_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data);
uint32 data[0];
} __attribute__ ((packed));
int dhd_csi_init(dhd_pub_t *dhd);
struct dhd_cfr_header_v2 { /* 8 bytes aligment for x64 */
/* byte 0 ~ 7 */
uint8 status_compat:4; /* bit3-0, current CSI data status: 0->good */
uint8 version_compat:4; /* bit7-4, duplicate but compatible part */
uint8 padding_magic;
uint16 magic_flag; /* flag for protecting and detecting header */
int dhd_csi_deinit(dhd_pub_t *dhd);
uint8 version; /* header version of this structure */
uint8 format_type; /* data format type of current CSI packet,
* enumerated in 'syna_csi_format_type'
*/
uint8 fc; /* packet frame control type of current
* CSI data for further checking if it
* is correct expected result
*/
uint8 flags; /* flag may use for extra emendation
* which enumerated as 'syna_csi_flag'
*/
void dhd_csi_clean_list(dhd_pub_t *dhd);
/* byte 8 ~ 19 */
uint8 client_ea[6]; /* client MAC address */
uint8 bsscfg_ea[6]; /* BSSCFG address of current interface */
/* byte 20 ~ 23 */
uint8 band; /* enumerated in 'syna_csi_band_type' */
uint8 bandwidth; /* enumerated in 'syna_csi_bandwidth_type' */
uint16 channel; /* channel number of corresponding band */
/* byte 24 ~ 31 */
uint64 report_tsf; /* current CSI DATA RX timestamp */
/* byte 32 ~ 35 */
uint8 num_txstream; /* peer side TX spatial steams */
uint8 num_rxchain; /* number of RX side chain/antenna */
uint16 num_subcarrier; /* Number of subcarrier */
/* byte 36 ~ 39 */
int8 rssi; /* average RSSI, and goto check the
* 'rssi_ant' if this 'rssi' is zero
*/
int8 noise; /* average noise */
int16 global_id; /* CSI frame global ID */
/* byte 40 ~ 47 */
int8 rssi_ant[8]; /* RSSI of each RX chain/antenna
* (Depends on solution, and some
* chipsets may only provide 'rssi'
* rather than 'rssi_ant')
*/
/* byte 48 ~ 55 */
uint64 padding_future; /* reserved */
/* byte 56 ~ 63 */
uint16 data_length; /* the data length of 'data[]' */
uint16 remain_length; /* the remain unsent length of 'data[]' */
uint16 padding_length; /* reserved */
uint16 checksum; /* 'data[]' checksum, 0 - not used */
/* byte 64 ~ End */
uint32 data[0]; /* variable according to 'data_length', but
* the minial valid data length will be
* decided by 'num_txchains', 'num_rxchain'
* 'num_subcarrier'. For example, the
* quantity of uint32(4 bytes) in the
* 11N 80MHz can be got via:
* 256 SubCarriers * 2 TXStream * 2 RXChain
*/
};
union dhd_cfr_header {
struct dhd_cfr_header_v0 header_v0;
struct dhd_cfr_header_v1 header_v1;
struct dhd_cfr_header_v2 header_v2;
};
#define CSI_CFR_TOTAL_LENGTH(data_len) \
(sizeof(union dhd_cfr_header) + data_len)
/* BW80 2x2 => 4bytes*256subcarries*2txstream*2rxchain */
#define CONST_CSI_MAXIMUM_DATA_BYTES (CSI_CFR_TOTAL_LENGTH(256 *2 *2 *4))
struct csi_cfr_node {
struct list_head list;
void *pNode; /* recording current node pointer
* especially for UDP data manner
*/
uint32 total_size;
struct syna_csi_header entry;
};
#define SYNA_CSI_CFR_NODE_LEN sizeof(struct csi_cfr_node)
#define SYNA_CSI_CFR_NODE_TOTAL_LEN(ptr, data_length) \
(\
SYNA_CSI_CFR_NODE_LEN + data_length \
)
#define SYNA_CSI_CFR_NODE_FREE_LEN(ptr) \
(\
((struct csi_cfr_node *)(ptr))->total_size \
- SYNA_CSI_CFR_NODE_LEN \
)
extern int dhd_csi_config(dhd_pub_t *dhdp, char *buf, uint length, bool is_set);
/* Function: change the upper layer fetching data manner
* Input: uint is_set indicate it's set or get action
* uint type the expected fetch type(ignore when get)
* uint param extra param when set(UDP socket port)
* Output: < 0 error encounter
* == 0 successful
* > 0 corresponding 'fetch type' when get
*/
extern int dhd_csi_data_fetch_type_access(uint is_set, uint type, uint param);
/* Function: parse the CSI event and convert to 'dhd_csi_header' format,
* and queue the item into the common 'csi_cfr_queue'
* Input: dhd_pub_t *dhdp context for operation
* char *buf buffer for storing csi data
* uint count total bytes available in 'buf'
* Output: < 0 error encounter
* == 0 successful but no csi data in queue
* > 0 bytes write into 'buf'
*/
extern int dhd_csi_retrieve_queue_data(dhd_pub_t *dhdp, char *buf, uint count);
/* Function: parse the CSI event and convert to 'dhd_csi_header' format,
* and queue the item into the common 'csi_cfr_queue'
* Input: dhd_pub_t *dhdp context for operation
* wl_event_msg_t *event wl event message header
* void *event_data extra event data
* Output: < 0 error encounter
* == 0 successful
*/
extern int dhd_csi_event_handler(dhd_pub_t *dhdp,
const wl_event_msg_t *event, void *event_data);
/* Function: Initialize the CSI module
* Input: dhd_pub_t *dhdp context for operation
* Output: < 0 error encounter
* == 0 successful
*/
extern int dhd_csi_init(dhd_pub_t *dhdp);
/* Function: Deinitialize the CSI module
* Input: dhd_pub_t *dhdp context for operation
* Output: < 0 error encounter
* == 0 successful
*/
extern int dhd_csi_deinit(dhd_pub_t *dhdp);
int dhd_csi_dump_list(dhd_pub_t *dhd, char *buf);
#endif /* __DHD_CSI_H__ */

View File

@ -1,333 +0,0 @@
/*
* 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,7 +1,7 @@
/*
* Customer code to add GPIO control during WLAN start/stop
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -33,6 +33,8 @@
#include <wlioctl.h>
#include <dhd_dbg.h>
#ifndef BCMDONGLEHOST
#include <wlc_pub.h>
#include <wl_dbg.h>
@ -68,7 +70,7 @@ int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr)
{
int host_oob_irq = 0;
#if defined(CUSTOMER_HW2) || defined(CUSTOMER_HW4) || defined(BOARD_HIKEY)
#if defined(BOARD_HIKEY)
host_oob_irq = wifi_platform_get_irq_number(adapter, irq_flags_ptr);
#else
@ -87,7 +89,7 @@ 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 /* CUSTOMER_HW2 || CUSTOMER_HW4 || BOARD_HIKEY */
#endif /* BOARD_HIKER */
return (host_oob_irq);
}
@ -114,8 +116,7 @@ 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) || defined(CUSTOMER_HW10) || defined(BOARD_HIKEY)) && \
(LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
#if defined(BOARD_HIKEY) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
ret = wifi_platform_get_mac_addr(adapter, buf);
#endif
@ -131,7 +132,195 @@ dhd_custom_get_mac_address(void *adapter, unsigned char *buf)
}
#endif /* GET_CUSTOM_MAC_ENABLE */
#ifndef CUSTOMER_HW4
#ifdef SYNA_SAR_CUSTOMER_PARAMETER
struct customer_cntry_list {
eCountry_flag_type type;
char ccode[WLC_CNTRY_BUF_SZ]; /* Country code */
};
/* maximum: (A~Z+0~9) * (A~Z+0~9) = (26+10)*(26+10) = 1296 */
#define MAX_COUNTRY_LIST 500
struct customer_cntry_list syna_cntry_flag[MAX_COUNTRY_LIST] = {
/* FCC TYPE */
{SYNA_COUNTRY_TYPE_FCC, "AG"},
{SYNA_COUNTRY_TYPE_FCC, "AI"},
{SYNA_COUNTRY_TYPE_FCC, "AR"},
{SYNA_COUNTRY_TYPE_FCC, "AW"},
{SYNA_COUNTRY_TYPE_FCC, "BB"},
{SYNA_COUNTRY_TYPE_FCC, "BL"},
{SYNA_COUNTRY_TYPE_FCC, "BM"},
{SYNA_COUNTRY_TYPE_FCC, "BO"},
{SYNA_COUNTRY_TYPE_FCC, "BS"},
{SYNA_COUNTRY_TYPE_FCC, "BZ"},
{SYNA_COUNTRY_TYPE_FCC, "CA"},
{SYNA_COUNTRY_TYPE_FCC, "CL"},
{SYNA_COUNTRY_TYPE_FCC, "CO"},
{SYNA_COUNTRY_TYPE_FCC, "CR"},
{SYNA_COUNTRY_TYPE_FCC, "CW"},
{SYNA_COUNTRY_TYPE_FCC, "DO"},
{SYNA_COUNTRY_TYPE_FCC, "EC"},
{SYNA_COUNTRY_TYPE_FCC, "FM"},
{SYNA_COUNTRY_TYPE_FCC, "GT"},
{SYNA_COUNTRY_TYPE_FCC, "GU"},
{SYNA_COUNTRY_TYPE_FCC, "GY"},
{SYNA_COUNTRY_TYPE_FCC, "HN"},
{SYNA_COUNTRY_TYPE_FCC, "HT"},
{SYNA_COUNTRY_TYPE_FCC, "IN"},
{SYNA_COUNTRY_TYPE_FCC, "IR"},
{SYNA_COUNTRY_TYPE_FCC, "JM"},
{SYNA_COUNTRY_TYPE_FCC, "KH"},
{SYNA_COUNTRY_TYPE_FCC, "KN"},
{SYNA_COUNTRY_TYPE_FCC, "KR"},
{SYNA_COUNTRY_TYPE_FCC, "KY"},
{SYNA_COUNTRY_TYPE_FCC, "LC"},
{SYNA_COUNTRY_TYPE_FCC, "MF"},
{SYNA_COUNTRY_TYPE_FCC, "MP"},
{SYNA_COUNTRY_TYPE_FCC, "NI"},
{SYNA_COUNTRY_TYPE_FCC, "PA"},
{SYNA_COUNTRY_TYPE_FCC, "PE"},
{SYNA_COUNTRY_TYPE_FCC, "PG"},
{SYNA_COUNTRY_TYPE_FCC, "PM"},
{SYNA_COUNTRY_TYPE_FCC, "PW"},
{SYNA_COUNTRY_TYPE_FCC, "PR"},
{SYNA_COUNTRY_TYPE_FCC, "PY"},
{SYNA_COUNTRY_TYPE_FCC, "SR"},
{SYNA_COUNTRY_TYPE_FCC, "SV"},
{SYNA_COUNTRY_TYPE_FCC, "SX"},
{SYNA_COUNTRY_TYPE_FCC, "TC"},
{SYNA_COUNTRY_TYPE_FCC, "TT"},
{SYNA_COUNTRY_TYPE_FCC, "US"},
{SYNA_COUNTRY_TYPE_FCC, "UY"},
{SYNA_COUNTRY_TYPE_FCC, "VC"},
{SYNA_COUNTRY_TYPE_FCC, "VE"},
{SYNA_COUNTRY_TYPE_FCC, "VG"},
{SYNA_COUNTRY_TYPE_FCC, "VI"},
{SYNA_COUNTRY_TYPE_FCC, "VU"},
{SYNA_COUNTRY_TYPE_FCC, "WF"},
{SYNA_COUNTRY_TYPE_FCC, "WS"},
{SYNA_COUNTRY_TYPE_INVALID, ""}
};
static int gSyna_country_flag_qty = 55;
static int syna_country_flag_find(char *cntry)
{
char country[WLC_CNTRY_BUF_SZ];
int ret = BCME_NOTFOUND;
int n;
if (!cntry) {
DHD_ERROR(("%s: invalid cntry!\n", __FUNCTION__));
return BCME_BADARG;
} else {
n = strcspn(cntry, " ,");
if ((n != 2) && (n != 3)) {
DHD_ERROR(("%s: invalid n=%d!\n", __FUNCTION__, n));
return BCME_BUFTOOLONG;
} else {
strlcpy(country, cntry, WLC_CNTRY_BUF_SZ);
country[n] = '\0';
DHD_TRACE(("%s: here n=%d, country='%s'!\n",
__FUNCTION__, n, country));
}
}
n = 0;
while ((MAX_COUNTRY_LIST > n) &&
(SYNA_COUNTRY_TYPE_INVALID != syna_cntry_flag[n].type) &&
(0 < strlen(syna_cntry_flag[n].ccode))) {
if (!strncmp(country, syna_cntry_flag[n].ccode, WLC_CNTRY_BUF_SZ)) {
ret = n;
break;
} else {
n++;
}
}
/* sync up the quantity for appending new item */
if ((MAX_COUNTRY_LIST > n) &&
(SYNA_COUNTRY_TYPE_INVALID == syna_cntry_flag[n].type)) {
gSyna_country_flag_qty = n;
DHD_TRACE(("%s: update qty=%d!\n", __FUNCTION__, n));
}
return ret;
}
eCountry_flag_type syna_country_check_type(char *cntry)
{
int ret = SYNA_COUNTRY_TYPE_INVALID;
int i;
i = syna_country_flag_find(cntry);
if (0 <= i) {
ret = syna_cntry_flag[i].type;
}
return ret;
}
int syna_country_update_type_list(eCountry_flag_type type, char *list_str)
{
char *next = NULL;
int n = 0;
size_t len;
if (SYNA_COUNTRY_TYPE_QTY <= type) {
return BCME_BADARG;
} else if ((next = list_str) == NULL) {
return BCME_BADARG;
}
while ((len = strcspn(next, " ,")) > 0) {
if (len >= WLC_CNTRY_BUF_SZ) {
DHD_ERROR(("%s: string '%s' before ',' or ' ' is too long\n",
__FUNCTION__, next));
return BCME_ERROR;
}
n = syna_country_flag_find(next);
if (0 > n) {
if (BCME_NOTFOUND == n) {
if (MAX_COUNTRY_LIST <= (1 + gSyna_country_flag_qty)) {
DHD_ERROR(("%s: too many ccode(max=%d) list: '%s'\n",
__FUNCTION__, MAX_COUNTRY_LIST, list_str));
break;
} else {
/* adopt this new item */
n = gSyna_country_flag_qty;
gSyna_country_flag_qty++;
}
} else {
DHD_ERROR(("%s: skip this invalid item '%s', err=%d\n",
__FUNCTION__, next, n));
}
}
if (0 <= n) {
/* update or add a new item */
syna_cntry_flag[n].type = type;
strlcpy(syna_cntry_flag[n].ccode, next, WLC_CNTRY_BUF_SZ);
syna_cntry_flag[n].ccode[len] = '\0';
DHD_TRACE(("%s: cntry list [%d] type=%d ccode=%s\n",
__FUNCTION__, n,
syna_cntry_flag[n].type, syna_cntry_flag[n].ccode));
/* fill with a new blank item as terminate */
if ((gSyna_country_flag_qty == (n + 1)) &&
(MAX_COUNTRY_LIST > gSyna_country_flag_qty)) {
syna_cntry_flag[n+1].type = SYNA_COUNTRY_TYPE_INVALID;
syna_cntry_flag[n+1].ccode[0] = '\0';
}
}
next += len;
next += strspn(next, " ,");
}
return BCME_OK;
}
#endif /* SYNA_SAR_CUSTOMER_PARAMETER */
/* Customized Locale table : OPTIONAL feature */
const struct cntry_locales_custom translate_custom_table[] = {
/* Table should be filled out based on custom platform regulatory requirement */
@ -179,7 +368,7 @@ const struct cntry_locales_custom translate_custom_table[] = {
{"TR", "TR", 0},
{"NO", "NO", 0},
#endif /* EXMAPLE_TABLE */
#if (defined(CUSTOMER_HW2) || defined(BOARD_HIKEY)) && !defined(CUSTOMER_HW5)
#if defined(BOARD_HIKEY)
#if defined(BCM4335_CHIP)
{"", "XZ", 11}, /* Universal if Country code is unknown or empty */
#endif
@ -236,142 +425,7 @@ 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 */
#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 */
#endif /* BOARD_HIKEY */
};
/* Customized Locale convertor
@ -434,4 +488,3 @@ get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t
*/
#endif /* OEM_ANDROID */
}
#endif /* !CUSTOMER_HW4 */

View File

@ -1,7 +1,7 @@
/*
* Platform Dependent file for Hikey
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -47,6 +47,9 @@ 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 HIKEY_PCIE_VENDOR_ID 0x19e5
#define HIKEY_PCIE_DEVICE_ID 0x3660
#define WLAN_REG_ON_GPIO 491
#define WLAN_HOST_WAKE_GPIO 493
@ -58,6 +61,30 @@ static int wlan_host_wake_up = -1;
static int wlan_host_wake_irq = 0;
#define WIFI_WLAN_HOST_WAKE_PROPNAME "wl_host_wake"
extern void kirin_pcie_power_on_atu_fixup(void) __attribute__ ((weak));
extern int kirin_pcie_lp_ctrl(u32 enable) __attribute__ ((weak));
void
dhd_wifi_deinit_gpio(void)
{
/* Disable ASPM before powering off */
if (kirin_pcie_lp_ctrl) {
kirin_pcie_lp_ctrl(0);
} else {
DHD_ERROR(("[%s] kirin_pcie_lp_ctrl is NULL. "
"ASPM may not work\n", __func__));
}
if (gpio_direction_output(wlan_reg_on, 0)) {
DHD_ERROR(("%s: WL_REG_ON is failed to pull up\n", __FUNCTION__));
}
if (gpio_get_value(wlan_reg_on)) {
DHD_INFO(("WL_REG_ON on-step-2 : [%d]\n",
gpio_get_value(wlan_reg_on)));
}
gpio_free(wlan_host_wake_up);
gpio_free(wlan_reg_on);
}
int
dhd_wifi_init_gpio(void)
{
@ -83,7 +110,7 @@ dhd_wifi_init_gpio(void)
* 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")) {
if (gpio_request_one(wlan_reg_on, GPIOF_DIR_OUT, "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));
@ -93,7 +120,7 @@ dhd_wifi_init_gpio(void)
}
gpio_reg_on_val = gpio_get_value(wlan_reg_on);
DHD_INFO(("%s: Initial WL_REG_ON: [%d]\n",
DHD_ERROR(("%s: Initial WL_REG_ON: [%d]\n",
__FUNCTION__, gpio_get_value(wlan_reg_on)));
if (gpio_reg_on_val == 0) {
@ -102,10 +129,27 @@ dhd_wifi_init_gpio(void)
DHD_ERROR(("%s: WL_REG_ON is failed to pull up\n", __FUNCTION__));
return -EIO;
}
}
/* Wait for WIFI_TURNON_DELAY due to power stability */
msleep(WIFI_TURNON_DELAY);
/* Wait for WIFI_TURNON_DELAY due to power stability */
msleep(WIFI_TURNON_DELAY);
/*
* Call Kiric RC ATU fixup else si_attach will fail due to
* improper BAR0/1 address translations
*/
if (kirin_pcie_power_on_atu_fixup) {
kirin_pcie_power_on_atu_fixup();
} else {
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(1);
} else {
DHD_ERROR(("[%s] kirin_pcie_lp_ctrl is NULL. "
"ASPM may not work\n", __func__));
}
}
/* ========== WLAN_HOST_WAKE ============ */
DHD_INFO(("%s: gpio_wlan_host_wake : %d\n", __FUNCTION__, wlan_host_wake_up));
@ -130,9 +174,6 @@ dhd_wifi_init_gpio(void)
return 0;
}
extern void kirin_pcie_power_on_atu_fixup(void) __attribute__ ((weak));
extern int kirin_pcie_lp_ctrl(u32 enable) __attribute__ ((weak));
int
dhd_wlan_power(int onoff)
{
@ -254,6 +295,15 @@ dhd_wlan_init(void)
int ret;
DHD_INFO(("%s: START.......\n", __FUNCTION__));
#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
ret = dhd_init_wlan_mem();
if (ret < 0) {
DHD_ERROR(("%s: failed to alloc reserved memory,"
" ret=%d\n", __FUNCTION__, ret));
goto fail;
}
#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
ret = dhd_wifi_init_gpio();
if (ret < 0) {
DHD_ERROR(("%s: failed to initiate GPIO, ret=%d\n",
@ -264,14 +314,6 @@ dhd_wlan_init(void)
dhd_wlan_resources.start = wlan_host_wake_irq;
dhd_wlan_resources.end = wlan_host_wake_irq;
#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
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:
DHD_INFO(("%s: FINISH.......\n", __FUNCTION__));
return ret;
@ -280,10 +322,20 @@ fail:
int
dhd_wlan_deinit(void)
{
gpio_free(wlan_host_wake_up);
gpio_free(wlan_reg_on);
dhd_wifi_deinit_gpio();
return 0;
}
uint32 dhd_plat_get_rc_vendor_id(void)
{
return HIKEY_PCIE_VENDOR_ID;
}
uint32 dhd_plat_get_rc_device_id(void)
{
return HIKEY_PCIE_DEVICE_ID;
}
#ifndef BCMDHD_MODULAR
/* Required only for Built-in DHD */
device_initcall(dhd_wlan_init);

View File

@ -1,7 +1,7 @@
/*
* Platform Dependent file for usage of Preallocted Memory
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -38,7 +38,7 @@
#include <linux/init.h>
#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
/* Please refer to 'enum dhd_prealloc_index' in dhd.h */
#define WLAN_STATIC_SCAN_BUF0 5
#define WLAN_STATIC_SCAN_BUF1 6
#define WLAN_STATIC_DHD_INFO_BUF 7
@ -46,11 +46,11 @@
#define WLAN_STATIC_DHD_IF_FLOW_LKUP 9
#define WLAN_STATIC_DHD_MEMDUMP_RAM 11
#define WLAN_STATIC_DHD_WLFC_HANGER 12
#define WLAN_STATIC_DHD_PKTID_MAP 13
#define WLAN_STATIC_DHD_PKTID_IOCTL_MAP 14
#define WLAN_STATIC_DHD_PKTID_MAP 13 /* Deprecated */
#define WLAN_STATIC_DHD_PKTID_IOCTL_MAP 14 /* Deprecated */
#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_DHD_PKTLOG_DUMP_BUF 17 /* Deprecated */
#define WLAN_SCAN_BUF_SIZE (64 * 1024)
@ -112,7 +112,7 @@
((WLAN_MAX_PKTID_IOCTL_ITEMS+1) * WLAN_DHD_PKTID_IOCTL_MAP_ITEM_SIZE))
#define DHD_LOG_DUMP_BUF_SIZE (1024 * 1024 * 4)
#define DHD_LOG_DUMP_BUF_EX_SIZE (1024 * 1024 * 2)
#define DHD_LOG_DUMP_BUF_EX_SIZE (1024 * 8)
#define DHD_PKTLOG_DUMP_BUF_SIZE (64 * 1024)
@ -138,15 +138,17 @@ static struct wlan_mem_prealloc wlan_mem_array[PREALLOC_WLAN_SEC_NUM] = {
static void *wlan_static_scan_buf0 = NULL;
static void *wlan_static_scan_buf1 = NULL;
static void *wlan_static_dhd_info_buf = NULL;
static void *wlan_static_dhd_wlfc_buf = NULL;
#ifdef CONFIG_BCMDHD_PCIE
static void *wlan_static_if_flow_lkup = NULL;
static void *wlan_static_dhd_memdump_ram = NULL;
#else
static void *wlan_static_dhd_wlfc_buf = NULL;
static void *wlan_static_dhd_wlfc_hanger = NULL;
static void *wlan_static_dhd_pktid_map = NULL;
static void *wlan_static_dhd_pktid_ioctl_map = NULL;
#endif /* CONFIG_BCMDHD_PCIE */
#ifdef CONFIG_BCMDHD_PREALLOC_MEMDUMP
static void *wlan_static_dhd_memdump_ram = NULL;
#endif /* #ifdef CONFIG_BCMDHD_PREALLOC_MEMDUMP */
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;
void dhd_exit_wlan_mem(void);
@ -174,7 +176,17 @@ void
}
return wlan_static_dhd_info_buf;
}
#ifdef CONFIG_BCMDHD_PCIE
if (section == WLAN_STATIC_DHD_IF_FLOW_LKUP) {
if (size > WLAN_DHD_IF_FLOW_LKUP_SIZE) {
pr_err("request DHD_WLFC size(%lu) is bigger than"
" static size(%d).\n",
size, WLAN_DHD_WLFC_BUF_SIZE);
return NULL;
}
return wlan_static_if_flow_lkup;
}
#else
if (section == WLAN_STATIC_DHD_WLFC_BUF) {
if (size > WLAN_DHD_WLFC_BUF_SIZE) {
pr_err("request DHD_WLFC size(%lu) is bigger than"
@ -194,17 +206,8 @@ void
}
return wlan_static_dhd_wlfc_hanger;
}
if (section == WLAN_STATIC_DHD_IF_FLOW_LKUP) {
if (size > WLAN_DHD_IF_FLOW_LKUP_SIZE) {
pr_err("request DHD_WLFC size(%lu) is bigger than"
" static size(%d).\n",
size, WLAN_DHD_WLFC_BUF_SIZE);
return NULL;
}
return wlan_static_if_flow_lkup;
}
#endif /* CONFIG_BCMDHD_PCIE */
#ifdef CONFIG_BCMDHD_PREALLOC_MEMDUMP
if (section == WLAN_STATIC_DHD_MEMDUMP_RAM) {
if (size > WLAN_DHD_MEMDUMP_SIZE) {
pr_err("request DHD_MEMDUMP_RAM size(%lu) is bigger"
@ -214,27 +217,7 @@ void
}
return wlan_static_dhd_memdump_ram;
}
if (section == WLAN_STATIC_DHD_PKTID_MAP) {
if (size > WLAN_DHD_PKTID_MAP_SIZE) {
pr_err("request DHD_PKTID_MAP size(%lu) is bigger than"
" static size(%d).\n",
size, WLAN_DHD_PKTID_MAP_SIZE);
return NULL;
}
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"
" static size(%d).\n",
size, WLAN_DHD_PKTID_IOCTL_MAP_SIZE);
return NULL;
}
return wlan_static_dhd_pktid_ioctl_map;
}
#endif /* CONFIG_BCMDHD_PREALLOC_MEMDUMP */
if (section == WLAN_STATIC_DHD_LOG_DUMP_BUF) {
if (size > DHD_LOG_DUMP_BUF_SIZE) {
pr_err("request DHD_LOG_DUMP_BUF size(%lu) is bigger then"
@ -255,16 +238,6 @@ void
return wlan_static_dhd_log_dump_buf_ex;
}
if (section == WLAN_STATIC_DHD_PKTLOG_DUMP_BUF) {
if (size > DHD_PKTLOG_DUMP_BUF_SIZE) {
pr_err("request DHD_PKTLOG_DUMP_BUF size(%lu) is bigger then"
" static size(%d).\n",
size, DHD_PKTLOG_DUMP_BUF_SIZE);
return NULL;
}
return wlan_static_dhd_pktlog_dump_buf;
}
if ((section < 0) || (section >= PREALLOC_WLAN_SEC_NUM)) {
return NULL;
}
@ -277,6 +250,13 @@ void
}
EXPORT_SYMBOL(dhd_wlan_mem_prealloc);
#ifdef DHD_DUMP_BUF_KVMALLOC
#define DUMP_BUF_MALLOC(size) kvmalloc(size, GFP_KERNEL)
#define DUMP_BUF_MFREE(addr) kvfree(addr)
#else
#define DUMP_BUF_MALLOC(size) kmalloc(size, GFP_KERNEL)
#define DUMP_BUF_MFREE(addr) kfree(addr)
#endif /* DHD_DUMP_BUF_KVMALLOC */
int
dhd_init_wlan_mem(void)
{
@ -311,8 +291,13 @@ dhd_init_wlan_mem(void)
for (i = 0; i < PREALLOC_WLAN_SEC_NUM; i++) {
if (wlan_mem_array[i].size > 0) {
#ifdef CONFIG_BCMDHD_PCIE
wlan_mem_array[i].mem_ptr =
kvmalloc(wlan_mem_array[i].size, GFP_KERNEL);
#else
wlan_mem_array[i].mem_ptr =
kmalloc(wlan_mem_array[i].size, GFP_KERNEL);
#endif /* CONFIG_BCMDHD_PCIE */
if (!wlan_mem_array[i].mem_ptr) {
pr_err("Failed to mem_alloc for WLAN\n");
@ -321,59 +306,55 @@ dhd_init_wlan_mem(void)
}
}
#ifdef CONFIG_BCMDHD_PCIE
wlan_static_scan_buf0 = kvmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL);
#else
wlan_static_scan_buf0 = kmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL);
#endif /* CONFIG_BCMDHD_PCIE */
if (!wlan_static_scan_buf0) {
pr_err("Failed to alloc wlan_static_scan_buf0\n");
goto err_mem_alloc;
}
#ifdef CONFIG_BCMDHD_PCIE
wlan_static_scan_buf1 = kvmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL);
#else
wlan_static_scan_buf1 = kmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL);
#endif /* CONFIG_BCMDHD_PCIE */
if (!wlan_static_scan_buf1) {
pr_err("Failed to alloc wlan_static_scan_buf1\n");
goto err_mem_alloc;
}
wlan_static_dhd_log_dump_buf = kmalloc(DHD_LOG_DUMP_BUF_SIZE, GFP_KERNEL);
wlan_static_dhd_log_dump_buf = DUMP_BUF_MALLOC(DHD_LOG_DUMP_BUF_SIZE);
if (!wlan_static_dhd_log_dump_buf) {
pr_err("Failed to alloc wlan_static_dhd_log_dump_buf\n");
goto err_mem_alloc;
}
wlan_static_dhd_log_dump_buf_ex = kmalloc(DHD_LOG_DUMP_BUF_EX_SIZE, GFP_KERNEL);
wlan_static_dhd_log_dump_buf_ex = DUMP_BUF_MALLOC(DHD_LOG_DUMP_BUF_EX_SIZE);
if (!wlan_static_dhd_log_dump_buf_ex) {
pr_err("Failed to alloc wlan_static_dhd_log_dump_buf_ex\n");
goto err_mem_alloc;
}
#ifdef CONFIG_BCMDHD_PCIE
wlan_static_dhd_info_buf = kvmalloc(WLAN_DHD_INFO_BUF_SIZE, GFP_KERNEL);
#else
wlan_static_dhd_info_buf = kmalloc(WLAN_DHD_INFO_BUF_SIZE, GFP_KERNEL);
#endif /* CONFIG_BCMDHD_PCIE */
if (!wlan_static_dhd_info_buf) {
pr_err("Failed to alloc wlan_static_dhd_info_buf\n");
goto err_mem_alloc;
}
#ifdef CONFIG_BCMDHD_PCIE
wlan_static_if_flow_lkup = kmalloc(WLAN_DHD_IF_FLOW_LKUP_SIZE,
wlan_static_if_flow_lkup = kvmalloc(WLAN_DHD_IF_FLOW_LKUP_SIZE,
GFP_KERNEL);
if (!wlan_static_if_flow_lkup) {
pr_err("Failed to alloc wlan_static_if_flow_lkup\n");
goto err_mem_alloc;
}
#ifdef CONFIG_BCMDHD_PREALLOC_PKTIDMAP
wlan_static_dhd_pktid_map = kmalloc(WLAN_DHD_PKTID_MAP_SIZE,
GFP_KERNEL);
if (!wlan_static_dhd_pktid_map) {
pr_err("Failed to alloc wlan_static_dhd_pktid_map\n");
goto err_mem_alloc;
}
wlan_static_dhd_pktid_ioctl_map = kmalloc(WLAN_DHD_PKTID_IOCTL_MAP_SIZE,
GFP_KERNEL);
if (!wlan_static_dhd_pktid_ioctl_map) {
pr_err("Failed to alloc wlan_static_dhd_pktid_ioctl_map\n");
goto err_mem_alloc;
}
#endif /* CONFIG_BCMDHD_PREALLOC_PKTIDMAP */
#else
wlan_static_dhd_wlfc_buf = kmalloc(WLAN_DHD_WLFC_BUF_SIZE,
GFP_KERNEL);
@ -391,19 +372,13 @@ dhd_init_wlan_mem(void)
#endif /* CONFIG_BCMDHD_PCIE */
#ifdef CONFIG_BCMDHD_PREALLOC_MEMDUMP
wlan_static_dhd_memdump_ram = kmalloc(WLAN_DHD_MEMDUMP_SIZE, GFP_KERNEL);
wlan_static_dhd_memdump_ram = DUMP_BUF_MALLOC(WLAN_DHD_MEMDUMP_SIZE);
if (!wlan_static_dhd_memdump_ram) {
pr_err("Failed to alloc wlan_static_dhd_memdump_ram\n");
goto err_mem_alloc;
}
#endif /* CONFIG_BCMDHD_PREALLOC_MEMDUMP */
wlan_static_dhd_pktlog_dump_buf = kmalloc(DHD_PKTLOG_DUMP_BUF_SIZE, GFP_KERNEL);
if (!wlan_static_dhd_pktlog_dump_buf) {
pr_err("Failed to alloc wlan_static_dhd_pktlog_dump_buf\n");
goto err_mem_alloc;
}
pr_err("%s: WIFI MEM Allocated\n", __FUNCTION__);
return 0;
@ -432,25 +407,14 @@ dhd_exit_wlan_mem(void)
#ifdef CONFIG_BCMDHD_PREALLOC_MEMDUMP
if (wlan_static_dhd_memdump_ram) {
kfree(wlan_static_dhd_memdump_ram);
DUMP_BUF_MFREE(wlan_static_dhd_memdump_ram);
}
#endif /* CONFIG_BCMDHD_PREALLOC_MEMDUMP */
#ifdef CONFIG_BCMDHD_PCIE
if (wlan_static_if_flow_lkup) {
kfree(wlan_static_if_flow_lkup);
kvfree(wlan_static_if_flow_lkup);
}
#ifdef CONFIG_BCMDHD_PREALLOC_PKTIDMAP
if (wlan_static_dhd_pktid_map) {
kfree(wlan_static_dhd_pktid_map);
}
if (wlan_static_dhd_pktid_ioctl_map) {
kfree(wlan_static_dhd_pktid_ioctl_map);
}
#endif /* CONFIG_BCMDHD_PREALLOC_PKTIDMAP */
#else
if (wlan_static_dhd_wlfc_buf) {
kfree(wlan_static_dhd_wlfc_buf);
@ -461,32 +425,44 @@ dhd_exit_wlan_mem(void)
}
#endif /* CONFIG_BCMDHD_PCIE */
if (wlan_static_dhd_info_buf) {
#ifdef CONFIG_BCMDHD_PCIE
kvfree(wlan_static_dhd_info_buf);
#else
kfree(wlan_static_dhd_info_buf);
#endif /* CONFIG_BCMDHD_PCIE */
}
if (wlan_static_dhd_log_dump_buf) {
kfree(wlan_static_dhd_log_dump_buf);
DUMP_BUF_MFREE(wlan_static_dhd_log_dump_buf);
}
if (wlan_static_dhd_log_dump_buf_ex) {
kfree(wlan_static_dhd_log_dump_buf_ex);
DUMP_BUF_MFREE(wlan_static_dhd_log_dump_buf_ex);
}
if (wlan_static_scan_buf1) {
#ifdef CONFIG_BCMDHD_PCIE
kvfree(wlan_static_scan_buf1);
#else
kfree(wlan_static_scan_buf1);
#endif /* CONFIG_BCMDHD_PCIE */
}
if (wlan_static_scan_buf0) {
#ifdef CONFIG_BCMDHD_PCIE
kvfree(wlan_static_scan_buf0);
#else
kfree(wlan_static_scan_buf0);
}
if (wlan_static_dhd_pktlog_dump_buf) {
kfree(wlan_static_dhd_pktlog_dump_buf);
#endif /* CONFIG_BCMDHD_PCIE */
}
for (i = 0; i < PREALLOC_WLAN_SEC_NUM; i++) {
if (wlan_mem_array[i].mem_ptr) {
#ifdef CONFIG_BCMDHD_PCIE
kvfree(wlan_mem_array[i].mem_ptr);
#else
kfree(wlan_mem_array[i].mem_ptr);
#endif /* CONFIG_BCMDHD_PCIE */
}
}

View File

@ -1,283 +0,0 @@
/*
* Platform Dependent file for Qualcomm MSM/APQ
*
* 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/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/skbuff.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>
#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 */
#define WIFI_TURNON_DELAY 200
static int wlan_reg_on = -1;
#define DHD_DT_COMPAT_ENTRY "android,bcmdhd_wlan"
#ifdef CUSTOMER_HW2
#define WIFI_WL_REG_ON_PROPNAME "wl_reg_on"
#else
#define WIFI_WL_REG_ON_PROPNAME "wlan-en-gpio"
#endif /* CUSTOMER_HW2 */
#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 /* MSM PCIE Platforms */
#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE
static int wlan_host_wake_up = -1;
static int wlan_host_wake_irq = 0;
#ifdef CUSTOMER_HW2
#define WIFI_WLAN_HOST_WAKE_PROPNAME "wl_host_wake"
#else
#define WIFI_WLAN_HOST_WAKE_PROPNAME "wlan-host-wake-gpio"
#endif /* CUSTOMER_HW2 */
#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */
int __init
dhd_wifi_init_gpio(void)
{
char *wlan_node = DHD_DT_COMPAT_ENTRY;
struct device_node *root_node = NULL;
root_node = of_find_compatible_node(NULL, NULL, wlan_node);
if (!root_node) {
WARN(1, "failed to get device node of BRCM WLAN\n");
return -ENODEV;
}
/* ========== WLAN_PWR_EN ============ */
wlan_reg_on = of_get_named_gpio(root_node, WIFI_WL_REG_ON_PROPNAME, 0);
printk(KERN_INFO "%s: gpio_wlan_power : %d\n", __FUNCTION__, wlan_reg_on);
if (gpio_request_one(wlan_reg_on, GPIOF_OUT_INIT_LOW, "WL_REG_ON")) {
printk(KERN_ERR "%s: Faiiled to request gpio %d for WL_REG_ON\n",
__FUNCTION__, wlan_reg_on);
} else {
printk(KERN_ERR "%s: gpio_request WL_REG_ON done - WLAN_EN: GPIO %d\n",
__FUNCTION__, wlan_reg_on);
}
if (gpio_direction_output(wlan_reg_on, 1)) {
printk(KERN_ERR "%s: WL_REG_ON failed to pull up\n", __FUNCTION__);
} else {
printk(KERN_ERR "%s: WL_REG_ON is pulled up\n", __FUNCTION__);
}
if (gpio_get_value(wlan_reg_on)) {
printk(KERN_INFO "%s: Initial WL_REG_ON: [%d]\n",
__FUNCTION__, gpio_get_value(wlan_reg_on));
}
/* Wait for WIFI_TURNON_DELAY due to power stability */
msleep(WIFI_TURNON_DELAY);
#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE
/* ========== WLAN_HOST_WAKE ============ */
wlan_host_wake_up = of_get_named_gpio(root_node, WIFI_WLAN_HOST_WAKE_PROPNAME, 0);
printk(KERN_INFO "%s: gpio_wlan_host_wake : %d\n", __FUNCTION__, wlan_host_wake_up);
#ifndef CUSTOMER_HW2
if (gpio_request_one(wlan_host_wake_up, GPIOF_IN, "WLAN_HOST_WAKE")) {
printk(KERN_ERR "%s: Faiiled 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"
" - WLAN_HOST_WAKE: GPIO %d\n",
__FUNCTION__, wlan_host_wake_up);
}
#endif /* !CUSTOMER_HW2 */
gpio_direction_input(wlan_host_wake_up);
wlan_host_wake_irq = gpio_to_irq(wlan_host_wake_up);
#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */
#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;
}
int
dhd_wlan_power(int onoff)
{
printk(KERN_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__);
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));
} else {
printk("[%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__);
}
}
} else {
if (gpio_direction_output(wlan_reg_on, 0)) {
printk(KERN_ERR "%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));
}
}
return 0;
}
EXPORT_SYMBOL(dhd_wlan_power);
static int
dhd_wlan_reset(int onoff)
{
return 0;
}
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 */
.end = 0, /* Dummy */
.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_wifi_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:
printk(KERN_INFO"%s: FINISH.......\n", __FUNCTION__);
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_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
late_initcall(dhd_wlan_init);
#endif /* CONFIG_DEFERRED_INITCALLS */
#else
device_initcall(dhd_wlan_init);
#endif /* MSM PCIE Platforms */
#endif /* !BCMDHD_MODULAR */

View File

@ -1,7 +1,7 @@
/*
* Debug/trace/assert driver definitions for Dongle Host Driver.
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -29,102 +29,38 @@
#if defined(NDIS)
#include "wl_nddbg.h"
#endif /* defined(NDIS) */
#ifdef DHD_LOG_DUMP
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 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][wlan]", dhd_dbg_get_system_timestamp()
#else
#define DBG_PRINT_PREFIX
#include <dhd_log_dump.h>
#endif
#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING
/* Only for writing to ring */
#define DHD_INFO_RING(args) DHD_ERROR(args)
/* FW_VERBOSE RING */
#define DHD_LOG_DUMP_FWLOG DHD_LOG_DUMP_WRITE_EX
#define DHD_LOG_DUMP_FWLOG_TS DHD_LOG_DUMP_WRITE_EX_TS
#else
#define DHD_INFO_RING(args)
/* DLD_BUF_TYPE_GENERAL */
#define DHD_LOG_DUMP_FWLOG DHD_LOG_DUMP_WRITE
#define DHD_LOG_DUMP_FWLOG_TS DHD_LOG_DUMP_WRITE_TS
#endif
#ifdef CUSTOM_PREFIX
#define DBG_PRINT_PREFIX "[%s]"CUSTOM_PREFIX, OSL_GET_RTCTIME()
#elif defined(CUSTOM_PREFIX_NORTCTIME)
#define DBG_PRINT_PREFIX CUSTOM_PREFIX_NORTCTIME
#define DBG_PRINT_SYSTEM_TIME pr_cont(DBG_PRINT_PREFIX)
#define DHD_CONS_ONLY(args) \
do { \
DBG_PRINT_SYSTEM_TIME; \
pr_cont args; \
} while (0)
#else
#define DBG_PRINT_SYSTEM_TIME
#define DHD_CONS_ONLY(args) do { printf args;} while (0)
#endif /* CUSTOM_PREFIX */
#if defined(BCMDBG) || defined(DHD_DEBUG)
@ -139,38 +75,32 @@ extern char* dhd_dbg_get_system_timestamp(void);
#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_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_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) { \
printf args; \
} \
if (dhd_log_level & DHD_ERROR_VAL) { \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING
#define DHD_INFO(args) \
do { \
if (dhd_msg_level & DHD_INFO_VAL) { \
printf args; \
} \
if (dhd_log_level & DHD_INFO_VAL) { \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#else
#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0)
#endif /* DHD_EFI */
#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
#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)
@ -183,55 +113,6 @@ do { \
#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 { \
@ -239,6 +120,9 @@ do { \
if (dhd_msg_level & DHD_ERROR_MEM_VAL) { \
printf args; \
} \
} \
if (dhd_log_level & DHD_ERROR_VAL) { \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
@ -248,12 +132,16 @@ do { \
if (dhd_msg_level & DHD_IOVAR_MEM_VAL) { \
printf args; \
} \
} \
if (dhd_log_level & DHD_ERROR_VAL) { \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_LOG_MEM(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
if (dhd_log_level & DHD_ERROR_VAL) { \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
@ -262,6 +150,8 @@ do { \
do { \
if (dhd_msg_level & DHD_EVENT_VAL) { \
printf args; \
} \
if (dhd_log_level & DHD_EVENT_VAL) { \
DHD_LOG_DUMP_WRITE_PRSRV_TS; \
DHD_LOG_DUMP_WRITE_PRSRV args; \
} \
@ -272,8 +162,10 @@ do { \
if (dhd_msg_level & DHD_PRSRV_MEM_VAL) { \
printf args; \
} \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
if (dhd_log_level & DHD_EVENT_VAL) { \
DHD_LOG_DUMP_WRITE_PRSRV_TS; \
DHD_LOG_DUMP_WRITE_PRSRV args; \
} \
} while (0)
/* Re-using 'DHD_MSGTRACE_VAL' for controlling printing of ecounter binary event
@ -286,6 +178,10 @@ do { \
if (dhd_msg_level & DHD_EVENT_VAL) { \
if (dhd_msg_level & DHD_MSGTRACE_VAL) { \
printf args; \
} \
} \
if (dhd_log_level & DHD_EVENT_VAL) { \
if (dhd_log_level & DHD_MSGTRACE_VAL) { \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
@ -295,6 +191,8 @@ do { \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
printf args; \
} \
if (dhd_log_level & DHD_ERROR_VAL) { \
DHD_LOG_DUMP_WRITE_EX_TS; \
DHD_LOG_DUMP_WRITE_EX args; \
} \
@ -312,11 +210,122 @@ do { \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
printf args; \
} \
if (dhd_log_level & DHD_ERROR_VAL) { \
DHD_LOG_DUMP_WRITE_ROAM_TS; \
DHD_LOG_DUMP_WRITE_ROAM args; \
} \
} while (0)
#endif /* DHD_EFI */
#define DHD_PKT_MON(args) \
do { \
if (dhd_msg_level & DHD_PKT_MON_VAL) { \
printf args; \
} \
if (dhd_log_level & DHD_PKT_MON_VAL) { \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_CTL(args) \
do { \
if (dhd_msg_level & DHD_CTL_VAL) { \
printf args; \
} \
if (dhd_log_level & DHD_CTL_VAL) { \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_TIMER(args) \
do { \
if (dhd_msg_level & DHD_TIMER_VAL) { \
printf args; \
} \
if (dhd_log_level & DHD_TIMER_VAL) { \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_INTR(args) \
do { \
if (dhd_msg_level & DHD_INTR_VAL) { \
printf args; \
} \
if (dhd_log_level & DHD_INTR_VAL) { \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_ISCAN(args) \
do { \
if (dhd_msg_level & DHD_ISCAN_VAL) { \
printf args; \
} \
if (dhd_log_level & DHD_ISCAN_VAL) { \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_ARPOE(args) \
do { \
if (dhd_msg_level & DHD_ARPOE_VAL) { \
printf args; \
} \
if (dhd_log_level & DHD_ARPOE_VAL) { \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_REORDER(args) \
do { \
if (dhd_msg_level & DHD_REORDER_VAL) { \
printf args; \
} \
if (dhd_log_level & DHD_REORDER_VAL) { \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_PNO(args) \
do { \
if (dhd_msg_level & DHD_PNO_VAL) { \
printf args; \
} \
if (dhd_log_level & DHD_PNO_VAL) { \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_RTT(args) \
do { \
if (dhd_msg_level & DHD_RTT_VAL) { \
printf args; \
} \
if (dhd_log_level & DHD_RTT_VAL) { \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_RPM(args) \
do { \
if (dhd_msg_level & DHD_RPM_VAL) { \
printf args; \
} \
if (dhd_log_level & DHD_RPM_VAL) { \
DHD_LOG_DUMP_WRITE_TS; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#else /* DHD_LOG_DUMP */
/* !DHD_LOG_DUMP */
#define DHD_MSGTRACE_LOG(args) do {if (dhd_msg_level & DHD_MSGTRACE_VAL) printf args;} while (0)
@ -328,50 +337,43 @@ do { \
#define DHD_PRSRV_MEM(args) DHD_EVENT(args)
#define DHD_ERROR_EX(args) DHD_ERROR(args)
#define DHD_ERROR_ROAM(args) DHD_ERROR(args)
#define DHD_PKT_MON(args) DHD_ERROR(args)
#endif /* DHD_LOG_DUMP */
#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0)
#if !defined(DHD_LOG_DUMP)
#define DHD_CTL(args) do {if (dhd_msg_level & DHD_CTL_VAL) printf args;} while (0)
#define DHD_TIMER(args) do {if (dhd_msg_level & DHD_TIMER_VAL) printf args;} while (0)
#define DHD_HDRS(args) do {if (dhd_msg_level & DHD_HDRS_VAL) printf args;} while (0)
#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)
#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_RPM(args) do {if (dhd_msg_level & DHD_RPM_VAL) printf args;} while (0)
#define DHD_PKT_MON(args) do {if (dhd_msg_level & DHD_PKT_MON_VAL) printf args;} while (0)
#endif
#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0)
#define DHD_HDRS(args) do {if (dhd_msg_level & DHD_HDRS_VAL) printf args;} while (0)
#define DHD_BYTES(args) do {if (dhd_msg_level & DHD_BYTES_VAL) printf args;} while (0)
#define DHD_GLOM(args) do {if (dhd_msg_level & DHD_GLOM_VAL) printf args;} while (0)
#define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) printf args;} while (0)
#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)
#if defined(DHD_LOG_PRINT_RATE_LIMIT)
#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_FW_VERBOSE(args) \
do { \
if (dbgring_msg_level & DHD_FWLOG_VAL) { \
DHD_LOG_DUMP_WRITE_EX args; \
} \
do { \
if (dhd_msg_level & DHD_FWLOG_VAL) { \
if (control_logtrace && !log_print_threshold) \
printf args; \
} \
if (dhd_log_level & DHD_FWLOG_VAL) { \
DHD_LOG_DUMP_FWLOG_TS; \
DHD_LOG_DUMP_FWLOG args; \
} \
} while (0)
#else
#define DHD_FWLOG(args) \
do { \
if (dhd_msg_level & DHD_FWLOG_VAL) { \
@ -380,7 +382,7 @@ do { \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#endif /* DHD_EFI */
#endif
#else /* DHD_LOG_DUMP */
#if defined(NDIS) && (NDISVER >= 0x0630)
#define DHD_FWLOG(args) do {if (dhd_msg_level & DHD_FWLOG_VAL) \
@ -391,20 +393,11 @@ do { \
#endif /* DHD_LOG_DUMP */
#define DHD_DBGIF(args) do {if (dhd_msg_level & DHD_DBGIF_VAL) printf args;} while (0)
#define DHD_TXFLOWCTL(args) DHD_RPM(args)
#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)
#define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL)
@ -442,25 +435,6 @@ do { \
{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_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_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_TRACE(args)
#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) \
@ -478,19 +452,8 @@ do { \
#define DHD_INTR(args)
#define DHD_GLOM(args)
#if defined(DHD_EFI) && defined(DHD_LOG_DUMP)
#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)
#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)
@ -502,61 +465,21 @@ do { \
#define DHD_RTT(args)
#define DHD_PKT_MON(args)
#if defined(DHD_EFI) && defined(DHD_LOG_DUMP)
#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_FWLOG(args) DHD_MSGTRACE_LOG(args)
#else
#define DHD_MSGTRACE_LOG(args)
#define DHD_FWLOG(args)
#endif /* DHD_EFI && DHD_LOG_DUMP */
#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_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) { \
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_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 */
#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_RPM(args) DHD_ERROR(args)
#define DHD_TXFLOWCTL(args) DHD_ERROR(args)
#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
#define DHD_TRACE_ON() 0
@ -616,21 +539,34 @@ do { \
#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;
extern int dhd_log_level;
#ifdef DHD_LOG_PRINT_RATE_LIMIT
extern int log_print_threshold;
#endif /* DHD_LOG_PRINT_RATE_LIMIT */
#ifdef DHD_IOVAR_LOG_FILTER_DUMP
#define DHD_IOVAR_LOG_CHECK(dhd_pub, ioc_cmd, ioc_msg) \
dhd_iovar_log_dump_check(dhd_pub, ioc_cmd, ioc_msg)
#else
#define DHD_IOVAR_LOG_CHECK(dhd_pub, ioc_cmd, ioc_msg) TRUE
#endif /* DHD_IOVAR_LOG_FILTER_DUMP */
#define DHD_IOVAR_LOG(dhd_pub, ioc_cmd, ioc_msg, fmt) \
do { \
if (DHD_IOVAR_LOG_CHECK(dhd_pub, ioc_cmd, ioc_msg)) { \
DHD_IOVAR_MEM(fmt); \
} else { \
DHD_TRACE(fmt); \
} \
} while (0)
/* DHD_PRINT - informational non-error messages which need to be always printed */
#define DHD_PRINT DHD_ERROR
/* Defines msg bits */
#include <dhdioctl.h>

View File

@ -1,7 +1,7 @@
/*
* DHD debug ring API and structures - implementation
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -30,6 +30,7 @@
#include <dhd.h>
#include <dhd_dbg.h>
#include <dhd_dbg_ring.h>
#include <dhd_debug.h>
dhd_dbg_ring_t *
dhd_dbg_ring_alloc_init(dhd_pub_t *dhd, uint16 ring_id,
@ -97,7 +98,14 @@ 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;
/* for DEBUG_DUMP and MEM_DUMP, buffer can be NULL
* since act as delayed allocation or fake rings
*/
if (id != DEBUG_DUMP_RING1_ID && id != DEBUG_DUMP_RING2_ID &&
id != MEM_DUMP_RING_ID) {
return BCME_NOMEM;
}
buf = NULL;
} else {
buf = allocd_buf;
}
@ -120,6 +128,17 @@ dhd_dbg_ring_init(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring, uint16 id, uint8 *name,
return BCME_OK;
}
int
dhd_dbg_ring_set_buf(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring, void *buf)
{
unsigned long flags = 0;
DHD_DBG_RING_LOCK(ring->lock, flags);
ring->ring_buf = buf;
DHD_DBG_RING_UNLOCK(ring->lock, flags);
return BCME_OK;
}
void
dhd_dbg_ring_deinit(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring)
{
@ -182,6 +201,38 @@ dhd_dbg_ring_get_pending_len(dhd_dbg_ring_t *ring)
return pending_len;
}
#ifdef DHD_PKT_LOGGING_DBGRING
int
dhd_dbg_ring_update(void *dbg_ring, uint32 w_len)
{
unsigned long flags;
dhd_dbg_ring_t *ring = (dhd_dbg_ring_t *)dbg_ring;
if (ring->id != PACKET_LOG_RING_ID) {
return BCME_UNSUPPORTED;
}
DHD_DBG_RING_LOCK(ring->lock, flags);
if (ring->state != RING_ACTIVE) {
DHD_DBG_RING_UNLOCK(ring->lock, flags);
return BCME_OK;
}
/* update statistics */
ring->stat.written_records++;
ring->stat.written_bytes += w_len;
DHD_DBGIF(("%s : RING%d[%s] written_records %d, written_bytes %d, read_bytes=%d,"
" ring->threshold=%d, wp=%d, rp=%d\n", __FUNCTION__, ring->id, ring->name,
ring->stat.written_records, ring->stat.written_bytes, ring->stat.read_bytes,
ring->threshold, ring->wp, ring->rp));
DHD_DBG_RING_UNLOCK(ring->lock, flags);
return BCME_OK;
}
#endif /* DHD_PKT_LOGGING_DBGRING */
int
dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data)
{
@ -189,11 +240,22 @@ dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data)
uint32 w_len;
uint32 avail_size;
dhd_dbg_ring_entry_t *w_entry, *r_entry;
int ret;
if (!ring || !hdr || !data) {
return BCME_BADARG;
}
#if defined(__linux__)
/* Prevents the case of accessing the ring buffer in the HardIRQ context.
* If an interrupt arise after holding ring lock, It could try the same lock.
* This is to use the ring lock as spin_lock_bh instead of spin_lock_irqsave.
*/
if (in_irq()) {
return BCME_BUSY;
}
#endif /* defined(__linux__) */
DHD_DBG_RING_LOCK(ring->lock, flags);
if (ring->state != RING_ACTIVE) {
@ -254,7 +316,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_DBGIF(("%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));
@ -286,7 +348,7 @@ dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data)
/* check before writing to the ring */
if (ring->wp + w_len >= ring->ring_size) {
DHD_ERROR(("%s: RING%d[%s] wp pointed out of ring boundary, "
DHD_DBGIF(("%s: RING%d[%s] wp pointed out of ring boundary, "
"wp=%d, ring_size=%d, w_len=%u\n", __FUNCTION__, ring->id,
ring->name, ring->wp, ring->ring_size, w_len));
ASSERT(0);
@ -296,10 +358,22 @@ dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data)
w_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf + ring->wp);
/* header */
memcpy(w_entry, hdr, DBG_RING_ENTRY_SIZE);
ret = memcpy_s(w_entry, avail_size, hdr, DBG_RING_ENTRY_SIZE);
if (ret) {
DHD_ERROR((" memcpy_s() error : %d, destsz: %d, n: %d\n",
ret, avail_size, (int)DBG_RING_ENTRY_SIZE));
return BCME_ERROR;
}
w_entry->len = hdr->len;
/* payload */
memcpy((char *)w_entry + DBG_RING_ENTRY_SIZE, data, w_entry->len);
avail_size -= DBG_RING_ENTRY_SIZE;
ret = memcpy_s((char *)w_entry + DBG_RING_ENTRY_SIZE,
avail_size, data, w_entry->len);
if (ret) {
DHD_ERROR((" memcpy_s() error : %d, destsz: %d, n: %d\n",
ret, avail_size, w_entry->len));
return BCME_ERROR;
}
/* update write pointer */
ring->wp += w_len;
@ -325,11 +399,13 @@ 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
@ -353,7 +429,7 @@ dhd_dbg_ring_pull_single(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool
/* Boundary Check */
rlen = ENTRY_LENGTH(r_entry);
if ((ring->rp + rlen) > ring->ring_size) {
DHD_ERROR(("%s: entry len %d is out of boundary of ring size %d,"
DHD_DBGIF(("%s: entry len %d is out of boundary of ring size %d,"
" current ring %d[%s] - rp=%d\n", __FUNCTION__, rlen,
ring->ring_size, ring->id, ring->name, ring->rp));
rlen = 0;
@ -368,12 +444,17 @@ dhd_dbg_ring_pull_single(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool
buf = (char *)r_entry;
}
if (rlen > buf_len) {
DHD_ERROR(("%s: buf len %d is too small for entry len %d\n",
DHD_DBGIF(("%s: buf len %d is too small for entry len %d\n",
__FUNCTION__, buf_len, rlen));
DHD_ERROR(("%s: ring %d[%s] - ring size=%d, wp=%d, rp=%d\n",
DHD_DBGIF(("%s: ring %d[%s] - ring size=%d, wp=%d, rp=%d\n",
__FUNCTION__, ring->id, ring->name, ring->ring_size,
ring->wp, ring->rp));
ASSERT(0);
/* The state of ringbuffer is different between calculating buf_len
* and current. ring->rp have chance to be update by pushing data
* to ring buffer when unlocking after calculating buf_len.
* But, It doesn't need to ASSERT because we only send up the
* entries stored so far.
*/
rlen = 0;
goto exit;
}
@ -391,7 +472,7 @@ dhd_dbg_ring_pull_single(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool
ring->rem_len = 0;
}
if (ring->rp >= ring->ring_size) {
DHD_ERROR(("%s: RING%d[%s] rp pointed out of ring boundary,"
DHD_DBGIF(("%s: RING%d[%s] rp pointed out of ring boundary,"
" rp=%d, ring_size=%d\n", __FUNCTION__, ring->id,
ring->name, ring->rp, ring->ring_size));
ASSERT(0);
@ -403,21 +484,27 @@ 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;
}
int
dhd_dbg_ring_pull(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool strip_hdr)
dhd_dbg_ring_pull(dhd_dbg_ring_t *ring, void *data, uint32 buf_len,
bool strip_hdr, int *num_entries)
{
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);
@ -426,6 +513,7 @@ dhd_dbg_ring_pull(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool strip_h
data = (uint8 *)data + r_len;
buf_len -= r_len;
total_r_len += r_len;
(*num_entries)++;
}
return total_r_len;

View File

@ -1,7 +1,7 @@
/*
* DHD debug ring header file - interface
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -52,6 +52,11 @@ typedef struct dhd_dbg_ring_entry {
uint64 timestamp; /* present if has_timestamp bit is set. */
} PACKED_STRUCT dhd_dbg_ring_entry_t;
typedef struct dhd_dbg_ring_entry_pack {
uint32 magic;
int num_entries;
} PACKED_STRUCT dhd_dbg_ring_entry_pack_t;
struct ring_statistics {
/* number of bytes that was written to the buffer by driver */
uint32 written_bytes;
@ -95,7 +100,9 @@ typedef struct dhd_dbg_ring {
bool pull_inactive; /* pull contents from ring even if it is inactive */
} dhd_dbg_ring_t;
#define DBGRING_FLUSH_THRESHOLD(ring) (ring->ring_size / 3)
#define DBGRING_FLUSH_THRESHOLD(ring) \
(ring->id != PACKET_LOG_RING_ID) ? \
(ring->ring_size / 3u) : (ring->ring_size / 4u)
#define RING_STAT_TO_STATUS(ring, status) \
do { \
/* status.name/ring->name are the same length so no need to check return value */ \
@ -108,10 +115,11 @@ typedef struct dhd_dbg_ring {
status.verbose_level = ring->log_level; \
} while (0)
#define DBG_RING_PACK_MAGIC 0xDBAADBAA
#define DBG_RING_ENTRY_PACK_SIZE (sizeof(dhd_dbg_ring_entry_pack_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
#define PAYLOAD_ECNTR_MAX_LEN 1648u
#define PAYLOAD_RTT_MAX_LEN 1648u
#define PAYLOAD_BCM_TRACE_MAX_LEN 1648u
#define PENDING_LEN_MAX 0xFFFFFFFF
@ -133,9 +141,13 @@ 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);
int dhd_dbg_ring_set_buf(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring, void *buf);
#ifdef DHD_PKT_LOGGING_DBGRING
int dhd_dbg_ring_update(void *dbg_ring, uint32 w_len);
#endif /* DHD_PKT_LOGGING_DBGRING */
int dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data);
int dhd_dbg_ring_pull(dhd_dbg_ring_t *ring, void *data, uint32 buf_len,
bool strip_hdr);
bool strip_hdr, int* num_entries);
int dhd_dbg_ring_pull_single(dhd_dbg_ring_t *ring, void *data, uint32 buf_len,
bool strip_header);
uint32 dhd_dbg_ring_get_pending_len(dhd_dbg_ring_t *ring);

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* DHD debugability header file
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -41,6 +41,7 @@ enum {
DBG_DRIVER_DUMP_SUPPORTED = (1 << (7)), /* dumps driver state */
DBG_PACKET_FATE_SUPPORTED = (1 << (8)), /* tracks connection packets' fate */
DBG_NAN_EVENT_SUPPORTED = (1 << (9)), /* NAN Events */
DBG_PACKET_LOG_SUPPORTED = (1 << (10)), /* Packet log with dbgring */
};
enum {
@ -50,6 +51,14 @@ enum {
DBG_RING_ENTRY_FLAGS_HAS_TIMESTAMP = (1 << (1))
};
enum {
/* Verbose logging level to set for each debug ring buffer */
RING_LOG_LEVEL_NONE = 0,
RING_LOG_LEVEL_DEFAULT = 1,
RING_LOG_LEVEL_VERBOSE = 2,
RING_LOG_LEVEL_EXCESSIVE = 3
};
/* firmware verbose ring, ring id 1 */
#define FW_VERBOSE_RING_NAME "fw_verbose"
#define FW_VERBOSE_RING_SIZE (256 * 1024)
@ -70,13 +79,31 @@ enum {
/* ROAM stats log ring */
#define ROAM_STATS_RING_NAME "roam_stats"
#define ROAM_STATS_RING_SIZE (64 * 1024)
#define DEBUG_DUMP_RING1_NAME "debug_dump1_"
#define DEBUG_DUMP_RING1_SIZE (2 * 1024 * 1024)
#define DEBUG_DUMP_RING2_NAME "debug_dump2_"
#define DEBUG_DUMP_RING2_SIZE (2 * 1024 * 1024)
#define MEM_DUMP_RING_NAME "mem_dump"
#define MEM_DUMP_RING_SIZE (3 * 1024 * 1024)
#define DHD_DEBUG_DUMP_NETLINK_MAX (1024 * 8)
#define DHD_DEBUG_DUMP_MAX_SYNC_CNT 5u
#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 */
/* Packet log ring, ring id 7 */
#ifdef DHD_PKT_LOGGING_DBGRING
#define DHD_PACKET_LOG_RING_NAME "packet_log"
#define DHD_PACKET_LOG_RING_PKTS MIN_PKTLOG_LEN
#define DHD_PACKET_LOG_RING_SUSPEND_THRESHOLD \
(DHD_PACKET_LOG_RING_PKTS * 8u / 10u)
#define DHD_PACKET_LOG_RING_RESUME_THRESHOLD \
(DHD_PACKET_LOG_RING_PKTS * 2u / 10u)
#define DHD_PACKET_LOG_RING_SIZE \
(DHD_PACKET_LOG_RING_PKTS * sizeof(dhd_pktlog_ring_info_t))
#endif /* DHD_PKT_LOGGING_DBGRING */
#define TLV_LOG_SIZE(tlv) ((tlv) ? (sizeof(tlv_log) + (tlv)->len) : 0)
@ -90,7 +117,7 @@ enum {
#ifdef DEBUGABILITY
#define DBG_RING_ACTIVE(dhdp, ring_id) \
((dhdp)->dbg->dbg_rings[(ring_id)].state == RING_ACTIVE)
((dhdp)->dbg && (dhdp)->dbg->dbg_rings[(ring_id)].state == RING_ACTIVE)
#else
#define DBG_RING_ACTIVE(dhdp, ring_id) 0
#endif /* DEBUGABILITY */
@ -424,6 +451,16 @@ typedef enum {
/* Packet free by firmware. */
TX_PKT_FATE_FW_PKT_FREE,
/* Firmware dropped the frame after suppress retries reached max */
TX_PKT_FATE_FW_MAX_SUP_RETR,
/* Firmware forced packet lifetime expiry */
TX_PKT_FATE_FW_FORCED_EXPIRED,
#ifdef DHD_PKT_LOGGING_DBGRING
/* Indicate to wait for updating txfate. */
TX_PKT_FATE_DRV_WAIT_UPDATE = 0x80000000,
#endif /* DHD_PKT_LOGGING_DBGRING */
} wifi_tx_packet_fate;
typedef enum {
@ -627,22 +664,26 @@ typedef struct dhd_dbg_rx_info
typedef struct dhd_dbg_tx_report
{
dhd_dbg_tx_info_t *tx_pkts;
/* Indicates how many packets queued to send over the air */
uint16 pkt_pos;
/* Indicates how many packets sent over the air and received txstatus */
uint16 status_pos;
} dhd_dbg_tx_report_t;
typedef struct dhd_dbg_rx_report
{
dhd_dbg_rx_info_t *rx_pkts;
/* Indicates how many packets sent over the air and received txstatus */
uint16 pkt_pos;
} dhd_dbg_rx_report_t;
typedef void (*dbg_pullreq_t)(void *os_priv, const int ring_id);
typedef void (*dbg_urgent_noti_t) (dhd_pub_t *dhdp, const void *data, const uint32 len);
typedef int (*dbg_mon_tx_pkts_t) (dhd_pub_t *dhdp, void *pkt, uint32 pktid);
typedef int (*dbg_mon_tx_pkts_t) (dhd_pub_t *dhdp, void *pkt, uint32 pktid,
frame_type type, uint8 mgmt_acked);
typedef int (*dbg_mon_tx_status_t) (dhd_pub_t *dhdp, void *pkt,
uint32 pktid, uint16 status);
typedef int (*dbg_mon_rx_pkts_t) (dhd_pub_t *dhdp, void *pkt);
typedef int (*dbg_mon_rx_pkts_t) (dhd_pub_t *dhdp, void *pkt, frame_type type);
typedef struct dhd_dbg_pkt_mon
{
@ -682,10 +723,11 @@ typedef struct dhd_dbg {
(((status_count) >= (pkt_count)) || ((status_count) >= MAX_FATE_LOG_LEN))
#ifdef DBG_PKT_MON
#define DHD_DBG_PKT_MON_TX(dhdp, pkt, pktid) \
#define DHD_DBG_PKT_MON_TX(dhdp, pkt, pktid, type, mgmt_acked) \
do { \
if ((dhdp) && (dhdp)->dbg && (dhdp)->dbg->pkt_mon.tx_pkt_mon && (pkt)) { \
(dhdp)->dbg->pkt_mon.tx_pkt_mon((dhdp), (pkt), (pktid)); \
(dhdp)->dbg->pkt_mon.tx_pkt_mon((dhdp), (pkt), \
(pktid), (type), (mgmt_acked)); \
} \
} while (0);
#define DHD_DBG_PKT_MON_TX_STATUS(dhdp, pkt, pktid, status) \
@ -694,11 +736,11 @@ typedef struct dhd_dbg {
(dhdp)->dbg->pkt_mon.tx_status_mon((dhdp), (pkt), (pktid), (status)); \
} \
} while (0);
#define DHD_DBG_PKT_MON_RX(dhdp, pkt) \
#define DHD_DBG_PKT_MON_RX(dhdp, pkt, type) \
do { \
if ((dhdp) && (dhdp)->dbg && (dhdp)->dbg->pkt_mon.rx_pkt_mon && (pkt)) { \
if (ntoh16((pkt)->protocol) != ETHER_TYPE_BRCM) { \
(dhdp)->dbg->pkt_mon.rx_pkt_mon((dhdp), (pkt)); \
(dhdp)->dbg->pkt_mon.rx_pkt_mon((dhdp), (pkt), (type)); \
} \
} \
} while (0);
@ -708,9 +750,9 @@ typedef struct dhd_dbg {
#define DHD_DBG_PKT_MON_STOP(dhdp) \
dhd_os_dbg_stop_pkt_monitor((dhdp));
#else
#define DHD_DBG_PKT_MON_TX(dhdp, pkt, pktid)
#define DHD_DBG_PKT_MON_TX(dhdp, pkt, pktid, type, mgmt_acked)
#define DHD_DBG_PKT_MON_TX_STATUS(dhdp, pkt, pktid, status)
#define DHD_DBG_PKT_MON_RX(dhdp, pkt)
#define DHD_DBG_PKT_MON_RX(dhdp, pkt, type)
#define DHD_DBG_PKT_MON_START(dhdp)
#define DHD_DBG_PKT_MON_STOP(dhdp)
#endif /* DBG_PKT_MON */
@ -741,6 +783,8 @@ typedef struct {
#define DHD_EVENT_LOG_FMT_NUM_OFFSET 2
#define DHD_EVENT_LOG_FMT_NUM_MASK 0x3FFF
#define DHD_EXT_FMTNUM_MASK 0xF /* bits[3..0] used */
/**
* OW:- one word
* TW:- two word
@ -783,9 +827,6 @@ 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);
@ -798,9 +839,18 @@ 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, 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_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len,
int *num_entries);
int dhd_dbg_pull_single_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len,
bool strip_header);
#ifdef DHD_PKT_LOGGING_DBGRING
int dhd_dbg_update_to_ring(dhd_pub_t *dhdp, void *ring, uint32 w_len);
int dhd_dbg_pull_from_pktlog(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len);
void dhd_os_dbg_urgent_pullreq(void *os_priv, int ring_id);
#endif /* DHD_PKT_LOGGING_DBGRING */
#ifdef DHD_DEBUGABILITY_DEBUG_DUMP
int dhd_debug_dump_ring_push(dhd_pub_t *dhdp, int ring_id, uint32 len, void *data);
#endif /* DHD_DEBUGABILITY_DEBUG_DUMP */
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);
@ -816,10 +866,11 @@ extern int dhd_dbg_attach_pkt_monitor(dhd_pub_t *dhdp,
dbg_mon_tx_status_t tx_status_mon,
dbg_mon_rx_pkts_t rx_pkt_mon);
extern int dhd_dbg_start_pkt_monitor(dhd_pub_t *dhdp);
extern int dhd_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid);
extern int dhd_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt,
uint32 pktid, frame_type type, uint8 mgmt_acked);
extern int dhd_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt,
uint32 pktid, uint16 status);
extern int dhd_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt);
extern int dhd_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt, frame_type type);
extern int dhd_dbg_stop_pkt_monitor(dhd_pub_t *dhdp);
extern int dhd_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf,
uint16 req_count, uint16 *resp_count);
@ -855,10 +906,11 @@ extern int dhd_os_dbg_get_feature(dhd_pub_t *dhdp, int32 *features);
extern int dhd_os_dbg_attach_pkt_monitor(dhd_pub_t *dhdp);
extern int dhd_os_dbg_start_pkt_monitor(dhd_pub_t *dhdp);
extern int dhd_os_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt,
uint32 pktid);
uint32 pktid, frame_type type, uint8 mgmt_acked);
extern int dhd_os_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt,
uint32 pktid, uint16 status);
extern int dhd_os_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt);
extern int dhd_os_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt,
frame_type type);
extern int dhd_os_dbg_stop_pkt_monitor(dhd_pub_t *dhdp);
extern int dhd_os_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp,
void __user *user_buf, uint16 req_count, uint16 *resp_count);

View File

@ -1,7 +1,7 @@
/*
* DHD debugability Linux os layer
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -34,6 +34,9 @@
#include <net/cfg80211.h>
#include <wl_cfgvendor.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)
#include <linux/sched/clock.h>
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0) */
#include <dhd_config.h>
typedef void (*dbg_ring_send_sub_t)(void *ctx, const int ring_id, const void *data,
@ -73,6 +76,7 @@ debug_data_send(dhd_pub_t *dhdp, int ring_id, const void *data, const uint32 len
struct net_device *ndev;
dbg_ring_send_sub_t ring_sub_send;
ndev = dhd_linux_get_primary_netdev(dhdp);
if (!ndev)
return;
if (!VALID_RING(ring_id))
@ -105,11 +109,21 @@ dbg_ring_poll_worker(struct work_struct *work)
dhd_pub_t *dhdp;
int ringid;
dhd_dbg_ring_status_t ring_status;
void *buf;
void *buf, *buf_entries;
dhd_dbg_ring_entry_pack_t *pack_hdr;
dhd_dbg_ring_entry_t *hdr;
uint32 buflen, rlen;
int32 buflen, rlen, remain_buflen;
int32 alloc_len;
unsigned long flags;
BCM_REFERENCE(hdr);
if (!CAN_SLEEP()) {
DHD_CONS_ONLY(("this context should be sleepable\n"));
sched = FALSE;
goto exit;
}
GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
ring_info = container_of(d_work, linux_dbgring_info_t, work);
GCC_DIAGNOSTIC_POP();
@ -120,55 +134,126 @@ dbg_ring_poll_worker(struct work_struct *work)
ring = &dhdp->dbg->dbg_rings[ringid];
DHD_DBG_RING_LOCK(ring->lock, flags);
dhd_dbg_get_ring_status(dhdp, ringid, &ring_status);
DHD_DBG_RING_UNLOCK(ring->lock, flags);
if (ring->wp > ring->rp) {
buflen = ring->wp - ring->rp;
} else if (ring->wp < ring->rp) {
buflen = ring->ring_size - ring->rp + ring->wp;
} else {
goto exit;
#ifdef DHD_PKT_LOGGING_DBGRING
if (ringid == PACKET_LOG_RING_ID) {
struct net_device *ndev;
ndev = dhd_linux_get_primary_netdev(dhdp);
buflen = DBG_RING_ENTRY_SIZE;
buflen += dhd_os_get_pktlog_dump_size(ndev);
DHD_DBGIF(("%s: buflen: %d\n", __FUNCTION__, buflen));
alloc_len = buflen + DBG_RING_ENTRY_PACK_SIZE;
} else
#endif /* DHD_PKT_LOGGING_DBGRING */
{
DHD_DBG_RING_LOCK(ring->lock, flags);
if (ring->wp > ring->rp) {
buflen = ring->wp - ring->rp;
} else if (ring->wp < ring->rp) {
buflen = ring->ring_size - ring->rp + ring->wp;
} else {
DHD_DBG_RING_UNLOCK(ring->lock, flags);
goto exit;
}
if (buflen > ring->ring_size) {
DHD_DBG_RING_UNLOCK(ring->lock, flags);
goto exit;
}
DHD_DBG_RING_UNLOCK(ring->lock, flags);
alloc_len = NLMSG_DEFAULT_SIZE;
}
buf = VMALLOCZ(dhdp->osh, alloc_len);
if (buflen > ring->ring_size) {
goto exit;
}
buf = MALLOCZ(dhdp->osh, buflen);
if (!buf) {
DHD_ERROR(("%s failed to allocate read buf\n", __FUNCTION__));
DHD_CONS_ONLY(("%s failed to allocate read buf\n", __FUNCTION__));
sched = FALSE;
goto exit;
}
DHD_DBG_RING_UNLOCK(ring->lock, flags);
rlen = dhd_dbg_pull_from_ring(dhdp, ringid, buf, buflen);
DHD_DBG_RING_LOCK(ring->lock, flags);
pack_hdr = (dhd_dbg_ring_entry_pack_t *)buf;
pack_hdr->magic = DBG_RING_PACK_MAGIC;
buf_entries = (char *)buf + sizeof(dhd_dbg_ring_entry_pack_t);
#ifdef DHD_PKT_LOGGING_DBGRING
if (ringid == PACKET_LOG_RING_ID) {
pack_hdr->num_entries = 1u;
rlen = dhd_dbg_pull_from_pktlog(dhdp, ringid, buf_entries, buflen);
DHD_DBGIF(("%s: rlen: %d\n", __FUNCTION__, rlen));
hdr = (dhd_dbg_ring_entry_t *)buf_entries;
while (rlen > 0) {
DHD_DBG_RING_LOCK(ring->lock, flags);
ring_status.read_bytes += (rlen - DBG_RING_ENTRY_SIZE);
ring->stat.read_bytes += (rlen - DBG_RING_ENTRY_SIZE);
if (ring->stat.read_bytes > ring->stat.written_bytes) {
DHD_DBGIF(("%s READ/WRITE counter mismatched!\n", __FUNCTION__));
ring->stat.read_bytes = ring->stat.written_bytes;
}
DHD_DBGIF(("%s RING%d[%s]read_bytes %d, written_bytes %d, "
"writen_records %d\n", __FUNCTION__, ring->id, ring->name,
ring->stat.read_bytes, ring->stat.written_bytes,
ring->stat.written_records));
DHD_DBG_RING_UNLOCK(ring->lock, flags);
/* offset fw ts to host ts */
hdr->timestamp += ring_info->tsoffset;
debug_data_send(dhdp, ringid, pack_hdr,
ENTRY_LENGTH(hdr) + DBG_RING_ENTRY_PACK_SIZE, ring_status);
rlen -= ENTRY_LENGTH(hdr);
hdr = (dhd_dbg_ring_entry_t *)((char *)hdr + ENTRY_LENGTH(hdr));
}
} else
#endif /* DHD_PKT_LOGGING_DBGRING */
{
remain_buflen = buflen;
while (remain_buflen > 0) {
pack_hdr->num_entries = 0;
memset_s(buf_entries, NLMSG_DEFAULT_SIZE - DBG_RING_ENTRY_PACK_SIZE,
0, NLMSG_DEFAULT_SIZE - DBG_RING_ENTRY_PACK_SIZE);
/* Returns as much as possible with the size of the passed buffer
* rlen means the total length of multiple entries including entry hdr
*/
rlen = dhd_dbg_pull_from_ring(dhdp, ringid, buf_entries,
NLMSG_DEFAULT_SIZE - DBG_RING_ENTRY_PACK_SIZE,
&pack_hdr->num_entries);
if (rlen <= 0) {
break;
}
DHD_DBG_RING_LOCK(ring->lock, flags);
ring_status.read_bytes += rlen;
DHD_DBG_RING_UNLOCK(ring->lock, flags);
/* payload length includes pack_hdr size */
debug_data_send(dhdp, ringid, pack_hdr,
rlen + DBG_RING_ENTRY_PACK_SIZE, ring_status);
remain_buflen -= rlen;
}
}
VMFREE(dhdp->osh, buf, alloc_len);
DHD_DBG_RING_LOCK(ring->lock, flags);
if (!ring->sched_pull) {
ring->sched_pull = TRUE;
}
hdr = (dhd_dbg_ring_entry_t *)buf;
while (rlen > 0) {
ring_status.read_bytes += ENTRY_LENGTH(hdr);
/* offset fw ts to host ts */
hdr->timestamp += ring_info->tsoffset;
debug_data_send(dhdp, ringid, hdr, ENTRY_LENGTH(hdr),
ring_status);
rlen -= ENTRY_LENGTH(hdr);
hdr = (dhd_dbg_ring_entry_t *)((char *)hdr + ENTRY_LENGTH(hdr));
}
MFREE(dhdp->osh, buf, buflen);
DHD_DBG_RING_UNLOCK(ring->lock, flags);
exit:
if (sched) {
/* retrigger the work at same interval */
if ((ring_status.written_bytes == ring_status.read_bytes) &&
(ring_info->interval)) {
schedule_delayed_work(d_work, ring_info->interval);
if ((ring_info->interval)) {
if ((ring_status.written_bytes == ring_status.read_bytes) ||
#ifdef DHD_PKT_LOGGING_DBGRING
(ringid == PACKET_LOG_RING_ID)) {
#else
FALSE) {
#endif /* DHD_PKT_LOGGING_DBGRING */
schedule_delayed_work(d_work, ring_info->interval);
}
}
}
DHD_DBG_RING_UNLOCK(ring->lock, flags);
return;
}
@ -205,8 +290,9 @@ dhd_os_start_logging(dhd_pub_t *dhdp, char *ring_name, int log_level,
if (!VALID_RING(ring_id))
return BCME_UNSUPPORTED;
DHD_INFO(("%s , log_level : %d, time_intval : %d, threshod %d Bytes\n",
__FUNCTION__, log_level, time_intval, threshold));
DHD_ERROR(("%s , ring_id : %d log_level : %d, "
"time_intval : %d, threshod %d Bytes\n",
__FUNCTION__, ring_id, log_level, time_intval, threshold));
/* change the configuration */
ret = dhd_dbg_set_configuration(dhdp, ring_id, log_level, flags, threshold);
@ -248,8 +334,6 @@ dhd_os_reset_logging(dhd_pub_t *dhdp)
DHD_INFO(("%s: Stop ring buffer %d\n", __FUNCTION__, ring_id));
ring_info = &os_priv[ring_id];
/* cancel any pending work */
cancel_delayed_work_sync(&ring_info->work);
/* log level zero makes stop logging on that ring */
ring_info->log_level = 0;
ring_info->interval = 0;
@ -259,6 +343,8 @@ dhd_os_reset_logging(dhd_pub_t *dhdp)
DHD_ERROR(("dhd_set_configuration is failed : %d\n", ret));
return ret;
}
/* cancel any pending work */
cancel_delayed_work_sync(&ring_info->work);
}
return ret;
}
@ -365,7 +451,7 @@ dhd_os_push_push_ring_data(dhd_pub_t *dhdp, int ring_id, void *data, int32 data_
}
#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
ret = dhd_dbg_push_to_ring(dhdp, ring_id, &msg_hdr, event_data);
if (ret) {
if (ret && ret != BCME_BUSY) {
DHD_ERROR(("%s : failed to push data into the ring (%d) with ret(%d)\n",
__FUNCTION__, ring_id, ret));
}
@ -388,9 +474,10 @@ dhd_os_dbg_start_pkt_monitor(dhd_pub_t *dhdp)
}
int
dhd_os_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid)
dhd_os_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid,
frame_type type, uint8 mgmt_acked)
{
return dhd_dbg_monitor_tx_pkts(dhdp, pkt, pktid);
return dhd_dbg_monitor_tx_pkts(dhdp, pkt, pktid, type, mgmt_acked);
}
int
@ -401,9 +488,9 @@ dhd_os_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid,
}
int
dhd_os_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt)
dhd_os_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt, frame_type type)
{
return dhd_dbg_monitor_rx_pkts(dhdp, pkt);
return dhd_dbg_monitor_rx_pkts(dhdp, pkt, type);
}
int
@ -465,6 +552,9 @@ dhd_os_dbg_get_feature(dhd_pub_t *dhdp, int32 *features)
}
#endif /* DBG_PKT_MON */
#endif /* DEBUGABILITY */
#ifdef DHD_PKT_LOGGING_DBGRING
*features |= DBG_PACKET_LOG_SUPPORTED;
#endif /* DHD_PKT_LOGGING_DBGRING */
return ret;
}
@ -478,6 +568,14 @@ dhd_os_dbg_pullreq(void *os_priv, int ring_id)
schedule_delayed_work(&ring_info->work, 0);
}
#ifdef DHD_PKT_LOGGING_DBGRING
void
dhd_os_dbg_urgent_pullreq(void *os_priv, int ring_id)
{
dhd_os_dbg_pullreq(os_priv, ring_id);
}
#endif /* DHD_PKT_LOGGING_DBGRING */
int
dhd_os_dbg_attach(dhd_pub_t *dhdp)
{
@ -486,9 +584,12 @@ dhd_os_dbg_attach(dhd_pub_t *dhdp)
int ring_id;
/* os_dbg data */
os_priv = MALLOCZ(dhdp->osh, sizeof(*os_priv) * DEBUG_RING_ID_MAX);
if (!os_priv)
os_priv = VMALLOCZ(dhdp->osh, sizeof(*os_priv) * DEBUG_RING_ID_MAX);
if (!os_priv) {
DHD_ERROR(("%s:%d: VMALLOC failed for os_priv, size %d\n", __FUNCTION__,
__LINE__, (uint32)sizeof(*os_priv) * DEBUG_RING_ID_MAX));
return BCME_NOMEM;
}
for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX;
ring_id++) {
@ -499,8 +600,9 @@ dhd_os_dbg_attach(dhd_pub_t *dhdp)
}
ret = dhd_dbg_attach(dhdp, dhd_os_dbg_pullreq, dhd_os_dbg_urgent_notifier, os_priv);
if (ret)
MFREE(dhdp->osh, os_priv, sizeof(*os_priv) * DEBUG_RING_ID_MAX);
if (ret) {
VMFREE(dhdp->osh, os_priv, sizeof(*os_priv) * DEBUG_RING_ID_MAX);
}
return ret;
}
@ -522,7 +624,7 @@ dhd_os_dbg_detach(dhd_pub_t *dhdp)
cancel_delayed_work_sync(&ring_info->work);
}
}
MFREE(dhdp->osh, os_priv, sizeof(*os_priv) * DEBUG_RING_ID_MAX);
VMFREE(dhdp->osh, os_priv, sizeof(*os_priv) * DEBUG_RING_ID_MAX);
return dhd_dbg_detach(dhdp);
}

View File

@ -1,7 +1,7 @@
/*
* Wifi dongle status Filter and Report
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -63,11 +63,7 @@
#endif /* IL_BIGENDINAN */
#define DHD_FILTER_ERR_INTERNAL(fmt, ...) DHD_ERROR(("EWPF-" fmt, ##__VA_ARGS__))
#ifdef DHD_REPLACE_LOG_INFO_TO_TRACE
#define DHD_FILTER_TRACE_INTERNAL(fmt, ...) DHD_TRACE(("EWPF-" fmt, ##__VA_ARGS__))
#else
#define DHD_FILTER_TRACE_INTERNAL(fmt, ...) DHD_INFO(("EWPF-" fmt, ##__VA_ARGS__))
#endif /* DHD_REPLACE_LOG_INFO_TO_TRACE */
#define DHD_FILTER_ERR(x) DHD_FILTER_ERR_INTERNAL x
#define DHD_FILTER_TRACE(x) DHD_FILTER_TRACE_INTERNAL x
@ -92,7 +88,7 @@
#define EWPF_SLICE_MAIN 0 /* SLICE ID for 5GHZ */
#define EWPF_SLICE_AUX 1 /* SLICE ID for 2GHZ */
#define EWPF_MAX_IFACE 2 /* MAX IFACE supported, 0: STA */
#define EWPF_MAX_IFACE 3 /* MAX IFACE supported */
#define EWPF_MAX_EVENT 1 /* MAX EVENT counter supported */
#define EWPF_MAX_KEY_INFO 1 /* MAX KEY INFO counter supported */
@ -131,6 +127,7 @@ typedef struct {
wl_periodic_compact_cntrs_v1_t compact_cntr_v1;
wl_periodic_compact_cntrs_v2_t compact_cntr_v2;
wl_periodic_compact_cntrs_v3_t compact_cntr_v3;
wl_periodic_compact_cntrs_v4_t compact_cntr_v4;
};
evt_hist_compact_toss_stats_v1_t hist_tx_toss_stat;
evt_hist_compact_toss_stats_v1_t hist_rx_toss_stat;
@ -230,7 +227,7 @@ static EWPF_tbl_t EWPF_periodic[] =
{
WL_STATE_COMPACT_COUNTERS,
evt_xtlv_copy_cb,
SLICE_INFO(compact_cntr_v3),
SLICE_INFO(compact_cntr_v4),
NULL
},
{
@ -835,7 +832,7 @@ static int
evt_get_last_toss_hist(uint8 *ptr, const uint8 *data, uint16 len)
{
bcm_xtlv_t *bcm_xtlv_desc = (bcm_xtlv_t *)data;
wl_hist_compact_toss_stats_v2_t *ewp_stats;
wl_hist_compact_toss_stats_v3_t *ewp_stats;
evt_hist_compact_toss_stats_v1_t bidata_stats;
int16 max_rcidx = EWPF_INVALID, secnd_rcidx = EWPF_INVALID;
uint16 cur_rnidx = 0, prev_rnidx = 0;
@ -846,21 +843,21 @@ evt_get_last_toss_hist(uint8 *ptr, const uint8 *data, uint16 len)
return BCME_ERROR;
}
if (bcm_xtlv_desc->len != sizeof(wl_hist_compact_toss_stats_v2_t)) {
if (bcm_xtlv_desc->len != sizeof(wl_hist_compact_toss_stats_v3_t)) {
DHD_FILTER_ERR(("%s : size is not matched %d\n", __FUNCTION__,
bcm_xtlv_desc->len));
return BCME_ERROR;
}
ewp_stats = (wl_hist_compact_toss_stats_v2_t *)(&bcm_xtlv_desc->data[0]);
ewp_stats = (wl_hist_compact_toss_stats_v3_t *)(&bcm_xtlv_desc->data[0]);
if (ewp_stats->htr_type == WL_STATE_HIST_TX_TOSS_REASONS) {
if (ewp_stats->version != WL_HIST_COMPACT_TOSS_STATS_TX_VER_2) {
if (ewp_stats->version != WL_HIST_COMPACT_TOSS_STATS_TX_VER_3) {
DHD_FILTER_ERR(("%s : unsupported version %d (type: %d)\n",
__FUNCTION__, ewp_stats->version, ewp_stats->htr_type));
return BCME_ERROR;
}
} else if (ewp_stats->htr_type == WL_STATE_HIST_RX_TOSS_REASONS) {
if (ewp_stats->version != WL_HIST_COMPACT_TOSS_STATS_RX_VER_2) {
if (ewp_stats->version != WL_HIST_COMPACT_TOSS_STATS_RX_VER_3) {
DHD_FILTER_ERR(("%s : unsupported version %d (type: %d)\n",
__FUNCTION__, ewp_stats->version, ewp_stats->htr_type));
return BCME_ERROR;
@ -888,10 +885,9 @@ evt_get_last_toss_hist(uint8 *ptr, const uint8 *data, uint16 len)
* Need to get largest count of toss reasons
*/
for (idx = 0; idx < WLC_HIST_TOSS_LEN; idx ++) {
cur_rccnt = (uint16)((ewp_stats->htr_rc[idx] &
HIST_TOSS_RC_COUNT_MASK)>>HIST_TOSS_RC_COUNT_POS);
cur_rccnt = (uint16)(ewp_stats->htr_rc[idx].toss_cnt);
DHD_FILTER_TRACE(("%s: idx %d htr_rc %04x cur_rccnt %d\n",
__FUNCTION__, idx, ewp_stats->htr_rc[idx], cur_rccnt));
__FUNCTION__, idx, ewp_stats->htr_rc[idx].toss_reason, cur_rccnt));
if (ewp_stats->htr_rc_ts[idx] && max_rccnt < cur_rccnt) {
max_rccnt = cur_rccnt;
secnd_rcidx = max_rcidx;
@ -906,16 +902,16 @@ evt_get_last_toss_hist(uint8 *ptr, const uint8 *data, uint16 len)
bidata_stats.version = ewp_stats->version;
bidata_stats.htr_type = ewp_stats->htr_type;
bidata_stats.htr_num = ewp_stats->htr_num;
bidata_stats.htr_rn_last = ewp_stats->htr_running[cur_rnidx];
bidata_stats.htr_rn_last = *(uint32*)(&ewp_stats->htr_running[cur_rnidx]);
bidata_stats.htr_rn_ts_last = ewp_stats->htr_rn_ts[cur_rnidx];
bidata_stats.htr_rn_prev = ewp_stats->htr_running[prev_rnidx];
bidata_stats.htr_rn_prev = *(uint32*)(&ewp_stats->htr_running[prev_rnidx]);
bidata_stats.htr_rn_ts_prev = ewp_stats->htr_rn_ts[prev_rnidx];
if (max_rcidx != EWPF_INVALID) {
bidata_stats.htr_rc_max = ewp_stats->htr_rc[max_rcidx];
bidata_stats.htr_rc_max = *(uint32*)(&ewp_stats->htr_rc[max_rcidx]);
bidata_stats.htr_rc_ts_max = ewp_stats->htr_rc_ts[max_rcidx];
}
if (secnd_rcidx != EWPF_INVALID) {
bidata_stats.htr_rc_secnd = ewp_stats->htr_rc[secnd_rcidx];
bidata_stats.htr_rc_secnd = *(uint32*)(&ewp_stats->htr_rc[secnd_rcidx]);
bidata_stats.htr_rc_ts_secnd = ewp_stats->htr_rc_ts[secnd_rcidx];
}
DHD_FILTER_TRACE(("%s: ver %d type %d num %d "
@ -1279,7 +1275,7 @@ dhd_event_log_filter_event_handler(dhd_pub_t *dhdp, prcd_event_log_hdr_t *plog_h
#define EWP_REPORT_NAME_MAX 64
#ifdef DHD_EWPR_VER2
#define EWP_REPORT_VERSION 0x20190514
#define EWP_REPORT_VERSION 0x20200722
#define EWP_REPORT_SET_DEFAULT 0x01
#define EWPR_CSDCLIENT_DIFF 10
#define EWPR_INTERVAL 3
@ -1349,7 +1345,7 @@ typedef struct {
uint32 *delta_list; /* IN delta values to find */
} ewpr_lock_param_t;
#define MAX_MULTI_VER 3
#define MAX_MULTI_VER 4
typedef struct {
uint32 version; /* VERSION for multiple version struct */
uint32 offset; /* offset of the member at the version */
@ -1386,7 +1382,7 @@ typedef struct {
/* offset defines */
#define EWPR_CNT_VERSION_OFFSET \
OFFSETOF(EWPF_slc_elem_t, compact_cntr_v3)
OFFSETOF(EWPF_slc_elem_t, compact_cntr_v4)
#define EWPR_CNT_V1_OFFSET(a) \
WL_PERIODIC_COMPACT_CNTRS_VER_1, \
@ -1397,6 +1393,9 @@ typedef struct {
#define EWPR_CNT_V3_OFFSET(a) \
WL_PERIODIC_COMPACT_CNTRS_VER_3, \
(OFFSETOF(EWPF_slc_elem_t, compact_cntr_v3) + OFFSETOF(wl_periodic_compact_cntrs_v3_t, a))
#define EWPR_CNT_V4_OFFSET(a) \
WL_PERIODIC_COMPACT_CNTRS_VER_4, \
(OFFSETOF(EWPF_slc_elem_t, compact_cntr_v4) + OFFSETOF(wl_periodic_compact_cntrs_v4_t, a))
#define EWPR_STAT_OFFSET(a) \
(OFFSETOF(EWPF_ifc_elem_t, if_stat) + OFFSETOF(wl_if_stats_t, a))
#define EWPR_INFRA_OFFSET(a) \
@ -1434,14 +1433,16 @@ typedef struct {
.v_info = { EWPR_CNT_VERSION_OFFSET, \
{{EWPR_CNT_V1_OFFSET(a)}, \
{EWPR_CNT_V2_OFFSET(a)}, \
{EWPR_CNT_V3_OFFSET(a)}}}, \
{EWPR_CNT_V3_OFFSET(a)}, \
{EWPR_CNT_V4_OFFSET(a)}}}, \
EWP_UINT32, EWP_HEX, EWP_UINT32}
#define EWPR_SERIAL_CNT_16(a) {\
#a, EWPF_IDX_TYPE_SLICE, TRUE, \
.v_info = { EWPR_CNT_VERSION_OFFSET, \
{{EWPR_CNT_V1_OFFSET(a)}, \
{EWPR_CNT_V2_OFFSET(a)}, \
{EWPR_CNT_V3_OFFSET(a)}}}, \
{EWPR_CNT_V3_OFFSET(a)}, \
{EWPR_CNT_V4_OFFSET(a)}}}, \
EWP_UINT32, EWP_HEX, EWP_UINT16}
#define EWPR_SERIAL_STAT(a) {\
#a, EWPF_IDX_TYPE_IFACE, FALSE, .offset = EWPR_STAT_OFFSET(a), \
@ -1528,10 +1529,10 @@ typedef struct {
#define EWPR_SINGLE_USEC_TO_SEC EWPR_DISPLAY_METHOD_SINGLE, EWPF_USEC_TO_SEC
/* serail info type define */
#define EWPR_SERIAL_CNT_V3_BIT(a, b, c, d) {\
#define EWPR_SERIAL_CNT_V4_BIT(a, b, c, d) {\
#a, EWPF_IDX_TYPE_SLICE, TRUE, \
.v_info = { EWPR_CNT_VERSION_OFFSET, \
{{EWPR_CNT_V3_OFFSET(a)}}}, \
{{EWPR_CNT_V4_OFFSET(a)}}}, \
EWP_UINT32, EWP_BIN, EWP_BIT, EWPF_INFO_ECNT, b, c, d}
#define EWPR_SERIAL_STAT_BIT(a, b, c, d) {\
#a, EWPF_IDX_TYPE_IFACE, FALSE, .offset = EWPR_STAT_OFFSET(a), \
@ -1717,21 +1718,28 @@ ewpr_serial_bit_unwanted_network_default_tbl[] = {
EWPR_SERIAL_MGMT_BIT(rxdeauth, 4, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_MGMT_BIT(txaction, 7, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_MGMT_BIT(rxaction, 7, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(txallfrm, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxrsptmout, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxbadplcp, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxcrsglitch, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxbadfcs, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxbeaconmbss, 5, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxbeaconobss, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(lqcm_report, 19, 6, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(tx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxretry, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxdup, 15, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(chswitch_cnt, 8, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(pm_dur, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxholes, 15, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(txallfrm, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxrsptmout, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxbadplcp, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxcrsglitch, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxbadfcs, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxbeaconmbss, 5, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxbeaconobss, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(lqcm_report, 19, 6, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(tx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxretry, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxdup, 15, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(chswitch_cnt, 8, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(pm_dur, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxholes, 15, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxundec, 16, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxundec_mcst, 16, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(replay, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(replay_mcst, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(pktfilter_discard, 16, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(pktfilter_forward, 16, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(mac_rxfilter, 16, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_BTC_STAT_16_BIT(bt_dcsn_map, 16, 3, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_BTC_STAT_16_BIT(bt_dcsn_cnt, 12, 3, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_BTC_STAT_16_BIT(bt_a2dp_hiwat_cnt, 12, 3, EWPR_SINGLE_DEFAULT),
@ -1783,7 +1791,7 @@ ewpr_serial_bit_unwanted_network_default_tbl[] = {
EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_max, 32, 1, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_ts_secnd, 32, 1, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_secnd, 32, 1, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_CPLOG_BIT(packtlog, 22, 70),
EWPR_SERIAL_CPLOG_BIT(packtlog, 22, 50),
EWPR_SERIAL_NONE
};
@ -1817,21 +1825,28 @@ ewpr_serial_bit_assoc_fail_default_tbl[] = {
EWPR_SERIAL_MGMT_BIT(rxdeauth, 4, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_MGMT_BIT(txaction, 7, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_MGMT_BIT(rxaction, 7, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(txallfrm, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxrsptmout, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxbadplcp, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxcrsglitch, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxbadfcs, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxbeaconmbss, 5, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxbeaconobss, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(lqcm_report, 19, 6, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(tx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxretry, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxdup, 15, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(chswitch_cnt, 8, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(pm_dur, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxholes, 15, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(txallfrm, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxrsptmout, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxbadplcp, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxcrsglitch, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxbadfcs, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxbeaconmbss, 5, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxbeaconobss, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(lqcm_report, 19, 6, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(tx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxretry, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxdup, 15, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(chswitch_cnt, 8, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(pm_dur, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxholes, 15, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxundec, 16, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxundec_mcst, 16, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(replay, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(replay_mcst, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(pktfilter_discard, 16, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(pktfilter_forward, 16, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(mac_rxfilter, 16, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_BTC_STAT_16_BIT(bt_dcsn_map, 16, 3, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_BTC_STAT_16_BIT(bt_dcsn_cnt, 12, 3, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_BTC_STAT_16_BIT(bt_a2dp_hiwat_cnt, 12, 3, EWPR_SINGLE_DEFAULT),
@ -1869,7 +1884,7 @@ ewpr_serial_bit_assoc_fail_default_tbl[] = {
EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_max, 32, 1, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_ts_secnd, 32, 1, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_secnd, 32, 1, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_CPLOG_BIT(packtlog, 22, 70),
EWPR_SERIAL_CPLOG_BIT(packtlog, 22, 50),
EWPR_SERIAL_NONE
};
@ -1903,21 +1918,28 @@ ewpr_serial_bit_abnormal_disconnect_default_tbl[] = {
EWPR_SERIAL_MGMT_BIT(rxdeauth, 4, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_MGMT_BIT(txaction, 7, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_MGMT_BIT(rxaction, 7, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(txallfrm, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxrsptmout, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxbadplcp, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxcrsglitch, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxbadfcs, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxbeaconmbss, 5, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxbeaconobss, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(lqcm_report, 19, 6, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(tx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxretry, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxdup, 15, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(chswitch_cnt, 8, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(pm_dur, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V3_BIT(rxholes, 15, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(txallfrm, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxrsptmout, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxbadplcp, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxcrsglitch, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxbadfcs, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxbeaconmbss, 5, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxbeaconobss, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(lqcm_report, 19, 6, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(tx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rx_toss_cnt, 18, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxretry, 17, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxdup, 15, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(chswitch_cnt, 8, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(pm_dur, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxholes, 15, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxundec, 16, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(rxundec_mcst, 16, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(replay, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(replay_mcst, 12, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(pktfilter_discard, 16, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(pktfilter_forward, 16, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_CNT_V4_BIT(mac_rxfilter, 16, 6, EWPR_DIFF_DEFAULT),
EWPR_SERIAL_BTC_STAT_16_BIT(bt_dcsn_map, 16, 3, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_BTC_STAT_16_BIT(bt_dcsn_cnt, 12, 3, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_BTC_STAT_16_BIT(bt_a2dp_hiwat_cnt, 12, 3, EWPR_SINGLE_DEFAULT),
@ -1969,7 +1991,7 @@ ewpr_serial_bit_abnormal_disconnect_default_tbl[] = {
EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_max, 32, 1, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_ts_secnd, 32, 1, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_RX_TOSS_HIST_BIT(htr_rc_secnd, 32, 1, EWPR_SINGLE_DEFAULT),
EWPR_SERIAL_CPLOG_BIT(packtlog, 22, 70),
EWPR_SERIAL_CPLOG_BIT(packtlog, 22, 50),
EWPR_SERIAL_NONE
};

View File

@ -1,7 +1,7 @@
/*
* Wifi dongle status Filter and Report
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you

View File

@ -4,7 +4,7 @@
* Flow rings are transmit traffic (=propagating towards antenna) related entities
*
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -64,12 +64,6 @@ int dhd_flow_queue_overflow(flow_queue_t *queue, void *pkt);
#define FLOW_QUEUE_PKT_NEXT(p) PKTLINK(p)
#define FLOW_QUEUE_PKT_SETNEXT(p, x) PKTSETLINK((p), (x))
#ifdef DHD_REPLACE_LOG_INFO_TO_TRACE
#define DHD_FLOWRING_INFO DHD_TRACE
#else
#define DHD_FLOWRING_INFO DHD_INFO
#endif /* DHD_REPLACE_LOG_INFO_TO_TRACE */
const uint8 prio2ac[8] = { 0, 1, 1, 0, 2, 2, 3, 3 };
const uint8 prio2tid[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
@ -254,7 +248,6 @@ BCMFASTPATH(dhd_flow_queue_dequeue)(dhd_pub_t *dhdp, flow_queue_t *queue)
pkt = queue->head; /* from head */
if (pkt == NULL) {
ASSERT((queue->len == 0) && (queue->tail == NULL));
goto done;
}
@ -361,11 +354,11 @@ dhd_get_max_multi_client_flow_rings(dhd_pub_t *dhdp)
int
dhd_flowid_map_init(dhd_pub_t *dhdp, uint16 max_tx_flow_rings)
{
#if defined(DHD_HTPUT_TUNABLES)
uint16 max_normal_tx_flow_rings = max_tx_flow_rings - HTPUT_TOTAL_FLOW_RINGS;
#else
uint16 max_normal_tx_flow_rings = max_tx_flow_rings;
#endif /* DHD_HTPUT_TUNABLES */
if (dhdp->htput_support) {
max_normal_tx_flow_rings = max_tx_flow_rings - HTPUT_TOTAL_FLOW_RINGS;
}
/* Construct a normal flowid allocator from FLOWID_RESERVED to
* (max_normal_tx_flow_rings - 1)
@ -377,21 +370,24 @@ dhd_flowid_map_init(dhd_pub_t *dhdp, uint16 max_tx_flow_rings)
return BCME_NOMEM;
}
#if defined(DHD_HTPUT_TUNABLES)
if (HTPUT_TOTAL_FLOW_RINGS > 0) {
dhdp->htput_flow_ring_start = max_normal_tx_flow_rings + FLOWID_RESERVED;
/* Construct a htput flowid allocator from htput_flow_ring_start to
* (htput_flow_ring_start + HTPUT_TOTAL_FLOW_RINGS - 1)
*/
dhdp->htput_flowid_allocator = id16_map_init(dhdp->osh, HTPUT_TOTAL_FLOW_RINGS,
dhdp->htput_flow_ring_start);
if (dhdp->htput_flowid_allocator == NULL) {
DHD_ERROR(("%s: htput flowid allocator init failure\n", __FUNCTION__));
return BCME_NOMEM;
dhdp->htput_flowid_allocator = NULL;
if (dhdp->htput_support) {
if (HTPUT_TOTAL_FLOW_RINGS > 0) {
dhdp->htput_flow_ring_start = max_normal_tx_flow_rings + FLOWID_RESERVED;
/* Construct a htput flowid allocator from htput_flow_ring_start to
* (htput_flow_ring_start + HTPUT_TOTAL_FLOW_RINGS - 1)
*/
dhdp->htput_flowid_allocator = id16_map_init(dhdp->osh,
HTPUT_TOTAL_FLOW_RINGS, dhdp->htput_flow_ring_start);
if (dhdp->htput_flowid_allocator == NULL) {
DHD_ERROR(("%s: htput flowid allocator init failure\n",
__FUNCTION__));
return BCME_NOMEM;
}
dhdp->htput_client_flow_rings = 0u;
}
dhdp->htput_client_flow_rings = 0u;
}
#endif /* !DHD_HTPUT_TUNABLES */
return BCME_OK;
}
@ -404,14 +400,13 @@ dhd_flowid_map_deinit(dhd_pub_t *dhdp)
}
ASSERT(dhdp->flowid_allocator == NULL);
#if defined(DHD_HTPUT_TUNABLES)
if (dhdp->htput_flowid_allocator) {
dhdp->htput_flowid_allocator = id16_map_fini(dhdp->osh,
dhdp->htput_flowid_allocator);
ASSERT(dhdp->htput_flowid_allocator == NULL);
}
dhdp->htput_client_flow_rings = 0u;
#endif /* !DHD_HTPUT_TUNABLES */
return;
}
@ -508,7 +503,8 @@ dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_h2d_rings)
bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO);
dhdp->max_multi_client_flow_rings = dhd_get_max_multi_client_flow_rings(dhdp);
dhdp->multi_client_flow_rings = 0U;
OSL_ATOMIC_INIT(dhdp->osh, &dhdp->multi_client_flow_rings);
#ifdef DHD_LOSSLESS_ROAMING
dhdp->dequeue_prec_map = ALLPRIO;
@ -608,7 +604,8 @@ void dhd_flow_rings_deinit(dhd_pub_t *dhdp)
bzero(dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO);
dhdp->max_multi_client_flow_rings = 0U;
dhdp->multi_client_flow_rings = 0U;
OSL_ATOMIC_INIT(dhdp->osh, &dhdp->multi_client_flow_rings);
lock = dhdp->flowid_lock;
dhdp->flowid_lock = NULL;
@ -702,7 +699,8 @@ dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da)
}
} else {
if (ETHER_ISMULTI(da)) {
if (ETHER_ISMULTI(da) &&
TRUE) {
ismcast = TRUE;
hash = 0;
} else {
@ -723,11 +721,7 @@ dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da)
}
DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
#ifdef DHD_EFI
DHD_TRACE(("%s: cannot find flowid\n", __FUNCTION__));
#else
DHD_FLOWRING_INFO(("%s: cannot find flowid\n", __FUNCTION__));
#endif
DHD_INFO(("%s: cannot find flowid\n", __FUNCTION__));
return FLOWID_INVALID;
} /* dhd_flowid_find */
@ -737,7 +731,13 @@ dhd_flowid_map_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *da)
uint16 flowid = FLOWID_INVALID;
ASSERT(dhdp->flowid_allocator != NULL);
#if defined(DHD_HTPUT_TUNABLES)
/* P2P Connections are always 80Mhz */
if (DHD_IF_ROLE_P2PGC(dhdp, ifindex) ||
DHD_IF_ROLE_P2PGO(dhdp, ifindex)) {
flowid = id16_map_alloc(dhdp->flowid_allocator);
return flowid;
}
if (dhdp->htput_flowid_allocator) {
if (prio == HTPUT_FLOW_RING_PRIO) {
if (DHD_IF_ROLE_GENERIC_STA(dhdp, ifindex)) {
@ -748,7 +748,8 @@ dhd_flowid_map_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *da)
* will take care assigning same for those HTPUT_PRIO packets.
*/
flowid = id16_map_alloc(dhdp->htput_flowid_allocator);
} else if (DHD_IF_ROLE_MULTI_CLIENT(dhdp, ifindex) && !ETHER_ISMULTI(da)) {
} else if (DHD_IF_ROLE_MULTI_CLIENT(dhdp, ifindex) && !ETHER_ISMULTI(da) &&
dhd_is_sta_htput(dhdp, ifindex, (uint8 *)da)) {
/* Use HTPUT flowrings for only HTPUT_NUM_CLIENT_FLOW_RINGS */
if (dhdp->htput_client_flow_rings < HTPUT_NUM_CLIENT_FLOW_RINGS) {
flowid = id16_map_alloc(dhdp->htput_flowid_allocator);
@ -760,7 +761,6 @@ dhd_flowid_map_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *da)
}
}
}
#endif /* !DHD_HTPUT_TUNABLES */
BCM_REFERENCE(flowid);
@ -830,7 +830,9 @@ dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da)
} else {
/* For bcast/mcast assign first slot in in interface */
hash = ETHER_ISMULTI(da) ? 0 : DHD_FLOWRING_HASHINDEX(da, prio);
hash = (ETHER_ISMULTI(da) &&
TRUE) ? 0 : DHD_FLOWRING_HASHINDEX(da, prio);
cur = if_flow_lkup[ifindex].fl_hash[hash];
if (cur) {
while (cur->next) {
@ -842,7 +844,7 @@ dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da)
}
DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
DHD_FLOWRING_INFO(("%s: allocated flowid %d\n", __FUNCTION__, fl_hash_node->flowid));
DHD_INFO(("%s: allocated flowid %d\n", __FUNCTION__, fl_hash_node->flowid));
if (fl_hash_node->flowid > dhdp->max_tx_flowid) {
DHD_ERROR(("%s: flowid=%d max_tx_flowid=%d ifindex=%d prio=%d role=%d\n",
@ -881,7 +883,7 @@ dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex,
id = dhd_flowid_find(dhdp, ifindex, prio, sa, da);
if (id == FLOWID_INVALID) {
if (id == FLOWID_INVALID || (id > dhdp->max_tx_flowid)) {
bool if_role_multi_client;
if_flow_lkup_t *if_flow_lkup;
if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
@ -895,9 +897,11 @@ dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex,
/* Abort Flowring creation if multi client flowrings crossed the threshold */
#ifdef DHD_LIMIT_MULTI_CLIENT_FLOWRINGS
if (if_role_multi_client &&
(dhdp->multi_client_flow_rings >= dhdp->max_multi_client_flow_rings)) {
(OSL_ATOMIC_READ(dhdp->osh, &dhdp->multi_client_flow_rings) >=
dhdp->max_multi_client_flow_rings)) {
DHD_ERROR_RLMT(("%s: Max multi client flow rings reached: %d:%d\n",
__FUNCTION__, dhdp->multi_client_flow_rings,
__FUNCTION__,
OSL_ATOMIC_READ(dhdp->osh, &dhdp->multi_client_flow_rings),
dhdp->max_multi_client_flow_rings));
return BCME_ERROR;
}
@ -923,7 +927,7 @@ dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex,
/* Only after flowid alloc, increment multi_client_flow_rings */
if (if_role_multi_client) {
dhdp->multi_client_flow_rings++;
OSL_ATOMIC_INC(dhdp->osh, &dhdp->multi_client_flow_rings);
}
/* register this flowid in dhd_pub */
@ -1095,7 +1099,7 @@ BCMFASTPATH(dhd_flowid_update)(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, void
return BCME_ERROR;
}
DHD_FLOWRING_INFO(("%s: prio %d flowid %d\n", __FUNCTION__, prio, flowid));
DHD_INFO(("%s: prio %d flowid %d\n", __FUNCTION__, prio, flowid));
/* Tag the packet with flowid */
DHD_PKT_SET_FLOWID(pktbuf, flowid);
@ -1105,7 +1109,6 @@ BCMFASTPATH(dhd_flowid_update)(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, void
static void
dhd_flowid_map_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid)
{
#if defined(DHD_HTPUT_TUNABLES)
if (dhdp->htput_flowid_allocator) {
if (DHD_IS_FLOWID_HTPUT(dhdp, flowid)) {
id16_map_free(dhdp->htput_flowid_allocator, flowid);
@ -1116,7 +1119,6 @@ dhd_flowid_map_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid)
return;
}
}
#endif /* !DHD_HTPUT_TUNABLES */
id16_map_free(dhdp->flowid_allocator, flowid);
@ -1169,15 +1171,19 @@ dhd_flowid_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid)
/* Decrement multi_client_flow_rings */
if (if_role_multi_client) {
dhdp->multi_client_flow_rings--;
if (OSL_ATOMIC_READ(dhdp->osh,
&dhdp->multi_client_flow_rings)) {
OSL_ATOMIC_DEC(dhdp->osh,
&dhdp->multi_client_flow_rings);
}
}
/* deregister flowid from dhd_pub. */
dhd_del_flowid(dhdp, ifindex, flowid);
dhd_flowid_map_free(dhdp, ifindex, flowid);
DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
MFREE(dhdp->osh, cur, sizeof(flow_hash_info_t));
DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags);
return;
}
@ -1219,6 +1225,50 @@ dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex)
}
}
void
dhd_update_multicilent_flow_rings(dhd_pub_t *dhdp, uint8 ifindex, bool increment)
{
uint32 id;
flow_ring_table_t *flow_ring_table;
DHD_ERROR(("%s: ifindex %u\n", __FUNCTION__, ifindex));
ASSERT(ifindex < DHD_MAX_IFS);
if (ifindex >= DHD_MAX_IFS)
return;
if (!dhdp->flow_ring_table)
return;
flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table;
for (id = 0; id < dhdp->num_h2d_rings; id++) {
if (flow_ring_table[id].active &&
(flow_ring_table[id].flow_info.ifindex == ifindex) &&
(flow_ring_table[id].status == FLOW_RING_STATUS_OPEN)) {
if (increment) {
if (OSL_ATOMIC_READ(dhdp->osh, &dhdp->multi_client_flow_rings) <
dhdp->max_multi_client_flow_rings) {
OSL_ATOMIC_INC(dhdp->osh, &dhdp->multi_client_flow_rings);
} else {
DHD_ERROR(("%s: multi_client_flow_rings:%u"
" reached max:%d\n", __FUNCTION__,
OSL_ATOMIC_READ(dhdp->osh,
&dhdp->multi_client_flow_rings),
dhdp->max_multi_client_flow_rings));
}
} else {
if (OSL_ATOMIC_READ(dhdp->osh, &dhdp->multi_client_flow_rings)) {
OSL_ATOMIC_DEC(dhdp->osh, &dhdp->multi_client_flow_rings);
} else {
DHD_ERROR(("%s: multi_client_flow_rings:%u"
" reached ZERO\n", __FUNCTION__,
OSL_ATOMIC_READ(dhdp->osh,
&dhdp->multi_client_flow_rings)));
}
}
}
}
}
void
dhd_flow_rings_flush(dhd_pub_t *dhdp, uint8 ifindex)
{
@ -1252,7 +1302,7 @@ dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex, char *addr)
uint32 id;
flow_ring_table_t *flow_ring_table;
DHD_ERROR(("%s: ifindex %u\n", __FUNCTION__, ifindex));
DHD_INFO(("%s: ifindex %u\n", __FUNCTION__, ifindex));
ASSERT(ifindex < DHD_MAX_IFS);
if (ifindex >= DHD_MAX_IFS)
@ -1277,7 +1327,7 @@ dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex, char *addr)
(!memcmp(flow_ring_table[id].flow_info.da, addr, ETHER_ADDR_LEN)) &&
((flow_ring_table[id].status == FLOW_RING_STATUS_OPEN) ||
(flow_ring_table[id].status == FLOW_RING_STATUS_CREATE_PENDING))) {
DHD_ERROR(("%s: deleting flowid %d\n",
DHD_INFO(("%s: deleting flowid %d\n",
__FUNCTION__, flow_ring_table[id].flowid));
dhd_bus_flow_ring_delete_request(dhdp->bus,
(void *) &flow_ring_table[id]);
@ -1308,8 +1358,15 @@ dhd_update_interface_flow_info(dhd_pub_t *dhdp, uint8 ifindex,
if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
if (op == WLC_E_IF_ADD || op == WLC_E_IF_CHANGE) {
DHD_ERROR(("%s: ifindex:%d previous role:%d new role:%d\n",
__FUNCTION__, ifindex, if_flow_lkup[ifindex].role, role));
if_flow_lkup[ifindex].role = role;
#ifdef PCIE_FULL_DONGLE
if (op == WLC_E_IF_CHANGE) {
bool increment = DHD_IF_ROLE_MULTI_CLIENT(dhdp, ifindex);
dhd_update_multicilent_flow_rings(dhdp, ifindex, increment);
}
#endif /* PCIE_FULL_DONGLE */
if (role == WLC_E_IF_ROLE_WDS) {
/**
@ -1452,48 +1509,3 @@ dhd_active_tx_flowring_bkpq_len(dhd_pub_t *dhd)
DHD_FLOWRING_LIST_UNLOCK(bus->dhd->flowring_list_lock, list_lock_flags);
return active_tx_flowring_qlen;
}
#ifdef DHD_AWDL
/**
* Handle/Intercept awdl peer op IOVAR fired by user
* buf = NULL means delete all peers in awdl interface
*/
void
dhd_awdl_peer_op(dhd_pub_t *dhdp, uint8 ifindex, void *buf, uint32 buflen)
{
awdl_peer_op_t *peer = (awdl_peer_op_t *)buf;
DHD_TRACE(("%s\n", __FUNCTION__));
ASSERT(ifindex < DHD_MAX_IFS);
if (ifindex >= DHD_MAX_IFS)
return;
if (!buf) {
/* Delete all peers in awdl interface */
if_flow_lkup_t *if_flow_lkup;
if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup;
if (if_flow_lkup[ifindex].role != WLC_E_IF_ROLE_AWDL) {
DHD_ERROR(("%s: Iinterface %d is not a awdl peer \n",
__FUNCTION__, ifindex));
return;
}
dhd_flow_rings_delete(dhdp, ifindex);
return;
}
/* Parse awdl_peer_op info now */
if (buflen < sizeof(awdl_peer_op_t)) {
DHD_ERROR(("%s: cannot handle awdl_peer_op add/del\n", __FUNCTION__));
return;
}
/**
* Only flowring deletion is handled here
* Flowring addition is taken care in dhd_flowid_lookup
*/
if (peer->opcode == AWDL_PEER_OP_DEL) {
dhd_del_sta(dhdp, ifindex, &peer->addr.octet[0]);
dhd_flow_rings_delete_for_peer(dhdp, ifindex, (char *)&peer->addr.octet[0]);
} else if (peer->opcode == AWDL_PEER_OP_ADD) {
dhd_findadd_sta(dhdp, ifindex, &peer->addr.octet[0]);
}
return;
}
#endif /* DHD_AWDL */

View File

@ -6,7 +6,7 @@
* Provides type definitions and function prototypes used to create, delete and manage flow rings at
* high level.
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -58,47 +58,19 @@
#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 */
((pub)->htput_support && (flowid >= (pub)->htput_flow_ring_start) && \
((uint16)flowid < ((pub)->htput_flow_ring_start + HTPUT_TOTAL_FLOW_RINGS)))
#if defined(FLOW_RING_PREALLOC)
#define MAX_FLOW_RINGS 64
#endif /* FLOW_RING_PREALLOC */
#ifdef DHD_EFI
/*
* 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 /* DHD_EFI */
#define DHD_FLOWRING_RX_BUFPOST_PKTSZ_MAX 4096
@ -127,16 +99,9 @@
#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])
@ -272,9 +237,6 @@ 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;
@ -327,6 +289,8 @@ 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);
extern void dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex);
extern void dhd_update_multicilent_flow_rings(dhd_pub_t *dhdp, uint8 ifindex,
bool increment);
extern void dhd_flow_rings_flush(dhd_pub_t *dhdp, uint8 ifindex);
extern void dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex,
@ -342,10 +306,5 @@ extern int dhd_update_interface_link_status(dhd_pub_t *dhdp, uint8 ifindex,
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

@ -1,563 +0,0 @@
/*
* 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

@ -1,55 +0,0 @@
/*
* 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

@ -1,24 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <osl.h>
#include <dhd_linux.h>
#include <linux/gpio.h>
#ifdef BCMDHD_DTS
#include <linux/of_gpio.h>
#endif
#ifdef BCMDHD_PLATDEV
#include <linux/platform_device.h>
#endif
#ifdef CUSTOMER_HW_ROCKCHIP
#include <linux/rfkill-wlan.h>
#endif
#if defined(BUS_POWER_RESTORE) && defined(BCMSDIO)
#include <linux/mmc/core.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
#endif /* defined(BUS_POWER_RESTORE) && defined(BCMSDIO) */
#ifdef CONFIG_DHD_USE_STATIC_BUF
#ifdef DHD_STATIC_IN_DRIVER
extern int dhd_static_buf_init(void);
extern void dhd_static_buf_exit(void);
#endif /* DHD_STATIC_IN_DRIVER */
#ifdef BCMDHD_MDRIVER
#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER)
extern void *dhd_wlan_mem_prealloc(uint bus_type, int index,
int section, unsigned long size);
#else
@ -33,7 +28,7 @@ extern void *dhd_wlan_mem_prealloc(int section, unsigned long size);
#ifdef BCMDHD_DTS
/* This is sample code in dts file.
bcmdhd {
bcmdhd_wlan {
compatible = "android,bcmdhd_wlan";
gpio_wl_reg_on = <&gpio GPIOH_4 GPIO_ACTIVE_HIGH>;
gpio_wl_host_wake = <&gpio GPIOZ_15 GPIO_ACTIVE_HIGH>;
@ -62,19 +57,11 @@ dhd_wlan_set_power(int on, wifi_adapter_info_t *adapter)
#ifdef CUSTOMER_HW_ROCKCHIP
rockchip_wifi_power(1);
#ifdef BCMPCIE
//rk_pcie_power_on_atu_fixup();
// rk_pcie_power_on_atu_fixup();
#endif
#endif
#ifdef BUS_POWER_RESTORE
#ifdef BCMSDIO
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
if (adapter->sdio_func && adapter->sdio_func->card && adapter->sdio_func->card->host) {
mdelay(100);
printf("======== mmc_power_restore_host! ========\n");
mmc_power_restore_host(adapter->sdio_func->card->host);
}
#endif
#elif defined(BCMPCIE)
#ifdef BCMPCIE
if (adapter->pci_dev) {
mdelay(100);
printf("======== pci_set_power_state PCI_D0! ========\n");
@ -90,17 +77,9 @@ dhd_wlan_set_power(int on, wifi_adapter_info_t *adapter)
#endif /* BCMPCIE */
#endif /* BUS_POWER_RESTORE */
/* Lets customer power to get stable */
mdelay(100);
} else {
#ifdef BUS_POWER_RESTORE
#ifdef BCMSDIO
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
if (adapter->sdio_func && adapter->sdio_func->card && adapter->sdio_func->card->host) {
printf("======== mmc_power_save_host! ========\n");
mmc_power_save_host(adapter->sdio_func->card->host);
}
#endif
#elif defined(BCMPCIE)
#ifdef BCMPCIE
if (adapter->pci_dev) {
printf("======== pci_set_power_state PCI_D3hot! ========\n");
pci_save_state(adapter->pci_dev);
@ -127,16 +106,17 @@ dhd_wlan_set_power(int on, wifi_adapter_info_t *adapter)
return err;
}
static int dhd_wlan_set_reset(int onoff)
static int
dhd_wlan_set_reset(int onoff)
{
return 0;
}
static int dhd_wlan_set_carddetect(int present)
static int
dhd_wlan_set_carddetect(int present)
{
int err = 0;
#if !defined(BUS_POWER_RESTORE)
if (present) {
#if defined(BCMSDIO)
printf("======== Card detection to detect SDIO card! ========\n");
@ -156,20 +136,20 @@ static int dhd_wlan_set_carddetect(int present)
err = sdhci_force_presence_change(&sdmmc_channel, 0);
#endif /* CUSTOMER_HW_PLATFORM */
#ifdef CUSTOMER_HW_ROCKCHIP
rockchip_wifi_set_carddetect(0);
rockchip_wifi_set_carddetect(0);
#endif
#elif defined(BCMPCIE)
printf("======== Card detection to remove PCIE card! ========\n");
#endif
}
#endif /* BUS_POWER_RESTORE */
return err;
}
static int dhd_wlan_get_mac_addr(unsigned char *buf, int ifidx)
static int
dhd_wlan_get_mac_addr(unsigned char *buf, int ifidx)
{
int err = 0;
int err = -1;
if (ifidx == 1) {
#ifdef EXAMPLE_GET_MAC
@ -265,16 +245,17 @@ struct wifi_platform_data dhd_wlan_control = {
.get_country_code = dhd_wlan_get_country_code,
};
int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter)
static int
dhd_wlan_init_gpio(wifi_adapter_info_t *adapter)
{
#ifdef BCMDHD_DTS
char wlan_node[32];
struct device_node *root_node = NULL;
#endif
int err = 0;
int gpio_wl_reg_on;
int gpio_wl_reg_on = -1;
#ifdef CUSTOMER_OOB
int gpio_wl_host_wake;
int gpio_wl_host_wake = -1;
int host_oob_irq = -1;
uint host_oob_irq_flags = 0;
#ifdef CUSTOMER_HW_ROCKCHIP
@ -288,9 +269,19 @@ int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter)
* WL_REG_ON and WL_HOST_WAKE.
*/
#ifdef BCMDHD_DTS
#ifdef BCMDHD_PLATDEV
if (adapter->pdev) {
root_node = adapter->pdev->dev.of_node;
strcpy(wlan_node, root_node->name);
} else {
printf("%s: adapter->pdev is NULL\n", __FUNCTION__);
return -1;
}
#else
strcpy(wlan_node, DHD_DT_COMPAT_ENTRY);
printf("======== Get GPIO from DTS(%s) ========\n", wlan_node);
root_node = of_find_compatible_node(NULL, NULL, wlan_node);
#endif
printf("======== Get GPIO from DTS(%s) ========\n", wlan_node);
if (root_node) {
gpio_wl_reg_on = of_get_named_gpio(root_node, GPIO_WL_REG_ON_PROPNAME, 0);
#ifdef CUSTOMER_OOB
@ -308,8 +299,8 @@ int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter)
if (gpio_wl_reg_on >= 0) {
err = gpio_request(gpio_wl_reg_on, "WL_REG_ON");
if (err < 0) {
printf("%s: gpio_request(%d) for WL_REG_ON failed\n",
__FUNCTION__, gpio_wl_reg_on);
printf("%s: gpio_request(%d) for WL_REG_ON failed %d\n",
__FUNCTION__, gpio_wl_reg_on, err);
gpio_wl_reg_on = -1;
}
}
@ -319,22 +310,22 @@ int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter)
if (gpio_wl_host_wake >= 0) {
err = gpio_request(gpio_wl_host_wake, "bcmdhd");
if (err < 0) {
printf("%s: gpio_request(%d) for WL_HOST_WAKE failed\n",
__FUNCTION__, gpio_wl_host_wake);
printf("%s: gpio_request(%d) for WL_HOST_WAKE failed %d\n",
__FUNCTION__, gpio_wl_host_wake, err);
return -1;
}
adapter->gpio_wl_host_wake = gpio_wl_host_wake;
err = gpio_direction_input(gpio_wl_host_wake);
if (err < 0) {
printf("%s: gpio_direction_input(%d) for WL_HOST_WAKE failed\n",
__FUNCTION__, gpio_wl_host_wake);
printf("%s: gpio_direction_input(%d) for WL_HOST_WAKE failed %d\n",
__FUNCTION__, gpio_wl_host_wake, err);
gpio_free(gpio_wl_host_wake);
return -1;
}
host_oob_irq = gpio_to_irq(gpio_wl_host_wake);
if (host_oob_irq < 0) {
printf("%s: gpio_to_irq(%d) for WL_HOST_WAKE failed\n",
__FUNCTION__, gpio_wl_host_wake);
printf("%s: gpio_to_irq(%d) for WL_HOST_WAKE failed %d\n",
__FUNCTION__, gpio_wl_host_wake, host_oob_irq);
gpio_free(gpio_wl_host_wake);
return -1;
}
@ -374,7 +365,8 @@ int dhd_wlan_init_gpio(wifi_adapter_info_t *adapter)
return 0;
}
static void dhd_wlan_deinit_gpio(wifi_adapter_info_t *adapter)
static void
dhd_wlan_deinit_gpio(wifi_adapter_info_t *adapter)
{
int gpio_wl_reg_on = adapter->gpio_wl_reg_on;
#ifdef CUSTOMER_OOB
@ -384,42 +376,74 @@ static void dhd_wlan_deinit_gpio(wifi_adapter_info_t *adapter)
if (gpio_wl_reg_on >= 0) {
printf("%s: gpio_free(WL_REG_ON %d)\n", __FUNCTION__, gpio_wl_reg_on);
gpio_free(gpio_wl_reg_on);
gpio_wl_reg_on = -1;
adapter->gpio_wl_reg_on = -1;
}
#ifdef CUSTOMER_OOB
if (gpio_wl_host_wake >= 0) {
printf("%s: gpio_free(WL_HOST_WAKE %d)\n", __FUNCTION__, gpio_wl_host_wake);
gpio_free(gpio_wl_host_wake);
gpio_wl_host_wake = -1;
adapter->gpio_wl_host_wake = -1;
}
#endif /* CUSTOMER_OOB */
}
int dhd_wlan_init_plat_data(wifi_adapter_info_t *adapter)
#if defined(BCMDHD_MDRIVER)
static void
dhd_wlan_init_adapter(wifi_adapter_info_t *adapter)
{
#ifdef ADAPTER_IDX
if (ADAPTER_IDX == 0) {
adapter->bus_num = 1;
adapter->slot_num = 1;
} else if (ADAPTER_IDX == 1) {
adapter->bus_num = 2;
adapter->slot_num = 1;
}
adapter->index = ADAPTER_IDX;
#ifdef BCMSDIO
adapter->bus_type = SDIO_BUS;
#elif defined(BCMPCIE)
adapter->bus_type = PCI_BUS;
#elif defined(BCMDBUS)
adapter->bus_type = USB_BUS;
#endif
printf("bus_type=%d, bus_num=%d, slot_num=%d\n",
adapter->bus_type, adapter->bus_num, adapter->slot_num);
#endif /* ADAPTER_IDX */
#ifdef DHD_STATIC_IN_DRIVER
adapter->index = 0;
#elif !defined(ADAPTER_IDX)
#ifdef BCMSDIO
adapter->index = 0;
#elif defined(BCMPCIE)
adapter->index = 1;
#elif defined(BCMDBUS)
adapter->index = 2;
#endif
#endif /* DHD_STATIC_IN_DRIVER */
}
#endif /* BCMDHD_MDRIVER */
int
dhd_wlan_init_plat_data(wifi_adapter_info_t *adapter)
{
int err = 0;
printf("======== %s ========\n", __FUNCTION__);
if (adapter->index == -1) {
adapter->index = 0;
}
#ifdef BCMDHD_MDRIVER
dhd_wlan_init_adapter(adapter);
#endif /* BCMDHD_MDRIVER */
err = dhd_wlan_init_gpio(adapter);
if (err)
goto exit;
#ifdef DHD_STATIC_IN_DRIVER
err = dhd_static_buf_init();
#endif
exit:
return err;
}
void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter)
void
dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter)
{
printf("======== %s ========\n", __FUNCTION__);
#ifdef DHD_STATIC_IN_DRIVER
dhd_static_buf_exit();
#endif
dhd_wlan_deinit_gpio(adapter);
}

View File

@ -1,7 +1,7 @@
/*
* IP Packet Parser Module.
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -31,6 +31,7 @@
#include <bcmip.h>
#include <bcmendian.h>
#include <dhd.h>
#include <dhd_dbg.h>
#include <dhd_ip.h>
@ -976,6 +977,11 @@ dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt)
cur_framelen -= ETHER_HDR_LEN;
ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN);
if (cur_framelen < IPV4_MIN_HEADER_LEN) {
DHD_TRACE(("%s %d: cur_framelen(%d) < IPV4_MIN_HEADER_LEN\n", __FUNCTION__,
__LINE__, cur_framelen));
goto exit;
}
ip_hdr_len = IPV4_HLEN(ip_hdr);
if (IP_VER(ip_hdr) != IP_VER_4 || IPV4_PROT(ip_hdr) != IP_PROT_TCP) {
@ -988,6 +994,11 @@ dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt)
cur_framelen -= ip_hdr_len;
ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN);
if (cur_framelen < TCP_MIN_HEADER_LEN) {
DHD_TRACE(("%s %d: cur_framelen is less than TCP_MIN_HEADER_LEN\n",
__FUNCTION__, __LINE__));
goto exit;
}
DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__));

View File

@ -3,7 +3,7 @@
*
* Provides type definitions and function prototypes used to parse ip packet.
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -62,10 +62,10 @@ extern tcp_hdr_flag_t dhd_tcpdata_get_flag(dhd_pub_t *dhdp, void *pkt);
/* Max number of TCP streams that have own src/dst IP addrs and TCP ports */
#ifndef TCPACK_INFO_MAXNUM
#define TCPACK_INFO_MAXNUM 4
#define TCPACK_INFO_MAXNUM 40
#endif
#ifndef TCPDATA_INFO_MAXNUM
#define TCPDATA_INFO_MAXNUM 4
#define TCPDATA_INFO_MAXNUM 40
#endif
#define TCPDATA_PSH_INFO_MAXNUM (8 * TCPDATA_INFO_MAXNUM)

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

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* DHD Linux header file (dhd_linux exports for cfg80211 and other components)
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -35,6 +35,9 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <dngl_stats.h>
#ifdef DHD_LOG_DUMP
#include <dhd_log_dump.h>
#endif
#include <dhd.h>
#ifdef DHD_WMF
#include <dhd_wmf_linux.h>
@ -55,6 +58,14 @@
#include <etd.h>
#endif /* PCIE_FULL_DONGLE */
#ifdef CONFIG_IRQ_HISTORY
#include <linux/power/irq_history.h>
#endif /* CONFIG_IRQ_HISTORY */
#if defined(OEM_ANDROID)
#include <linux/nl80211.h>
#endif /* OEM_ANDROID */
#ifdef WL_MONITOR
#ifdef HOST_RADIOTAP_CONV
#include <bcmwifi_monitor.h>
@ -67,9 +78,9 @@
/* dongle status */
enum wifi_adapter_status {
WIFI_STATUS_POWER_ON = 0,
WIFI_STATUS_ATTACH,
WIFI_STATUS_FW_READY,
WIFI_STATUS_DETTACH
WIFI_STATUS_NET_ATTACHED,
WIFI_STATUS_BUS_DISCONNECTED
};
#define wifi_chk_adapter_status(adapter, stat) (test_bit(stat, &(adapter)->status))
#define wifi_get_adapter_status(adapter, stat) (test_bit(stat, &(adapter)->status))
@ -77,9 +88,149 @@ enum wifi_adapter_status {
#define wifi_clr_adapter_status(adapter, stat) (clear_bit(stat, &(adapter)->status))
#define wifi_chg_adapter_status(adapter, stat) (change_bit(stat, &(adapter)->status))
#ifdef DHD_COREDUMP
#define PC_FOUND_BIT 0x01
#define LR_FOUND_BIT 0x02
#define ALL_ADDR_VAL (PC_FOUND_BIT | LR_FOUND_BIT)
#define READ_NUM_BYTES 1000
#define DHD_FUNC_STR_LEN 80
#define DHD_COREDUMP_MAGIC 0xDDCEDACF
#define TLV_TYPE_LENGTH_SIZE (8u)
/* coredump is composed as following TLV format.
* Type(32bit) | Length(32bit) | Value(x bit)
* e.g) socram type | length | socram dump
* sssr core1 type | length | sssr core1 dump
* ...
*/
enum coredump_types {
DHD_COREDUMP_TYPE_SSSRDUMP_CORE0_BEFORE = 0,
DHD_COREDUMP_TYPE_SSSRDUMP_CORE0_AFTER,
DHD_COREDUMP_TYPE_SSSRDUMP_CORE1_BEFORE,
DHD_COREDUMP_TYPE_SSSRDUMP_CORE1_AFTER,
DHD_COREDUMP_TYPE_SSSRDUMP_CORE2_BEFORE,
DHD_COREDUMP_TYPE_SSSRDUMP_CORE2_AFTER,
DHD_COREDUMP_TYPE_SSSRDUMP_DIG_BEFORE,
DHD_COREDUMP_TYPE_SSSRDUMP_DIG_AFTER,
DHD_COREDUMP_TYPE_SOCRAMDUMP
};
#ifdef DHD_SSSR_DUMP
typedef struct dhd_coredump {
uint32 type;
uint32 length;
void *bufptr;
} dhd_coredump_t;
#endif /* DHD_SSSR_DUMP */
#endif /* DHD_COREDUMP */
#ifdef BCMDBUS
#define DBUS_NRXQ 50
#define DBUS_NTXQ 100
#endif /* BCMDBUS */
#ifdef DHD_WAKE_RX_STATUS
#define ETHER_ICMP6_HEADER 20
#define ETHER_IPV6_SADDR (ETHER_ICMP6_HEADER + 2)
#define ETHER_IPV6_DAADR (ETHER_IPV6_SADDR + IPV6_ADDR_LEN)
#define ETHER_ICMPV6_TYPE (ETHER_IPV6_DAADR + IPV6_ADDR_LEN)
#endif /* DHD_WAKE_RX_STATUS */
#ifdef SUPPORT_AP_POWERSAVE
#define RXCHAIN_PWRSAVE_PPS 10
#define RXCHAIN_PWRSAVE_QUIET_TIME 10
#define RXCHAIN_PWRSAVE_STAS_ASSOC_CHECK 0
#endif /* SUPPORT_AP_POWERSAVE */
#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */
#define DHD_FW_READY_TIMEOUT 5000 /* msec : allowed time to finished fw download */
/* FW initialised value for ocl_rssi_threshold */
#define FW_OCL_RSSI_THRESH_INITVAL -75
#if defined(DHD_TRACE_WAKE_LOCK)
typedef enum dhd_wklock_type {
DHD_WAKE_LOCK,
DHD_WAKE_UNLOCK,
DHD_WAIVE_LOCK,
DHD_RESTORE_LOCK
} dhd_wklock_t;
struct wk_trace_record {
unsigned long addr; /* Address of the instruction */
dhd_wklock_t lock_type; /* lock_type */
unsigned long long counter; /* counter information */
struct hlist_node wklock_node; /* hash node */
};
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
#define HASH_ADD(hashtable, node, key) \
do { \
hash_add(hashtable, node, key); \
} while (0);
#else
#define HASH_ADD(hashtable, node, key) \
do { \
int index = hash_long(key, ilog2(ARRAY_SIZE(hashtable))); \
hlist_add_head(node, &hashtable[index]); \
} while (0);
#endif /* KERNEL_VER < KERNEL_VERSION(3, 7, 0) */
#define STORE_WKLOCK_RECORD(wklock_type) \
do { \
struct wk_trace_record *wklock_info = NULL; \
unsigned long func_addr = (unsigned long)__builtin_return_address(0); \
wklock_info = find_wklock_entry(func_addr); \
if (wklock_info) { \
if (wklock_type == DHD_WAIVE_LOCK || wklock_type == DHD_RESTORE_LOCK) { \
wklock_info->counter = dhd->wakelock_counter; \
} else { \
wklock_info->counter++; \
} \
} else { \
wklock_info = kzalloc(sizeof(*wklock_info), GFP_ATOMIC); \
if (!wklock_info) {\
DHD_ERROR(("Can't allocate wk_trace_record \n")); \
} else { \
wklock_info->addr = func_addr; \
wklock_info->lock_type = wklock_type; \
if (wklock_type == DHD_WAIVE_LOCK || \
wklock_type == DHD_RESTORE_LOCK) { \
wklock_info->counter = dhd->wakelock_counter; \
} else { \
wklock_info->counter++; \
} \
HASH_ADD(wklock_history, &wklock_info->wklock_node, func_addr); \
} \
} \
} while (0);
#else
#define STORE_WKLOCK_RECORD(wklock_type)
#endif /* DHD_TRACE_WAKE_LOCK */
#ifdef ENABLE_ADAPTIVE_SCHED
#define DEFAULT_CPUFREQ_THRESH 1000000 /* threshold frequency : 1000000 = 1GHz */
#ifndef CUSTOM_CPUFREQ_THRESH
#define CUSTOM_CPUFREQ_THRESH DEFAULT_CPUFREQ_THRESH
#endif /* CUSTOM_CPUFREQ_THRESH */
#endif /* ENABLE_ADAPTIVE_SCHED */
/* enable HOSTIP cache update from the host side when an eth0:N is up */
#define AOE_IP_ALIAS_SUPPORT 1
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) && defined(DHD_TCP_LIMIT_OUTPUT)
#ifndef DHD_TCP_LIMIT_OUTPUT_BYTES
#define DHD_TCP_LIMIT_OUTPUT_BYTES (4 * 1024 * 1024)
#endif /* DHD_TCP_LIMIT_OUTPUT_BYTES */
#ifndef TCP_DEFAULT_LIMIT_OUTPUT
#define TCP_DEFAULT_LIMIT_OUTPUT (256 * 1024)
#endif /* TSQ_DEFAULT_LIMIT_OUTPUT */
#endif /* LINUX_VERSION_CODE > 4.19.0 && DHD_TCP_LIMIT_OUTPUT */
#define DHD_MEMDUMP_TYPE_STR_LEN 32
#define DHD_MEMDUMP_PATH_STR_LEN 128
typedef struct wifi_adapter_info {
const char *name;
uint irq_num;
@ -99,7 +250,7 @@ typedef struct wifi_adapter_info {
#endif
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) */
#if defined(BCMSDIO)
@ -109,9 +260,12 @@ typedef struct wifi_adapter_info {
struct pci_dev *pci_dev;
struct pci_saved_state *pci_saved_state;
#endif /* BCMPCIE */
#ifdef BCMDHD_PLATDEV
struct platform_device *pdev;
#endif /* BCMDHD_PLATDEV */
} wifi_adapter_info_t;
#if defined(CONFIG_WIFI_CONTROL_FUNC) || defined(CUSTOMER_HW4)
#if defined(CONFIG_WIFI_CONTROL_FUNC)
#include <linux/wlan_plat.h>
#else
#include <dhd_plat.h>
@ -134,6 +288,7 @@ typedef struct dhd_sta {
#ifdef DHD_WMF
struct dhd_sta *psta_prim; /* primary index of psta interface */
#endif /* DHD_WMF */
chanspec_t chanspec; /* sta chanspec info */
} dhd_sta_t;
typedef dhd_sta_t dhd_sta_pool_t;
@ -204,12 +359,6 @@ typedef struct dhd_tx_lb_pkttag_fr {
#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"
@ -230,35 +379,6 @@ extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd, int *dtim_period, int *bc
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 */
@ -272,65 +392,6 @@ extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int* idle_time);
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;
@ -454,20 +515,24 @@ struct dhd_rx_tx_work {
#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
#ifdef FILTER_IE
#ifdef DHD_LINUX_STD_FW_API
#define FILTER_IE_PATH "filter_ie"
#else
#define FILTER_IE_PATH "/vendor/etc/wifi/filter_ie"
#endif /* DHD_LINUX_STD_FW_API */
#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)
do { \
if (!(p)) { \
DHD_ERROR(("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);
@ -505,22 +570,40 @@ 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 */
#if defined(WLADPS) || defined(WLADPS_PRIVATE_CMD)
#if defined(WLADPS)
#define ADPS_ENABLE 1
#define ADPS_DISABLE 0
#define ADPS_MODE_PM2_ONLY 3
int dhd_enable_adps(dhd_pub_t *dhd, uint8 on);
#endif /* WLADPS || WLADPS_PRIVATE_CMD */
#endif
#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 */
extern void dhd_set_del_in_progress(dhd_pub_t *dhdp, struct net_device * ndev);
extern void dhd_clear_del_in_progress(dhd_pub_t *dhdp, struct net_device * ndev);
#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);
#ifdef BCMDBUS
int dhd_dbus_txdata(dhd_pub_t *dhdp, void *pktbuf);
#endif
void dhd_event_logtrace_enqueue(dhd_pub_t *dhdp, int ifidx, void *pktbuf);
#if defined(SUPPORT_MULTIPLE_NVRAM) || defined(SUPPORT_MULTIPLE_CLMBLOB)
int dhd_get_platform_naming_for_nvram_clmblob_file(download_type_t component, char* file_name);
#ifdef USE_CID_CHECK
void dhd_set_platform_ext_name_for_chip_version(char* chip_version);
#endif /* USE_CID_CHECK */
#endif /* SUPPORT_MULTIPLE_NVRAM || SUPPORT_MULTIPLE_CLMBLOB */
void dhd_netif_rx_ni(struct sk_buff * skb);
#if defined(DBG_PKT_MON) && !defined(PCIE_FULL_DONGLE)
extern bool dhd_80211_mon_pkt(dhd_pub_t *dhdp, void *pkt, int ifidx);
#endif /* DBG_PKT_MON */
#endif /* __DHD_LINUX_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
* Broadcom Dongle Host Driver (DHD), Linux-specific network interface
* Basically selected code segments from usb-cdc.c and usb-rndis.c
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -35,12 +35,6 @@ extern dhd_pub_t* g_dhd_pub;
#define DHD_NAPI_LATENCY_SIZE (sizeof(uint64) * DHD_NUM_NAPI_LATENCY_ROWS)
#endif /* DHD_LB_STATS */
#ifdef DHD_REPLACE_LOG_INFO_TO_TRACE
#define DHD_LB_INFO DHD_TRACE
#else
#define DHD_LB_INFO DHD_INFO
#endif /* DHD_REPLACE_LOG_INFO_TO_TRACE */
void
dhd_lb_set_default_cpus(dhd_info_t *dhd)
{
@ -173,8 +167,22 @@ void dhd_select_cpu_candidacy(dhd_info_t *dhd)
* cpumask_next returns >= nr_cpu_ids
*/
tx_cpu = cpumask_next(napi_cpu, dhd->cpumask_primary_new);
if (tx_cpu >= nr_cpu_ids)
tx_cpu = 0;
if (tx_cpu >= nr_cpu_ids) {
/* If no CPU is available for tx processing in primary CPUs,
* choose the same CPU with net_tx_cpu
* in case net_tx_cpu is in primary CPUs.
*/
cpumask_and(dhd->cpumask_primary_new, dhd->cpumask_primary,
dhd->cpumask_curr_avail);
if (cpumask_test_cpu(net_tx_cpu, dhd->cpumask_primary_new)) {
tx_cpu = net_tx_cpu;
DHD_INFO(("%s If no CPU is for tx cpu, use net_tx_cpu %d\n",
__FUNCTION__, net_tx_cpu));
} else {
tx_cpu = 0;
}
}
}
DHD_INFO(("%s After primary CPU check napi_cpu %d tx_cpu %d\n",
@ -200,24 +208,31 @@ void dhd_select_cpu_candidacy(dhd_info_t *dhd)
} else if (tx_cpu == 0) {
tx_cpu = cpumask_first(dhd->cpumask_secondary_new);
}
/* If no CPU was available for tx processing, choose CPU 0 */
if (tx_cpu >= nr_cpu_ids)
tx_cpu = 0;
}
if ((primary_available_cpus == 0) &&
(secondary_available_cpus == 0)) {
/* No CPUs available from primary or secondary mask */
napi_cpu = 1;
tx_cpu = 2;
tx_cpu = napi_cpu = nr_cpu_ids - 1;
}
DHD_INFO(("%s After secondary CPU check napi_cpu %d tx_cpu %d\n",
__FUNCTION__, napi_cpu, tx_cpu));
/* If no CPU was available for napi processing, choose CPU 0 */
if (napi_cpu >= nr_cpu_ids)
napi_cpu = 0;
ASSERT(napi_cpu < nr_cpu_ids);
ASSERT(tx_cpu < nr_cpu_ids);
/* If no CPU was available for tx processing, choose CPU 0 */
if (tx_cpu >= nr_cpu_ids)
tx_cpu = 0;
DHD_INFO(("%s After secondary CPU check napi_cpu %d tx_cpu %d nr cpu ids %d\n",
__FUNCTION__, napi_cpu, tx_cpu, nr_cpu_ids));
if (!cpu_online(napi_cpu)) {
napi_cpu = 0;
}
if (!cpu_online(tx_cpu)) {
tx_cpu = 0;
}
atomic_set(&dhd->rx_napi_cpu, napi_cpu);
atomic_set(&dhd->tx_cpu, tx_cpu);
@ -237,6 +252,12 @@ int dhd_cpu_startup_callback(unsigned int cpu)
{
dhd_info_t *dhd = g_dhd_pub->info;
if (!dhd || !(dhd->dhd_state & DHD_ATTACH_STATE_LB_ATTACH_DONE)) {
DHD_ERROR(("%s(): LB data is not initialized yet.\n",
__FUNCTION__));
return 0;
}
DHD_INFO(("%s(): \r\n cpu:%d", __FUNCTION__, cpu));
DHD_LB_STATS_INCR(dhd->cpu_online_cnt[cpu]);
cpumask_set_cpu(cpu, dhd->cpumask_curr_avail);
@ -249,6 +270,12 @@ int dhd_cpu_teardown_callback(unsigned int cpu)
{
dhd_info_t *dhd = g_dhd_pub->info;
if (!dhd || !(dhd->dhd_state & DHD_ATTACH_STATE_LB_ATTACH_DONE)) {
DHD_ERROR(("%s(): LB data is not initialized yet.\n",
__FUNCTION__));
return 0;
}
DHD_INFO(("%s(): \r\n cpu:%d", __FUNCTION__, cpu));
DHD_LB_STATS_INCR(dhd->cpu_offline_cnt[cpu]);
cpumask_clear_cpu(cpu, dhd->cpumask_curr_avail);
@ -299,14 +326,13 @@ dhd_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
int dhd_register_cpuhp_callback(dhd_info_t *dhd)
{
int cpuhp_ret = 0;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
cpuhp_ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "dhd",
dhd->dhd_cpuhp_state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "dhd",
dhd_cpu_startup_callback, dhd_cpu_teardown_callback);
if (cpuhp_ret < 0) {
if (dhd->dhd_cpuhp_state < 0) {
DHD_ERROR(("%s(): cpuhp_setup_state failed %d RX LB won't happen \r\n",
__FUNCTION__, cpuhp_ret));
__FUNCTION__, dhd->dhd_cpuhp_state));
}
#else
/*
@ -317,7 +343,7 @@ int dhd_register_cpuhp_callback(dhd_info_t *dhd)
dhd->cpu_notifier.notifier_call = dhd_cpu_callback;
register_hotcpu_notifier(&dhd->cpu_notifier); /* Register a callback */
#endif /* LINUX_VERSION_CODE < 4.10.0 */
return cpuhp_ret;
return dhd->dhd_cpuhp_state;
}
int dhd_unregister_cpuhp_callback(dhd_info_t *dhd)
@ -325,12 +351,14 @@ int dhd_unregister_cpuhp_callback(dhd_info_t *dhd)
int ret = 0;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
/* Don't want to call tear down while unregistering */
cpuhp_remove_state_nocalls(CPUHP_AP_ONLINE_DYN);
if (dhd->dhd_cpuhp_state >= 0) {
cpuhp_remove_state_nocalls(dhd->dhd_cpuhp_state);
}
#else
if (dhd->cpu_notifier.notifier_call != NULL) {
unregister_cpu_notifier(&dhd->cpu_notifier);
}
#endif
#endif /* LINUX_VERSION_CODE < 4.10.0 */
return ret;
}
@ -647,7 +675,7 @@ void dhd_lb_stats_dump_cpu_array(struct bcmstrbuf *strbuf, uint32 *p)
uint64 dhd_lb_mem_usage(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
{
dhd_info_t *dhd;
uint16 rxbufpost_sz;
uint16 rxbufpost_alloc_sz;
uint16 rx_post_active = 0;
uint16 rx_cmpl_active = 0;
uint64 rx_path_memory_usage = 0;
@ -663,28 +691,30 @@ uint64 dhd_lb_mem_usage(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
DHD_ERROR(("%s(): DHD pointer is NULL \n", __FUNCTION__));
return 0;
}
rxbufpost_sz = dhd_prot_get_rxbufpost_sz(dhdp);
if (rxbufpost_sz == 0) {
rxbufpost_sz = DHD_FLOWRING_RX_BUFPOST_PKTSZ;
rxbufpost_alloc_sz = dhd_prot_get_rxbufpost_alloc_sz(dhdp);
if (rxbufpost_alloc_sz == 0) {
rxbufpost_alloc_sz = DHD_FLOWRING_RX_BUFPOST_PKTSZ;
}
rx_path_memory_usage = rxbufpost_sz * (skb_queue_len(&dhd->rx_pend_queue) +
rx_path_memory_usage = rxbufpost_alloc_sz * (skb_queue_len(&dhd->rx_emerge_queue) +
skb_queue_len(&dhd->rx_pend_queue) +
skb_queue_len(&dhd->rx_napi_queue) +
skb_queue_len(&dhd->rx_process_queue));
rx_post_active = dhd_prot_get_h2d_rx_post_active(dhdp);
if (rx_post_active != 0) {
rx_path_memory_usage += (rxbufpost_sz * rx_post_active);
rx_path_memory_usage += (rxbufpost_alloc_sz * rx_post_active);
}
rx_cmpl_active = dhd_prot_get_d2h_rx_cpln_active(dhdp);
if (rx_cmpl_active != 0) {
rx_path_memory_usage += (rxbufpost_sz * rx_cmpl_active);
rx_path_memory_usage += (rxbufpost_alloc_sz * rx_cmpl_active);
}
dhdp->rxpath_mem = rx_path_memory_usage;
bcm_bprintf(strbuf, "\nrxbufpost_sz: %d rx_post_active: %d rx_cmpl_active: %d "
"pend_queue_len: %d napi_queue_len: %d process_queue_len: %d\n",
rxbufpost_sz, rx_post_active, rx_cmpl_active,
skb_queue_len(&dhd->rx_pend_queue),
bcm_bprintf(strbuf, "\nrxbufpost_alloc_sz: %d rx_post_active: %d rx_cmpl_active: %d "
"emerge_queue_len: %d pend_queue_len: %d napi_queue_len: %d"
" process_queue_len: %d\n",
rxbufpost_alloc_sz, rx_post_active, rx_cmpl_active,
skb_queue_len(&dhd->rx_emerge_queue), skb_queue_len(&dhd->rx_pend_queue),
skb_queue_len(&dhd->rx_napi_queue), skb_queue_len(&dhd->rx_process_queue));
bcm_bprintf(strbuf, "DHD rx-path memory_usage: %llubytes %lluKB \n",
rx_path_memory_usage, (rx_path_memory_usage/ 1024));
@ -708,6 +738,7 @@ void dhd_lb_stats_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
return;
}
bcm_bprintf(strbuf, "\nLoad Balancing/NAPI stats:\n==========================\n");
bcm_bprintf(strbuf, "\ncpu_online_cnt:\n");
dhd_lb_stats_dump_cpu_array(strbuf, dhd->cpu_online_cnt);
@ -731,6 +762,13 @@ void dhd_lb_stats_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
dhd_lb_stats_dump_histo(dhdp, strbuf, dhd->napi_rx_hist);
bcm_bprintf(strbuf, "\nNAPI poll latency stats ie from napi schedule to napi execution\n");
dhd_lb_stats_dump_napi_latency(dhdp, strbuf, dhd->napi_latency);
bcm_bprintf(strbuf, "\nlb_rxp_stop_thr_hitcnt: %llu lb_rxp_strt_thr_hitcnt: %llu"
" rx_dma_stall_hc_ignore_cnt: %llu\n",
dhdp->lb_rxp_stop_thr_hitcnt, dhdp->lb_rxp_strt_thr_hitcnt,
dhdp->rx_dma_stall_hc_ignore_cnt);
bcm_bprintf(strbuf, "\nlb_rxp_napi_sched_cnt: %llu lb_rxp_napi_omplete_cnt: %llu\n",
dhdp->lb_rxp_napi_sched_cnt, dhdp->lb_rxp_napi_complete_cnt);
#endif /* DHD_LB_RXP */
#ifdef DHD_LB_TXP
@ -740,6 +778,7 @@ void dhd_lb_stats_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
bcm_bprintf(strbuf, "\ntx_start_percpu_run_cnt:\n");
dhd_lb_stats_dump_cpu_array(strbuf, dhd->tx_start_percpu_run_cnt);
#endif /* DHD_LB_TXP */
bcm_bprintf(strbuf, "\n");
}
void dhd_lb_stats_update_napi_latency(uint64 *bin, uint32 latency)
@ -986,7 +1025,7 @@ dhd_napi_poll(struct napi_struct *napi, int budget)
napi_latency = (uint32)(OSL_SYSUPTIME_US() - dhd->napi_schedule_time);
dhd_lb_stats_update_napi_latency(dhd->napi_latency, napi_latency);
#endif /* DHD_LB_STATS */
DHD_LB_INFO(("%s napi_queue<%d> budget<%d>\n",
DHD_INFO(("%s napi_queue<%d> budget<%d>\n",
__FUNCTION__, skb_queue_len(&dhd->rx_napi_queue), budget));
/*
@ -1008,7 +1047,7 @@ dhd_napi_poll(struct napi_struct *napi, int budget)
ifid = DHD_PKTTAG_IFID((dhd_pkttag_fr_t *)PKTTAG(skb));
DHD_LB_INFO(("%s dhd_rx_frame pkt<%p> ifid<%d>\n",
DHD_INFO(("%s dhd_rx_frame pkt<%p> ifid<%d>\n",
__FUNCTION__, skb, ifid));
dhd_rx_frame(&dhd->pub, ifid, skb, pkt_count, chan);
@ -1032,7 +1071,7 @@ dhd_napi_poll(struct napi_struct *napi, int budget)
}
DHD_LB_STATS_UPDATE_NAPI_HISTO(&dhd->pub, processed);
DHD_LB_INFO(("%s processed %d\n", __FUNCTION__, processed));
DHD_INFO(("%s processed %d\n", __FUNCTION__, processed));
/*
* Signal napi complete only when no more packets are processed and
@ -1076,6 +1115,21 @@ dhd_napi_schedule(void *info)
DHD_INFO(("%s rx_napi_struct<%p> on cpu<%d>\n",
__FUNCTION__, &dhd->rx_napi_struct, atomic_read(&dhd->rx_napi_cpu)));
/* On Android platform, napi prevention during suspend in progress causes
* rx performance drop of ~5Mbs(SWWLAN-349763).
* So, excludes this prevention for Android platform.
*/
#ifndef OEM_ANDROID
DHD_GENERAL_LOCK(&dhd->pub, flags);
if (DHD_BUS_BUSY_CHECK_SUSPEND_IN_PROGRESS(&dhd->pub)) {
DHD_GENERAL_UNLOCK(&dhd->pub, flags);
return;
}
DHD_GENERAL_UNLOCK(&dhd->pub, flags);
#endif /* OEM_ANDROID */
/* add napi_struct to softnet data poll list and raise NET_RX_SOFTIRQ */
if (napi_schedule_prep(&dhd->rx_napi_struct)) {
@ -1104,31 +1158,6 @@ dhd_napi_schedule(void *info)
*/
}
/**
* dhd_napi_schedule_on - API to schedule on a desired CPU core a NET_RX_SOFTIRQ
* action after placing the dhd's rx_process napi object in the the remote CPU's
* softnet data's poll_list.
*
* @dhd: dhd_info which has the rx_process napi object
* @on_cpu: desired remote CPU id
*/
static INLINE int
dhd_napi_schedule_on(dhd_info_t *dhd, int on_cpu)
{
int wait = 0; /* asynchronous IPI */
DHD_INFO(("%s dhd<%p> napi<%p> on_cpu<%d>\n",
__FUNCTION__, dhd, &dhd->rx_napi_struct, on_cpu));
if (smp_call_function_single(on_cpu, dhd_napi_schedule, dhd, wait)) {
DHD_ERROR(("%s smp_call_function_single on_cpu<%d> failed\n",
__FUNCTION__, on_cpu));
}
DHD_LB_STATS_INCR(dhd->napi_sched_cnt);
return 0;
}
/*
* Call get_online_cpus/put_online_cpus around dhd_napi_schedule_on
* Why should we do this?
@ -1186,7 +1215,7 @@ dhd_lb_rx_napi_dispatch(dhd_pub_t *dhdp)
return;
}
DHD_LB_INFO(("%s append napi_queue<%d> pend_queue<%d>\n", __FUNCTION__,
DHD_INFO(("%s append napi_queue<%d> pend_queue<%d>\n", __FUNCTION__,
skb_queue_len(&dhd->rx_napi_queue), skb_queue_len(&dhd->rx_pend_queue)));
/* append the producer's queue of packets to the napi's rx process queue */
@ -1236,7 +1265,7 @@ dhd_lb_rx_napi_dispatch(dhd_pub_t *dhdp)
}
DHD_LB_INFO(("%s : schedule to curr_cpu : %d, rx_napi_cpu : %d\n",
DHD_INFO(("%s : schedule to curr_cpu : %d, rx_napi_cpu : %d\n",
__FUNCTION__, curr_cpu, rx_napi_cpu));
dhd_work_schedule_on(&dhd->rx_napi_dispatcher_work, rx_napi_cpu);
DHD_LB_STATS_INCR(dhd->napi_sched_cnt);
@ -1244,6 +1273,26 @@ dhd_lb_rx_napi_dispatch(dhd_pub_t *dhdp)
put_cpu();
}
/**
* dhd_rx_emerge_enqueue - Enqueue the packet into the ememrgency queue for repost
*/
void
dhd_rx_emerge_enqueue(dhd_pub_t *dhdp, void *pkt)
{
dhd_info_t *dhd = dhdp->info;
skb_queue_tail(&dhd->rx_emerge_queue, pkt);
}
/**
* dhd_rx_emerge_dequeue - Deueue the packet from the emergency queue for repost
*/
void *
dhd_rx_emerge_dequeue(dhd_pub_t *dhdp)
{
dhd_info_t *dhd = dhdp->info;
return skb_dequeue(&dhd->rx_emerge_queue);
}
/**
* dhd_lb_rx_pkt_enqueue - Enqueue the packet into the producer's queue
*/
@ -1252,7 +1301,7 @@ dhd_lb_rx_pkt_enqueue(dhd_pub_t *dhdp, void *pkt, int ifidx)
{
dhd_info_t *dhd = dhdp->info;
DHD_LB_INFO(("%s enqueue pkt<%p> ifidx<%d> pend_queue<%d>\n", __FUNCTION__,
DHD_INFO(("%s enqueue pkt<%p> ifidx<%d> pend_queue<%d>\n", __FUNCTION__,
pkt, ifidx, skb_queue_len(&dhd->rx_pend_queue)));
DHD_PKTTAG_SET_IFID((dhd_pkttag_fr_t *)PKTTAG(pkt), ifidx);
__skb_queue_tail(&dhd->rx_pend_queue, pkt);
@ -1304,7 +1353,9 @@ BCMFASTPATH(dhd_lb_sendpkt)(dhd_info_t *dhd, struct net_device *net,
#endif /* DHD_LB_TXP */
#ifdef DHD_LB_TXP
#ifndef DHD_LB_TXBOUND
#define DHD_LB_TXBOUND 64
#endif
/*
* Function that performs the TX processing on a given CPU
*/
@ -1351,7 +1402,7 @@ dhd_lb_tx_process(dhd_info_t *dhd)
} while (1);
DHD_LB_INFO(("%s(): Processed %d packets \r\n", __FUNCTION__, cnt));
DHD_INFO(("%s(): Processed %d packets \r\n", __FUNCTION__, cnt));
return resched;
}
@ -1369,7 +1420,7 @@ dhd_lb_tx_handler(unsigned long data)
#endif /* DHD_LB_TXP */
#endif /* DHD_LB */
#if defined(DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON)
#if defined(SET_PCIE_IRQ_CPU_CORE) || defined(DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON)
void
dhd_irq_set_affinity(dhd_pub_t *dhdp, const struct cpumask *cpumask)
{
@ -1399,4 +1450,77 @@ dhd_irq_set_affinity(dhd_pub_t *dhdp, const struct cpumask *cpumask)
DHD_ERROR(("%s : irq set affinity is failed cpu:0x%lx\n",
__FUNCTION__, *cpumask_bits(cpumask)));
}
#endif /* DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON */
#endif /* SET_PCIE_IRQ_CPU_CORE || DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON */
#ifdef SET_PCIE_IRQ_CPU_CORE
void
dhd_set_irq_cpucore(dhd_pub_t *dhdp, int affinity_cmd)
{
#if defined(DHD_LB) && defined(DHD_LB_HOST_CTRL)
struct dhd_info *dhd = NULL;
#endif /* DHD_LB && DHD_LB_HOST_CTRL */
if (!dhdp) {
DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__));
return;
}
if (!dhdp->bus) {
DHD_ERROR(("%s : dhd->bus is NULL\n", __FUNCTION__));
return;
}
if (affinity_cmd < DHD_AFFINITY_OFF || affinity_cmd > DHD_AFFINITY_LAST) {
DHD_ERROR(("Wrong Affinity cmds:%d, %s\n", affinity_cmd, __FUNCTION__));
return;
}
DHD_ERROR(("Enter %s, PCIe affinity cmd=0x%x\n", __FUNCTION__, affinity_cmd));
#if defined(DHD_LB) && defined(DHD_LB_HOST_CTRL)
dhd = dhdp->info;
if (affinity_cmd == DHD_AFFINITY_OFF) {
dhd->permitted_primary_cpu = FALSE;
} else if (affinity_cmd == DHD_AFFINITY_TPUT_150MBPS ||
affinity_cmd == DHD_AFFINITY_TPUT_300MBPS) {
dhd->permitted_primary_cpu = TRUE;
}
dhd_select_cpu_candidacy(dhd);
/*
* It needs to NAPI disable -> enable to raise NET_RX napi CPU core
* during Rx traffic
* NET_RX does not move to NAPI CPU core if continusly calling napi polling
* function
*/
napi_disable(&dhd->rx_napi_struct);
napi_enable(&dhd->rx_napi_struct);
#endif /* DHD_LB && DHD_LB_HOST_CTRL */
/*
irq_set_affinity() assign dedicated CPU core PCIe interrupt
If dedicated CPU core is not on-line,
PCIe interrupt scheduled on CPU core 0
*/
switch (affinity_cmd) {
case DHD_AFFINITY_OFF:
#if defined(DHD_LB) && defined(DHD_LB_HOST_CTRL)
dhd_irq_set_affinity(dhdp, dhdp->info->cpumask_secondary);
#endif /* DHD_LB && DHD_LB_HOST_CTRL */
break;
case DHD_AFFINITY_TPUT_150MBPS:
dhd_irq_set_affinity(dhdp, dhdp->info->cpumask_primary);
break;
case DHD_AFFINITY_TPUT_300MBPS:
#ifdef CONFIG_ARCH_EXYNOS
dhd_irq_set_affinity(dhdp, cpumask_of(PCIE_IRQ_CPU_CORE));
#else
dhd_irq_set_affinity(dhdp, dhdp->info->cpumask_primary);
#endif /* CONFIG_ARCH_EXYNOS */
break;
default:
DHD_ERROR(("%s, Unknown PCIe affinity cmd=0x%x\n",
__FUNCTION__, affinity_cmd));
}
}
#endif /* SET_PCIE_IRQ_CPU_CORE */

View File

@ -1,7 +1,7 @@
/*
* Packet dump helper functions
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -37,7 +37,13 @@
#include <bcmdhcp.h>
#include <bcmarp.h>
#include <bcmicmp.h>
#include <bcmigmp.h>
#include <dhd_linux_pktdump.h>
#ifdef WL_CFGVENDOR_CUST_ADVLOG
#include <wl_cfg80211.h>
#include <wl_cfgvendor.h>
#include <dhd_flowring.h>
#endif /* WL_CFGVENDOR_CUST_ADVLOG */
#include <dhd_config.h>
#include <wl_android.h>
@ -168,16 +174,27 @@ static const char pkt_cnt_msg[][20] = {
};
#endif
static const char tx_pktfate[][30] = {
"TX_PKT_FATE_ACKED", /* 0: WLFC_CTL_PKTFLAG_DISCARD */
"TX_PKT_FATE_FW_QUEUED", /* 1: WLFC_CTL_PKTFLAG_D11SUPPRESS */
"TX_PKT_FATE_FW_QUEUED", /* 2: WLFC_CTL_PKTFLAG_WLSUPPRESS */
"TX_PKT_FATE_FW_DROP_INVALID", /* 3: WLFC_CTL_PKTFLAG_TOSSED_BYWLC */
"TX_PKT_FATE_SENT", /* 4: WLFC_CTL_PKTFLAG_DISCARD_NOACK */
"TX_PKT_FATE_FW_DROP_OTHER", /* 5: WLFC_CTL_PKTFLAG_SUPPRESS_ACKED */
"TX_PKT_FATE_FW_DROP_EXPTIME", /* 6: WLFC_CTL_PKTFLAG_EXPIRED */
"TX_PKT_FATE_FW_DROP_OTHER", /* 7: WLFC_CTL_PKTFLAG_DROPPED */
"TX_PKT_FATE_FW_PKT_FREE", /* 8: WLFC_CTL_PKTFLAG_MKTFREE */
#if defined(DHD_DNS_DUMP) || defined(DHD_ARP_DUMP) || defined(DHD_ICMP_DUMP) || \
defined(DHD_DHCP_DUMP) || defined(DHD_8021X_DUMP) || defined(DHD_PKTDUMP_ROAM)
#define DHD_PKTFATE_STR_MAX 30
#define DHD_PKTFATE_EX_STR_MAX 10
typedef struct dhd_tx_pktfate_entry {
const char reason[DHD_PKTFATE_STR_MAX];
const char ex[DHD_PKTFATE_EX_STR_MAX];
} dhd_tx_pktfate_entry_t;
static dhd_tx_pktfate_entry_t tx_pktfate[] = {
{"TX_PKT_FATE_ACKED", "ACK"}, /* 0: WLFC_CTL_PKTFLAG_DISCARD */
{"TX_PKT_FATE_FW_D11SUPPRESS", "TX_FAIL"}, /* 1: WLFC_CTL_PKTFLAG_D11SUPPRESS */
{"TX_PKT_FATE_FW_WLSUPPRESS", "TX_FAIL"}, /* 2: WLFC_CTL_PKTFLAG_WLSUPPRESS */
{"TX_PKT_FATE_FW_TOSSED_BYWLC", "TX_FAIL"}, /* 3: WLFC_CTL_PKTFLAG_TOSSED_BYWLC */
{"TX_PKT_FATE_SENT_NOACK", "NO_ACK"}, /* 4: WLFC_CTL_PKTFLAG_DISCARD_NOACK */
{"TX_PKT_FATE_FW_SUPPRESS_ACKED", "TX_FAIL"}, /* 5: WLFC_CTL_PKTFLAG_SUPPRESS_ACKED */
{"TX_PKT_FATE_FW_DROP_EXPTIME", "TX_FAIL"}, /* 6: WLFC_CTL_PKTFLAG_EXPIRED */
{"TX_PKT_FATE_FW_DROP_OTHER", "TX_FAIL"}, /* 7: WLFC_CTL_PKTFLAG_DROPPED */
{"TX_PKT_FATE_FW_PKT_FREE", "TX_FAIL"}, /* 8: WLFC_CTL_PKTFLAG_MKTFREE */
{"TX_PKT_FATE_FW_MAX_SUP_RETR", "TX_FAIL"}, /* 9: WLFC_CTL_PKTFLAG_MAX_SUP_RETR */
{"TX_PKT_FATE_FW_FORCED_EXPIRED", "TX_FAIL"}, /* 10: WLFC_CTL_PKTFLAG_FORCED_EXPIRED */
};
#define DBGREPLAY " Replay Counter: %02x%02x%02x%02x%02x%02x%02x%02x"
@ -191,10 +208,17 @@ static const char tx_pktfate[][30] = {
((const eapol_key_hdr_t *)(key))->replay[7]
#define TXFATE_FMT " TX_PKTHASH:0x%X TX_PKT_FATE:%s"
#define TX_PKTHASH(pkthash) ((pkthash) ? (*pkthash) : (0))
#define TX_FATE_STR(fate) (((*fate) <= (WLFC_CTL_PKTFLAG_MKTFREE)) ? \
(tx_pktfate[(*fate)]) : "TX_PKT_FATE_FW_DROP_OTHER")
#define TX_FATE_STR(fate) (((*fate) <= (WLFC_CTL_PKTFLAG_FORCED_EXPIRED)) ? \
(tx_pktfate[(*fate)].reason) : "TX_PKT_FATE_UNKNOWN")
#define TX_FATE_STR_EX(fate) (((*fate) <= (WLFC_CTL_PKTFLAG_FORCED_EXPIRED)) ? \
(tx_pktfate[(*fate)].ex) : NULL)
#define TX_FATE(fate) ((fate) ? (TX_FATE_STR(fate)) : "N/A")
#define TX_FATE_EX(fate) ((fate) ? (TX_FATE_STR_EX(fate)) : NULL)
#define TX_FATE_ACKED(fate) ((fate) ? ((*fate) == (WLFC_CTL_PKTFLAG_DISCARD)) : (0))
#endif /*
* DHD_DNS_DUMP || DHD_ARP_DUMP || DHD_ICMP_DUMP ||
* DHD_DHCP_DUMP || DHD_8021X_DUMP || DHD_PKTDUMP_ROAM
*/
#define EAP_PRINT(x, args...) \
do { \
@ -1075,6 +1099,7 @@ typedef struct bootp_fmt {
static const uint8 bootp_magic_cookie[4] = { 99, 130, 83, 99 };
#ifdef DHD_DHCP_DUMP
#if defined(DHD_DHCP_DUMP) || defined(WL_CFGVENDOR_CUST_ADVLOG)
#define DHCP_MSGTYPE_DISCOVER 1
#define DHCP_MSGTYPE_OFFER 2
#define DHCP_MSGTYPE_REQUEST 3
@ -1083,6 +1108,7 @@ static const uint8 bootp_magic_cookie[4] = { 99, 130, 83, 99 };
#define DHCP_MSGTYPE_NAK 6
#define DHCP_MSGTYPE_RELEASE 7
#define DHCP_MSGTYPE_INFORM 8
#endif /* DHD_DHCP_DUMP || WL_CFGVENDOR_CUST_ADVLOG */
#define DHCP_PRINT(str) \
do { \
@ -1098,15 +1124,26 @@ static const uint8 bootp_magic_cookie[4] = { 99, 130, 83, 99 };
} \
} while (0)
static char dhcp_ops[][10] = {
#define MAX_DHCP_OPS_STR 3
#define MAX_DHCP_TYPES_STR 9
static char dhcp_ops[MAX_DHCP_OPS_STR][10] = {
"NA", "REQUEST", "REPLY"
};
static char dhcp_types[][10] = {
static char dhcp_types[MAX_DHCP_TYPES_STR][10] = {
"NA", "DISCOVER", "OFFER", "REQUEST", "DECLINE", "ACK", "NAK", "RELEASE", "INFORM"
};
#define DHCP_OPS_STR(ops) ((ops < MAX_DHCP_OPS_STR) ? \
(dhcp_ops[ops]) : "UNKNOWN_DHCP_OPS")
#define DHCP_TYPES_STR(type) ((type < MAX_DHCP_TYPES_STR) ? \
(dhcp_types[type]) : "UNKNOWN_DHCP_TYPE")
#ifdef DHD_STATUS_LOGGING
static const int dhcp_types_stat[9] = {
#define MAX_DHCP_TYPES_STAT 9
#define DHCP_TYPES_STAT(type) ((type < MAX_DHCP_TYPES_STAT) ? \
(dhcp_types_stat[type]) : ST(INVALID))
static const int dhcp_types_stat[MAX_DHCP_TYPES_STAT] = {
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)
@ -1120,7 +1157,8 @@ dhd_dhcp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
bootp_fmt_t *b = (bootp_fmt_t *)&pktdata[ETHER_HDR_LEN];
struct ipv4_hdr *iph = &b->iph;
uint8 *ptr, *opt, *end = (uint8 *) b + ntohs(b->iph.tot_len);
int dhcp_type = 0, len, opt_len;
uint8 dhcp_type = 0;
int len, opt_len;
char *ifname = NULL, *typestr = NULL, *opstr = NULL;
bool cond;
char sabuf[20]="", dabuf[20]="";
@ -1156,9 +1194,9 @@ dhd_dhcp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
if (*opt == DHCP_OPT_MSGTYPE) {
if (opt[1]) {
dhcp_type = opt[2];
typestr = dhcp_types[dhcp_type];
opstr = dhcp_ops[b->op];
DHD_STATLOG_DATA(dhdp, dhcp_types_stat[dhcp_type],
typestr = DHCP_TYPES_STR(dhcp_type);
opstr = DHCP_OPS_STR(b->op);
DHD_STATLOG_DATA(dhdp, DHCP_TYPES_STAT(dhcp_type),
ifidx, tx, cond);
DHCP_PRINT("DHCP");
break;
@ -1186,6 +1224,23 @@ dhd_check_icmp(uint8 *pktdata)
return TRUE;
}
bool
dhd_check_icmpv6(uint8 *pktdata, uint32 plen)
{
uint8 *pkt = (uint8 *)&pktdata[ETHER_HDR_LEN];
struct ipv6_hdr *ip6h = (struct ipv6_hdr *)pkt;
if (IPV6_PROT(ip6h) != IP_PROT_ICMP6) {
return FALSE;
}
/* check header length */
if (plen <= IPV6_MIN_HLEN) {
return FALSE;
}
return TRUE;
}
#ifdef DHD_ICMP_DUMP
#define ICMP_TYPE_DEST_UNREACH 3
#define ICMP_ECHO_SEQ_OFFSET 6
@ -1577,6 +1632,222 @@ dhd_trx_pkt_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, uint32 pktlen, bool
}
#endif /* DHD_RX_DUMP */
#ifdef WL_CFGVENDOR_CUST_ADVLOG
typedef struct dhd_advlog_arr_map_entry {
uint32 avglog_type;
dhd_advlog_map_entry_t *arr;
uint32 arr_len;
} dhd_advlog_arr_map_entry_t;
typedef enum dhd_advlog_type {
DHD_ADVLOG_DHCP_TX = 0,
DHD_ADVLOG_DHCP_RX = 1,
DHD_ADVLOG_EAP = 2,
DHD_ADVLOG_EAPOL = 3,
DHD_ADVLOG_LAST = 4
} dhd_advlog_type_t;
static dhd_advlog_map_entry_t eap_type_map[] = {
{EAP_TYPE_IDENT, "Identity"},
{EAP_TYPE_TLS, "TLS"},
{EAP_TYPE_LEAP, "LEAP"},
{EAP_TYPE_TTLS, "TTLS"},
{EAP_TYPE_AKA, "AKA"},
{EAP_TYPE_PEAP, "PEAP"},
{EAP_TYPE_FAST, "FAST"},
{EAP_TYPE_PSK, "PSK"},
{EAP_TYPE_AKAP, "AKAP"},
};
static dhd_advlog_map_entry_t eap_advlog_map[] = {
{EAP_CODE_REQUEST, "[EAP] REQ type=%s len=%d"},
{EAP_CODE_RESPONSE, "[EAP] RESP type=%s len=%d tx_status=%s"},
{EAP_CODE_SUCCESS, "[EAP] SUCC"},
{EAP_CODE_FAILURE, "[EAP] FAIL"},
};
static dhd_advlog_map_entry_t dhcp_tx_advlog_map[] = {
{DHCP_MSGTYPE_DISCOVER, "[DHCP] DISCOVER tx_status=%s"},
{DHCP_MSGTYPE_REQUEST, "[DHCP] REQUEST tx_status=%s"},
};
static dhd_advlog_map_entry_t dhcp_rx_advlog_map[] = {
{DHCP_MSGTYPE_OFFER, "[DHCP] OFFER"},
{DHCP_MSGTYPE_ACK, "[DHCP] ACK"},
{DHCP_MSGTYPE_NAK, "[DHCP] NAK"},
};
static dhd_advlog_map_entry_t eapol_advlog_map[] = {
{EAPOL_4WAY_M1, "[EAPOL] 4WAY M1"},
{EAPOL_4WAY_M2, "[EAPOL] 4WAY M2 tx_status=%s"},
{EAPOL_4WAY_M3, "[EAPOL] 4WAY M3"},
{EAPOL_4WAY_M4, "[EAPOL] 4WAY M4 tx_status=%s"},
{EAPOL_GROUPKEY_M1, "[EAPOL] GTK M1"},
{EAPOL_GROUPKEY_M2, "[EAPOL] GTK M2 tx_status=%s"},
};
static dhd_advlog_arr_map_entry_t advlog_map_arr[] = {
{DHD_ADVLOG_DHCP_TX, dhcp_tx_advlog_map, ARRAY_SIZE(dhcp_tx_advlog_map)},
{DHD_ADVLOG_DHCP_RX, dhcp_rx_advlog_map, ARRAY_SIZE(dhcp_rx_advlog_map)},
{DHD_ADVLOG_EAP, eap_advlog_map, ARRAY_SIZE(eap_advlog_map)},
{DHD_ADVLOG_EAPOL, eapol_advlog_map, ARRAY_SIZE(eapol_advlog_map)},
};
const char* get_advlog_val(dhd_advlog_map_entry_t *arr, uint32 arr_len, int tag)
{
int i;
for (i = 0; i < arr_len; i++) {
if (tag == arr[i].key) {
return arr[i].val;
}
}
return NULL;
}
static int get_dhcp_type(uint8 *pktdata)
{
bootp_fmt_t *b = (bootp_fmt_t *)&pktdata[ETHER_HDR_LEN];
uint8 *ptr, *opt, *end = (uint8 *) b + ntohs(b->iph.tot_len);
int dhcp_type = 0, len, opt_len;
len = ntohs(b->udph.len) - sizeof(struct bcmudp_hdr);
opt_len = len - (sizeof(*b) - sizeof(struct ipv4_hdr) -
sizeof(struct bcmudp_hdr) - sizeof(b->options));
/* parse bootp options */
if (opt_len >= BOOTP_MAGIC_COOKIE_LEN &&
!memcmp(b->options, bootp_magic_cookie, BOOTP_MAGIC_COOKIE_LEN)) {
ptr = &b->options[BOOTP_MAGIC_COOKIE_LEN];
while (ptr < end && *ptr != 0xff) {
opt = ptr++;
if (*opt == 0) {
continue;
}
ptr += *ptr + 1;
if (ptr >= end) {
break;
}
if (*opt == DHCP_OPT_MSGTYPE) {
if (opt[1]) {
dhcp_type = opt[2];
return dhcp_type;
}
}
}
}
return BCME_ERROR;
}
static int dhd_send_supp(uint32 avglog_type, int arg_tag, int arg_type, uint32 pktlen,
bool tx, uint16 *pktfate)
{
const char *type_str = NULL;
const char *fmt_str = NULL;
dhd_advlog_map_entry_t *fmt_arr;
uint32 fmt_arr_len;
if (avglog_type >= DHD_ADVLOG_LAST) {
DHD_ERROR(("%s incorrect array index type:%d tag:%d\n",
__func__, avglog_type, arg_tag));
return BCME_ERROR;
}
if ((arg_type && !pktlen) || (!arg_type && pktlen)) {
DHD_ERROR(("%s Not expected value pair type:%d tag:%d pktlen:%u\n",
__func__, avglog_type, arg_tag, pktlen));
return BCME_ERROR;
}
if (arg_tag <= 0) {
DHD_ERROR(("%s Invalid tag number type:%d tag:%d\n",
__func__, avglog_type, arg_tag));
return BCME_ERROR;
}
/* Get the format string corresponding to the type */
fmt_arr = advlog_map_arr[avglog_type].arr;
fmt_arr_len = advlog_map_arr[avglog_type].arr_len;
fmt_str = get_advlog_val(fmt_arr, fmt_arr_len, arg_tag);
if (!fmt_str) {
DHD_ERROR(("%s map arr not found type:%d tag:%d\n",
__func__, avglog_type, arg_tag));
return BCME_ERROR;
}
/* EAP REQ/RESP */
if (arg_type && pktlen) {
/* Get Identity/PEAP/FAST/etc string */
type_str = get_advlog_val(eap_type_map, ARRAY_SIZE(eap_type_map), arg_type);
if (!type_str) {
DHD_ERROR(("%s type string not found type:%d tag:%d\n",
__func__, avglog_type, arg_tag));
return BCME_ERROR;
}
if (tx && pktfate) {
/* EAP RESP */
SUPP_ADVLOG((fmt_str, type_str, pktlen, TX_FATE_EX(pktfate)));
} else if (!tx) {
/* EAP REQ */
SUPP_ADVLOG((fmt_str, type_str, pktlen));
}
} else {
if (tx && pktfate) {
/* EAPOL M2/M4, GTK M2, DHCP DISC/REQ */
SUPP_ADVLOG((fmt_str, TX_FATE_EX(pktfate)));
} else if (!tx) {
/* EAPOL M1/M3, GTK M1, DHCP OFFER/ACK/NAK, EAP SUCC/FAIL */
SUPP_ADVLOG((fmt_str));
}
}
return BCME_OK;
}
void dhd_send_supp_dhcp(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx, uint16 *pktfate)
{
uint32 advlog_type;
/* Advanced Logging supports only STA mode */
if (!DHD_IF_ROLE_STA(dhdp, ifidx)) {
return;
}
if (tx) {
advlog_type = DHD_ADVLOG_DHCP_TX;
} else {
advlog_type = DHD_ADVLOG_DHCP_RX;
}
dhd_send_supp(advlog_type, get_dhcp_type(pktdata), 0, 0, tx, pktfate);
}
void dhd_send_supp_eap(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, uint32 pktlen,
bool tx, uint16 *pktfate)
{
eapol_header_t *eapol_hdr;
eap_header_fmt_t *eap_hdr;
uint16 len = 0;
uint8 type = 0;
/* Advanced Logging supports only STA mode */
if (!DHD_IF_ROLE_STA(dhdp, ifidx)) {
return;
}
eapol_hdr = (eapol_header_t *)pktdata;
eap_hdr = (eap_header_fmt_t *)(eapol_hdr->body);
if (eapol_hdr->type == EAP_PACKET) {
/* EAP SUCC/FAIL has no arg to print */
if (eap_hdr->code != EAP_CODE_SUCCESS &&
eap_hdr->code != EAP_CODE_FAILURE) {
type = eap_hdr->type;
len = ntoh16(eap_hdr->len);
}
dhd_send_supp(DHD_ADVLOG_EAP, eap_hdr->code, type, len, tx, pktfate);
} else if (eapol_hdr->type == EAPOL_KEY) {
dhd_send_supp(DHD_ADVLOG_EAPOL, dhd_is_4way_msg(pktdata),
0, 0, tx, pktfate);
}
}
#endif /* WL_CFGVENDOR_CUST_ADVLOG */
#ifdef BCMPCIE
static bool
dhd_is_eapol_pkt(dhd_pub_t *dhd, uint8 *pktdata, uint32 pktlen)

View File

@ -1,7 +1,7 @@
/*
* Header file for the Packet dump helper functions
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -51,11 +51,31 @@ 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
PKT_TYPE_ICMPV6 = 3,
PKT_TYPE_DNS = 4,
PKT_TYPE_ARP = 5,
PKT_TYPE_EAP = 6,
PKT_TYPE_IGMP = 7
};
#ifdef WL_CFGVENDOR_CUST_ADVLOG
#define DHD_ADVLOG_FMT_MAX 256u
typedef struct dhd_advlog_map_entry {
uint32 key;
const char val[DHD_ADVLOG_FMT_MAX];
} dhd_advlog_map_entry_t;
extern void dhd_send_supp_dhcp(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata,
bool tx, uint16 *pktfate);
extern void dhd_send_supp_eap(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, uint32 pktlen,
bool tx, uint16 *pktfate);
#else
static INLINE void dhd_send_supp_dhcp(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata,
bool tx, uint16 *pktfate) {}
static INLINE void dhd_send_supp_eap(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata,
uint32 pktlen, bool tx, uint16 *pktfate) {}
#endif /* WL_CFGVENDOR_CUST_ADVLOG */
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);
@ -131,5 +151,6 @@ 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_icmpv6(uint8 *pktdata, uint32 plen);
extern bool dhd_check_dns(uint8 *pktdata);
#endif /* __DHD_LINUX_PKTDUMP_H_ */

View File

@ -1,7 +1,7 @@
/*
* Linux platform device for DHD WLAN adapter
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -37,20 +37,16 @@
#if defined(OEM_ANDROID)
#include <wl_android.h>
#endif
#if defined(CONFIG_WIFI_CONTROL_FUNC) || defined(CUSTOMER_HW4)
#include <linux/wlan_plat.h>
#else
#include <dhd_plat.h>
#if defined(CONFIG_WIFI_CONTROL_FUNC)
#include <linux/wlan_plat.h>
#endif /* CONFIG_WIFI_CONTROL_FUNC */
#ifdef BCMDBUS
#include <dbus.h>
#endif
#ifdef CONFIG_DTS
#include<linux/regulator/consumer.h>
#include<linux/of_gpio.h>
#endif /* CONFIG_DTS */
#if defined(CUSTOMER_HW)
#if defined(CUSTOMER_HW) || defined(BCMDHD_PLATDEV)
extern int dhd_wlan_init_plat_data(wifi_adapter_info_t *adapter);
extern void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter);
#endif /* CUSTOMER_HW */
@ -59,6 +55,11 @@ 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"
#if defined(SUPPORT_MULTIPLE_BOARD_REVISION)
#include <linux/of.h>
extern char* dhd_get_device_dt_name(void);
#endif /* SUPPORT_MULTIPLE_BOARD_REVISION */
#ifdef DHD_WIFI_SHUTDOWN
extern void wifi_plat_dev_drv_shutdown(struct platform_device *pdev);
#endif
@ -88,7 +89,7 @@ static bool dts_enabled = FALSE;
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
struct resource dhd_wlan_resources = {0};
struct wifi_platform_data dhd_wlan_control = {0};
extern struct wifi_platform_data dhd_wlan_control;
#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
@ -99,14 +100,15 @@ static int dhd_wifi_platform_load(void);
extern void* wl_cfg80211_get_dhdp(struct net_device *dev);
#ifdef BCMDHD_MODULAR
// modify for compatibility
#if defined(BCMDHD_MODULAR) && defined(BOARD_MODULAR_INIT)
//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 */
#endif /* defined(BCMDHD_MODULAR) && defined(BOARD_MODULAR_INIT) */
#ifdef ENABLE_4335BT_WAR
extern int bcm_bt_lock(int cookie);
@ -118,6 +120,18 @@ static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "Wi
extern bool check_bcm4335_rev(void);
#endif /* BCM4335_XTAL_WAR */
#if defined(CONFIG_X86)
#define PCIE_RC_VENDOR_ID 0x8086
#define PCIE_RC_DEVICE_ID 0x9c1a
#elif defined(CONFIG_ARCH_TEGRA)
#define PCIE_RC_VENDOR_ID 0x14e4
#define PCIE_RC_DEVICE_ID 0x4347
#else /* CONFIG_ARCH_TEGRA */
/* Dummy defn */
#define PCIE_RC_VENDOR_ID 0xffff
#define PCIE_RC_DEVICE_ID 0xffff
#endif /* CONFIG_X86 */
wifi_adapter_info_t* dhd_wifi_platform_attach_adapter(uint32 bus_type,
uint32 bus_num, uint32 slot_num, unsigned long status)
{
@ -131,7 +145,7 @@ wifi_adapter_info_t* dhd_wifi_platform_attach_adapter(uint32 bus_type,
if ((adapter->bus_type == -1 || adapter->bus_type == bus_type) &&
(adapter->bus_num == -1 || adapter->bus_num == bus_num) &&
(adapter->slot_num == -1 || adapter->slot_num == slot_num)
#if defined(ENABLE_INSMOD_NO_FW_LOAD)
#if defined(ENABLE_INSMOD_NO_FW_LOAD) && !defined(ENABLE_INSMOD_NO_POWER_OFF)
&& (wifi_chk_adapter_status(adapter, status))
#endif
) {
@ -161,6 +175,10 @@ wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_n
return NULL;
}
#if defined(CONFIG_WIFI_CONTROL_FUNC) && defined(CONFIG_DHD_USE_STATIC_BUF)
extern void *dhd_wlan_mem_prealloc(int section, unsigned long size);
#endif /* CONFIG_WIFI_CONTROL_FUNC && CONFIG_DHD_USE_STATIC_BUF */
void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size)
{
void *alloc_ptr = NULL;
@ -170,10 +188,14 @@ void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned
return NULL;
plat_data = adapter->wifi_plat_data;
if (plat_data->mem_prealloc) {
#ifdef BCMDHD_MDRIVER
#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER)
alloc_ptr = plat_data->mem_prealloc(adapter->bus_type, adapter->index, section, size);
#else
#if defined(CONFIG_WIFI_CONTROL_FUNC) && defined(CONFIG_DHD_USE_STATIC_BUF)
alloc_ptr = dhd_wlan_mem_prealloc(section, size);
#else
alloc_ptr = plat_data->mem_prealloc(section, size);
#endif
#endif
if (alloc_ptr) {
DHD_INFO(("success alloc section %d\n", section));
@ -260,11 +282,17 @@ int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long
}
#endif /* ENABLE_4335BT_WAR */
#ifdef CONFIG_WIFI_CONTROL_FUNC
err = plat_data->set_power(on);
#else
err = plat_data->set_power(on, adapter);
#endif
}
if (msec && !err)
if (msec && !err) {
OSL_SLEEP(msec);
DHD_ERROR(("%s = %d, sleep done: %lu msec\n", __FUNCTION__, on, msec));
}
if (on && !err)
is_power_on = TRUE;
@ -310,7 +338,11 @@ 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 CONFIG_WIFI_CONTROL_FUNC
return plat_data->get_mac_addr(buf);
#else
return plat_data->get_mac_addr(buf, ifidx);
#endif
}
return -EOPNOTSUPP;
}
@ -381,6 +413,14 @@ static int wifi_plat_dev_drv_probe(struct platform_device *pdev)
adapter->wifi_plat_data = (void *)&dhd_wlan_control;
#endif
#ifdef BCMDHD_PLATDEV
adapter->pdev = pdev;
wifi_plat_dev_probe_ret = dhd_wlan_init_plat_data(adapter);
if (!wifi_plat_dev_probe_ret)
wifi_plat_dev_probe_ret = dhd_wifi_platform_load();
return wifi_plat_dev_probe_ret;
#endif
resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq");
if (resource == NULL)
resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq");
@ -452,6 +492,9 @@ static int wifi_plat_dev_drv_remove(struct platform_device *pdev)
#ifdef CONFIG_DTS
regulator_put(wifi_regulator);
#endif /* CONFIG_DTS */
#ifdef BCMDHD_PLATDEV
dhd_wlan_deinit_plat_data(adapter);
#endif
return 0;
}
@ -518,9 +561,10 @@ static int wifi_platdev_match(struct device *dev, const void *data)
static int wifi_platdev_match(struct device *dev, void *data)
#endif /* LINUX_VER >= 5.3.0 */
{
char *name = (char*)data;
char *name = NULL;
const struct platform_device *pdev;
GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
name = (char*)data;
pdev = to_platform_device(dev);
GCC_DIAGNOSTIC_POP();
@ -544,12 +588,16 @@ 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();
// modify for compaibility
#if defined(BCMDHD_MODULAR) && defined(BOARD_MODULAR_INIT)
// if ((err = dhd_wlan_init())) {
// DHD_ERROR(("%s: dhd_wlan_init() failed(%d)\n", __FUNCTION__, err));
// return err;
// }
#ifdef WBRC
wbrc_init();
#endif /* WBRC */
#endif /* BCMDHD_MODULAR */
#endif /* defined(BCMDHD_MODULAR) && defined(BOARD_MODULAR_INIT) */
#if !defined(CONFIG_DTS) && !defined(CUSTOMER_HW)
if (!dts_enabled) {
@ -569,16 +617,7 @@ static int wifi_ctrlfunc_register_drv(void)
return -ENOMEM;
}
adapter->name = "DHD generic adapter";
adapter->index = -1;
#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER)
#ifdef BCMSDIO
adapter->index = 0;
#elif defined(BCMPCIE)
adapter->index = 1;
#elif defined(BCMDBUS)
adapter->index = 2;
#endif
#endif
adapter->bus_type = -1;
adapter->bus_num = -1;
adapter->slot_num = -1;
@ -586,6 +625,11 @@ static int wifi_ctrlfunc_register_drv(void)
is_power_on = FALSE;
wifi_plat_dev_probe_ret = 0;
dhd_wifi_platdata = kzalloc(sizeof(bcmdhd_wifi_platdata_t), GFP_KERNEL);
if (dhd_wifi_platdata == NULL) {
DHD_ERROR(("%s:dhd_wifi_platdata alloc failed", __FUNCTION__));
kfree(adapter);
return -ENOMEM;
}
dhd_wifi_platdata->num_adapters = 1;
dhd_wifi_platdata->adapters = adapter;
init_waitqueue_head(&adapter->status_event);
@ -657,6 +701,11 @@ void wifi_ctrlfunc_unregister_drv(void)
if (dev2)
platform_driver_unregister(&wifi_platform_dev_driver_legacy);
#endif
if (!dhd_wifi_platdata) {
goto done;
}
if (dts_enabled) {
adapter = &dhd_wifi_platdata->adapters[0];
if (is_power_on) {
@ -664,24 +713,30 @@ void wifi_ctrlfunc_unregister_drv(void)
}
wifi_platform_bus_enumerate(adapter, FALSE);
}
#ifdef BCMDHD_MODULAR
// modify for compaibility
#if defined(BCMDHD_MODULAR) && defined(BOARD_MODULAR_INIT)
// dhd_wlan_deinit();
osl_static_mem_deinit(NULL, NULL);
#ifdef WBRC
wbrc_exit();
#endif /* WBRC */
#endif /* BCMDHD_MODULAR */
#endif /* defined(BCMDHD_MODULAR) && defined(BOARD_MODULAR_INIT) */
#endif /* !defined(CONFIG_DTS) */
#if defined(CUSTOMER_HW)
dhd_wlan_deinit_plat_data(adapter);
#endif
kfree(dhd_wifi_platdata->adapters);
dhd_wifi_platdata->adapters = NULL;
dhd_wifi_platdata->num_adapters = 0;
kfree(dhd_wifi_platdata);
dhd_wifi_platdata = NULL;
done:
if (dhd_wifi_platdata && dhd_wifi_platdata->adapters) {
kfree(dhd_wifi_platdata->adapters);
dhd_wifi_platdata->adapters = NULL;
dhd_wifi_platdata->num_adapters = 0;
}
if (dhd_wifi_platdata) {
kfree(dhd_wifi_platdata);
dhd_wifi_platdata = NULL;
}
}
#ifndef CUSTOMER_HW
@ -759,25 +814,31 @@ int dhd_wifi_platform_register_drv(void)
#ifdef BCMPCIE
static int dhd_wifi_platform_load_pcie(void)
{
int err = 0;
int i;
int err;
int retry;
wifi_adapter_info_t *adapter;
BCM_REFERENCE(i);
BCM_REFERENCE(adapter);
if (dhd_wifi_platdata == NULL) {
/* XXX For x86 Bringup PC or BRIX */
err = dhd_bus_register();
} else {
if (dhd_wifi_platdata) {
/* enumerate PCIe RC */
for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
adapter = &dhd_wifi_platdata->adapters[i];
err = wifi_platform_bus_enumerate(adapter, TRUE);
if (err) {
DHD_ERROR(("failed to enumerate bus %s err=%d",
adapter->name, err));
return err;
}
}
#ifdef DHD_SUPPORT_HDM
if (dhd_download_fw_on_driverload || hdm_trigger_init) {
if (dhd_download_fw_on_driverload || hdm_trigger_init)
#else
if (dhd_download_fw_on_driverload) {
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;
retry = POWERUP_MAX_RETRY;
adapter = &dhd_wifi_platdata->adapters[i];
DHD_ERROR(("Power-up adapter '%s'\n", adapter->name));
@ -798,17 +859,17 @@ static int dhd_wifi_platform_load_pcie(void)
wifi_platform_set_power(adapter,
FALSE, WIFI_TURNOFF_DELAY);
continue;
}
err = wifi_platform_bus_enumerate(adapter, TRUE);
if (err) {
DHD_ERROR(("failed to enumerate bus %s, "
"%d retry left\n",
adapter->name, retry));
wifi_platform_set_power(adapter, FALSE,
WIFI_TURNOFF_DELAY);
} else {
err = wifi_platform_bus_enumerate(adapter, TRUE);
if (err) {
DHD_ERROR(("failed to enumerate bus %s, "
"%d retry left\n",
adapter->name, retry));
wifi_platform_set_power(adapter, FALSE,
WIFI_TURNOFF_DELAY);
} else {
break;
}
break;
}
} while (retry--);
@ -819,19 +880,18 @@ static int dhd_wifi_platform_load_pcie(void)
}
}
}
}
err = dhd_bus_register();
if (err) {
DHD_ERROR(("%s: pcie_register_driver failed\n", __FUNCTION__));
if (dhd_download_fw_on_driverload) {
/* power down all adapters */
for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
adapter = &dhd_wifi_platdata->adapters[i];
wifi_platform_bus_enumerate(adapter, FALSE);
wifi_platform_set_power(adapter,
FALSE, WIFI_TURNOFF_DELAY);
}
err = dhd_bus_register();
if (err) {
DHD_ERROR(("%s: dhd_bus_register failed err=%d\n", __FUNCTION__, err));
if (dhd_wifi_platdata && dhd_download_fw_on_driverload) {
/* power down all adapters */
for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
adapter = &dhd_wifi_platdata->adapters[i];
wifi_platform_bus_enumerate(adapter, FALSE);
wifi_platform_set_power(adapter,
FALSE, WIFI_TURNOFF_DELAY);
}
}
}
@ -896,7 +956,9 @@ static int dhd_wifi_platform_load_sdio(void)
for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) {
bool chip_up = FALSE;
int retry = POWERUP_MAX_RETRY;
#ifndef DHD_INSMOD_NOWAIT
struct semaphore dhd_chipup_sem;
#endif
adapter = &dhd_wifi_platdata->adapters[i];
@ -907,6 +969,18 @@ static int dhd_wifi_platform_load_sdio(void)
adapter->bus_type, adapter->bus_num, adapter->slot_num));
do {
#ifdef DHD_INSMOD_NOWAIT
err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY);
if (err) {
DHD_ERROR(("%s: wifi pwr on error ! \n", __FUNCTION__));
wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY);
continue;
} else {
wifi_platform_bus_enumerate(adapter, TRUE);
chip_up = TRUE;
break;
}
#else
sema_init(&dhd_chipup_sem, 0);
err = dhd_bus_reg_sdio_notify(&dhd_chipup_sem);
if (err) {
@ -935,6 +1009,7 @@ static int dhd_wifi_platform_load_sdio(void)
dhd_bus_unreg_sdio_notify();
wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY);
wifi_platform_bus_enumerate(adapter, FALSE);
#endif
} while (retry--);
if (!chip_up) {
@ -951,6 +1026,7 @@ static int dhd_wifi_platform_load_sdio(void)
goto fail;
}
#ifndef DHD_INSMOD_NOWAIT
/*
* Wait till MMC sdio_register_driver callback called and made driver attach.
* It's needed to make sync up exit from dhd insmod and
@ -962,6 +1038,7 @@ static int dhd_wifi_platform_load_sdio(void)
dhd_bus_unregister();
goto fail;
}
#endif
return err;
@ -994,16 +1071,15 @@ static int dhd_wifi_platform_load_usb(void)
wifi_adapter_info_t *adapter;
s32 timeout = -1;
int i;
enum wifi_adapter_status wait_status;
#endif
#if !defined(DHD_PRELOAD)
#if !defined(DHD_PRELOAD) && !defined(ENABLE_INSMOD_NO_POWER_OFF)
/* 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));
DHD_ERROR(("failed to wifi_platform_set_power off %s\n", adapter->name));
goto exit;
}
}
@ -1030,12 +1106,8 @@ static int dhd_wifi_platform_load_usb(void)
DHD_ERROR(("failed to wifi_platform_set_power on %s\n", adapter->name));
goto fail;
}
if (dhd_download_fw_on_driverload)
wait_status = WIFI_STATUS_ATTACH;
else
wait_status = WIFI_STATUS_DETTACH;
timeout = wait_event_interruptible_timeout(adapter->status_event,
wifi_get_adapter_status(adapter, wait_status),
wifi_get_adapter_status(adapter, WIFI_STATUS_NET_ATTACHED),
msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT));
if (timeout <= 0) {
err = -1;
@ -1095,3 +1167,127 @@ end:
return err;
}
#if defined(SUPPORT_MULTIPLE_BOARD_REVISION)
void
concate_custom_board_revision(char *nv_path)
{
uint32 board_revision = 0;
struct device_node *root_node = NULL;
char* wlan_node = NULL;
if (!nv_path) {
DHD_ERROR(("nv_path is null\n"));
return;
}
wlan_node = dhd_get_device_dt_name();
if (!wlan_node) {
DHD_ERROR(("Failed to dt name\n"));
return;
}
root_node = of_find_compatible_node(NULL, NULL, wlan_node);
if (!root_node) {
DHD_ERROR(("Failed to get device node\n"));
return;
}
if (of_property_read_u32(root_node, "nvram-ES", &board_revision)) {
DHD_ERROR(("No board revision property in dtsi\n"));
return;
}
DHD_INFO(("Board revision:%d\n", board_revision));
if (board_revision == 1) {
strcat(nv_path, "_ES10");
DHD_INFO(("Mached Board revision ES10: nvram name:%s\n", nv_path));
}
}
#endif /* SUPPORT_MULTIPLE_BOARD_REVISION */
/* Weak functions that can be overridden in Platform specific implementation */
char* __attribute__ ((weak)) dhd_get_device_dt_name(void)
{
return NULL;
}
uint32 __attribute__ ((weak)) dhd_plat_get_info_size(void)
{
return 0;
}
int __attribute__ ((weak)) dhd_plat_pcie_register_event(void *plat_info,
struct pci_dev *pdev, dhd_pcie_event_cb_t pfn)
{
return 0;
}
void __attribute__ ((weak)) dhd_plat_pcie_deregister_event(void *plat_info)
{
return;
}
void __attribute__ ((weak)) dhd_plat_l1ss_ctrl(bool ctrl)
{
return;
}
void __attribute__ ((weak)) dhd_plat_l1_exit_io(void)
{
return;
}
void __attribute__ ((weak)) dhd_plat_l1_exit(void)
{
return;
}
void __attribute__ ((weak)) dhd_plat_report_bh_sched(void *plat_info, int resched)
{
return;
}
int __attribute__ ((weak)) dhd_plat_pcie_suspend(void *plat_info)
{
return 0;
}
int __attribute__ ((weak)) dhd_plat_pcie_resume(void *plat_info)
{
return 0;
}
void __attribute__ ((weak)) dhd_plat_pcie_register_dump(void *plat_info)
{
return;
}
void __attribute__ ((weak)) dhd_plat_pin_dbg_show(void *plat_info)
{
return;
}
uint32 __attribute__ ((weak)) dhd_plat_get_rc_vendor_id(void)
{
return PCIE_RC_VENDOR_ID;
}
uint32 __attribute__ ((weak)) dhd_plat_get_rc_device_id(void)
{
return PCIE_RC_DEVICE_ID;
}
uint16 __attribute__ ((weak)) dhd_plat_align_rxbuf_size(uint16 rxbufpost_sz)
{
return rxbufpost_sz;
}
int
__attribute__ ((weak)) dhd_get_platform_naming_for_nvram_clmblob_file(download_type_t component,
char *file_name)
{
return BCME_ERROR;
}

View File

@ -1,7 +1,7 @@
/*
* DHD Linux header file - contains private structure definition of the Linux specific layer
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -41,7 +41,6 @@
#ifdef CONFIG_HAS_WAKELOCK
#include <linux/pm_wakeup.h>
#endif /* CONFIG_HAS_WAKELOCK */
#include <linux/wakelock.h>
#include <dngl_stats.h>
#include <dhd.h>
#include <dhd_dbg.h>
@ -54,9 +53,15 @@
#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 */
#ifdef RX_PKT_POOL
#define RX_PKTPOOL_RESCHED_DELAY_MS 500u
#define RX_PKTPOOL_FETCH_MAX_ATTEMPTS 10u
typedef struct pkt_pool {
struct sk_buff_head skb_q ____cacheline_aligned;
uint32 max_size;
uint16 rxbuf_sz;
} pkt_pool_t;
#endif /* RX_PKT_POOL */
/*
* Do not include this header except for the dhd_linux.c dhd_linux_sysfs.c
@ -74,8 +79,9 @@ typedef struct dhd_info {
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 */
char clm_path[PATH_MAX]; /* path to clm vars file */
char clm_path[PATH_MAX]; /* path to CLM data */
char conf_path[PATH_MAX]; /* path to config vars file */
char sig_path[PATH_MAX]; /* path to rtecdc.sig file */
#ifdef DHD_UCODE_DOWNLOAD
char uc_path[PATH_MAX]; /* path to ucode image */
#endif /* DHD_UCODE_DOWNLOAD */
@ -96,18 +102,10 @@ typedef struct dhd_info {
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;
@ -129,32 +127,35 @@ typedef struct dhd_info {
/* Wakelocks */
#if defined(CONFIG_HAS_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 */
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 wakeup_source wl_intrwake; /* Host wakeup wakelock */
struct wakeup_source *wl_intrwake; /* Host wakeup wakelock */
#endif /* BCMPCIE_OOB_HOST_WAKE */
#ifdef DHD_USE_SCAN_WAKELOCK
struct wakeup_source 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 */
struct wakeup_source *wl_nanwake; /* NAN wakelock */
#endif /* CONFIG_HAS_WAKELOCK */
struct wake_lock rx_wakelock;
#if defined(OEM_ANDROID)
/* net_device interface lock, prevent race conditions among net_dev interface
* calls and wifi_on or wifi_off
*/
struct mutex dhd_net_if_mutex;
struct mutex dhd_suspend_mutex;
#if defined(PKT_FILTER_SUPPORT) && defined(APF)
#if defined(APF)
struct mutex dhd_apf_mutex;
#endif /* PKT_FILTER_SUPPORT && APF */
#endif /* APF */
#else
#if defined(APF)
struct mutex dhd_apf_mutex;
#endif /* APF */
#endif /* OEM_ANDROID */
spinlock_t wakelock_spinlock;
spinlock_t wakelock_evt_spinlock;
@ -254,6 +255,11 @@ typedef struct dhd_info {
struct work_struct tx_dispatcher_work;
struct work_struct rx_compl_dispatcher_work;
/* Emergency queue to hold pkts when flow control is enabled and
* same pkts will be posted back to the dongle till flow control is disabled.
*/
struct sk_buff_head rx_emerge_queue ____cacheline_aligned;
/* Number of times DPC Tasklet ran */
uint32 dhd_dpc_cnt;
/* Number of times NAPI processing got scheduled */
@ -352,7 +358,12 @@ typedef struct dhd_info {
uint32 *rxc_hist[HIST_BIN_SIZE];
struct kobject dhd_lb_kobj;
bool dhd_lb_candidacy_override;
enum cpuhp_state dhd_cpuhp_state;
#endif /* DHD_LB */
/* DPC bounds sysfs */
struct kobject dhd_dpc_bounds_kobj;
#if defined(DNGL_AXI_ERROR_LOGGING) && defined(DHD_USE_WQ_FOR_DNGL_AXI_ERROR)
struct work_struct axi_error_dispatcher_work;
#endif /* DNGL_AXI_ERROR_LOGGING && DHD_USE_WQ_FOR_DNGL_AXI_ERROR */
@ -364,24 +375,20 @@ 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;
bool fw_download_thread_exit;
#endif /* BCMDBUS */
#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */
uint32 flag_kobj; /* Add for duplicate kobj processing */
struct kobject dhd_kobj;
timer_list_compat_t timesync_timer;
#if defined(BT_OVER_SDIO)
@ -397,7 +404,7 @@ typedef struct dhd_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 */
@ -408,27 +415,13 @@ typedef struct dhd_info {
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];
@ -436,19 +429,35 @@ typedef struct dhd_info {
#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;
#ifdef WL_CFGVENDOR_SEND_ALERT_EVENT
struct work_struct dhd_alert_process_work;
#endif /* WL_CFGVENDOR_SEND_ALERT_EVENT */
#ifdef RX_PKT_POOL
pkt_pool_t rx_pkt_pool;
tsk_ctl_t rx_pktpool_thread;
#endif
#if defined(DHD_FILE_DUMP_EVENT) && defined(DHD_FW_COREDUMP)
osl_atomic_t dump_status;
struct work_struct dhd_dump_proc_work;
#endif /* DHD_FILE_DUMP_EVENT && DHD_FW_COREDUMP */
} dhd_info_t;
/** priv_link is the link between netdev and the dhdif and dhd_info structs. */
typedef struct dhd_dev_priv {
dhd_info_t * dhd; /* cached pointer to dhd_info in netdevice priv */
dhd_if_t * ifp; /* cached pointer to dhd_if in netdevice priv */
int ifidx; /* interface index */
void * lkup;
} dhd_dev_priv_t;
#define DHD_DEV_PRIV_SIZE (sizeof(dhd_dev_priv_t))
#define DHD_DEV_PRIV(dev) ((dhd_dev_priv_t *)DEV_PRIV(dev))
#define DHD_DEV_INFO(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->dhd)
#define DHD_DEV_IFP(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifp)
#define DHD_DEV_IFIDX(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifidx)
#define DHD_DEV_LKUP(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->lkup)
#ifdef WL_MONITOR
#define MONPKT_EXTRA_LEN 48u
#endif /* WL_MONITOR */
@ -495,21 +504,42 @@ int dhd_register_cpuhp_callback(dhd_info_t *dhd);
int dhd_unregister_cpuhp_callback(dhd_info_t *dhd);
#endif /* DHD_LB */
#if defined(DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON)
#ifdef RX_PKT_POOL
void dhd_rx_pktpool_init(dhd_info_t *dhd);
void dhd_rx_pktpool_deinit(dhd_info_t *dhd);
#endif /* RX_PKT_POOL */
#if defined(SET_PCIE_IRQ_CPU_CORE) || defined(DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON)
void dhd_irq_set_affinity(dhd_pub_t *dhdp, const struct cpumask *cpumask);
#endif /* DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON */
#endif /* SET_PCIE_IRQ_CPU_CORE || DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON */
void dhd_flush_logtrace_process(dhd_info_t *dhd);
#ifdef DHD_SSSR_DUMP
extern uint sssr_enab;
extern uint fis_enab;
#endif /* DHD_SSSR_DUMP */
#if defined(ANDROID_VERSION) && (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0))
#define WAKELOCK_BACKPORT
#endif
#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)
#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) || defined(WAKELOCK_BACKPORT))
#define dhd_wake_lock_init(wakeup_source, dev, name) \
do { \
wakeup_source = wakeup_source_register(dev, name); \
} while (0);
#else
#define dhd_wake_lock_init(wakeup_source, dev, name) \
do { \
wakeup_source = wakeup_source_register(name); \
} while (0);
#endif /* LINUX_VERSION >= 5.4.0 */
#define dhd_wake_lock_destroy(wakeup_source) \
do { \
wakeup_source_unregister(wakeup_source); \
} while (0);
#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)

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* Expose some of the kernel scheduler routines
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -31,11 +31,24 @@
int setScheduler(struct task_struct *p, int policy, struct sched_param *param)
{
int rc = 0;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0))
sched_set_fifo_low(p);
#else
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0))
rc = sched_setscheduler(p, policy, param);
#endif
#else
switch (policy) {
case SCHED_FIFO:
sched_set_fifo(p);
break;
case SCHED_RR:
sched_set_fifo_low(p);
break;
case SCHED_NORMAL:
default:
sched_set_normal(p, PRIO_TO_NICE(param->sched_priority));
break;
}
#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)) */
return rc;
}

View File

@ -4,7 +4,7 @@
* Provides type definitions and function prototypes to call into
* DHD's QOS on Socket Flow module.
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -32,87 +32,45 @@
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)
static 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)
static 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)
static 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)
static 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,
static 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_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
/*
* Broadcom Dongle Host Driver (DHD),
* Linux-specific network interface for transmit(tx) path
*
* Copyright (C) 2022, 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_tx_h_
#define _dhd_linux_tx_h_
void dhd_tx_stop_queues(struct net_device *net);
void dhd_tx_start_queues(struct net_device *net);
int BCMFASTPATH(__dhd_sendpkt)(dhd_pub_t *dhdp, int ifidx, void *pktbuf);
int BCMFASTPATH(dhd_sendpkt)(dhd_pub_t *dhdp, int ifidx, void *pktbuf);
#ifdef DHD_MQ
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
uint16
BCMFASTPATH(dhd_select_queue)(struct net_device *net, struct sk_buff *skb,
void *accel_priv, select_queue_fallback_t fallback);
#else
uint16
BCMFASTPATH(dhd_select_queue)(struct net_device *net, struct sk_buff *skb);
#endif /* LINUX_VERSION_CODE */
#endif /* DHD_MQ */
netdev_tx_t BCMFASTPATH(dhd_start_xmit)(struct sk_buff *skb, struct net_device *net);
void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state);
void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success);
void dhd_os_tx_completion_wake(dhd_pub_t *dhd);
void dhd_os_sdlock_txq(dhd_pub_t *pub);
void dhd_os_sdunlock_txq(dhd_pub_t *pub);
#endif /* _dhd_linux_tx_h_ */

View File

@ -2,7 +2,7 @@
* Broadcom Dongle Host Driver (DHD), Generic work queue framework
* Generic interface to handle dhd deferred work events
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you

View File

@ -2,7 +2,7 @@
* Broadcom Dongle Host Driver (DHD), Generic work queue framework
* Generic interface to handle dhd deferred work events
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -47,15 +47,14 @@ enum _wq_event {
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 */
DHD_WQ_WORK_AML_IOVAR,
DHD_WQ_WORK_NDEV_UPD_FEATURES,
DHD_MAX_WQ_EVENTS
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,402 @@
/*
* log_dump - debugability support for dumping logs to file - header file
*
* Copyright (C) 2022, 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_LOG_DUMP_H__
#define __DHD_LOG_DUMP_H__
#ifdef DHD_LOG_DUMP
#include <dhd.h>
#define LOG_DUMP_MAGIC 0xDEB3DEB3
#ifdef EWP_ECNTRS_LOGGING
#define ECNTR_RING_ID 0xECDB
#define ECNTR_RING_NAME "ewp_ecntr_ring"
#endif /* EWP_ECNTRS_LOGGING */
#ifdef EWP_RTT_LOGGING
#define RTT_RING_ID 0xADCD
#define RTT_RING_NAME "ewp_rtt_ring"
#endif /* EWP_ECNTRS_LOGGING */
#ifdef EWP_BCM_TRACE
#define BCM_TRACE_RING_ID 0xBCBC
#define BCM_TRACE_RING_NAME "ewp_bcm_trace_ring"
#endif /* EWP_BCM_TRACE */
#define DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE 512
#define DHD_LOG_DUMP_MAX_TAIL_FLUSH_SIZE (80 * 1024)
#define DHD_LOG_DUMP_TS_MULTIPLIER_VALUE 60
#define DHD_LOG_DUMP_TS_FMT_YYMMDDHHMMSSMSMS "%02d-%02d-%02d/%02d:%02d:%02d.%04lu"
#define DHD_LOG_DUMP_TS_FMT_YYMMDDHHMMSS "%02d%02d%02d%02d%02d%02d"
#define DHD_DEBUG_DUMP_TYPE "debug_dump"
#define DEBUG_DUMP_TRIGGER_INTERVAL_SEC 4
#ifndef _DHD_LOG_DUMP_DEFINITIONS_
#define _DHD_LOG_DUMP_DEFINITIONS_
#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 RING_DUMP_HDR "\n-------------------- Ring 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 */
#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_EX
#define DHD_LOG_DUMP_WRITE_ROAM DHD_DBG_RING_ROAM
#define DHD_PREFIX_TS "[%s][%s] ", \
OSL_GET_RTCTIME(), dhd_log_dump_get_timestamp()
#define DHD_PREFIX_TS_FN "[%s][%s] %s: ", \
OSL_GET_RTCTIME(), dhd_log_dump_get_timestamp(), __func__
#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_EX(DHD_PREFIX_TS)
#define DHD_LOG_DUMP_WRITE_PRSRV_TS_FN DHD_DBG_RING_EX(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 */
#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"
#define DHD_PKTID_MAP_LOG_HDR "\n---------------- PKTID MAP log -----------------------\n"
#define DHD_PKTID_UNMAP_LOG_HDR "\n------------------ PKTID UNMAP log -----------------------\n"
#define PKTID_LOG_DUMP_FMT \
"\nIndex \t\tTimestamp \tPktaddr(PA) \tPktid \tSize \tPkttype\n(Current=%d)\n"
/* 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
#define DHD_PRINT_BUF_NAME_LEN 30
#ifdef DHD_SSSR_DUMP
#define DUMP_SSSR_ATTR_START 2
#define DUMP_SSSR_ATTR_COUNT 10
typedef enum {
SSSR_C0_D11_BEFORE = 0,
SSSR_C0_D11_AFTER = 1,
SSSR_C1_D11_BEFORE = 2,
SSSR_C1_D11_AFTER = 3,
SSSR_C2_D11_BEFORE = 4,
SSSR_C2_D11_AFTER = 5,
SSSR_DIG_BEFORE = 6,
SSSR_DIG_AFTER = 7
} EWP_SSSR_DUMP;
#endif /* DHD_SSSR_DUMP */
typedef enum {
DLD_BUF_TYPE_GENERAL = 0,
DLD_BUF_TYPE_PRESERVE = 1,
DLD_BUF_TYPE_SPECIAL = 2,
DLD_BUF_TYPE_ECNTRS = 3,
DLD_BUF_TYPE_FILTER = 4,
DLD_BUF_TYPE_ALL = 5
} log_dump_type_t;
/*
* XXX: Always add new enums at the end to compatible with parser,
* also add new section in split_ret of EWP_config.py
*/
typedef enum {
LOG_DUMP_SECTION_GENERAL = 0,
LOG_DUMP_SECTION_ECNTRS,
LOG_DUMP_SECTION_SPECIAL,
LOG_DUMP_SECTION_DHD_DUMP,
LOG_DUMP_SECTION_EXT_TRAP,
LOG_DUMP_SECTION_HEALTH_CHK,
LOG_DUMP_SECTION_PRESERVE,
LOG_DUMP_SECTION_COOKIE,
LOG_DUMP_SECTION_RING,
LOG_DUMP_SECTION_STATUS,
LOG_DUMP_SECTION_RTT,
LOG_DUMP_SECTION_BCM_TRACE,
LOG_DUMP_SECTION_PKTID_MAP_LOG,
LOG_DUMP_SECTION_PKTID_UNMAP_LOG,
LOG_DUMP_SECTION_TIMESTAMP,
LOG_DUMP_SECTION_MAX
} log_dump_section_type_t;
/* Each section in the debug_dump log file shall begin with a header */
typedef struct {
uint32 magic; /* 0xDEB3DEB3 */
uint32 type; /* of type log_dump_section_type_t */
uint64 timestamp;
uint32 length; /* length of the section that follows */
} log_dump_section_hdr_t;
#ifdef DHD_DEBUGABILITY_LOG_DUMP_RING
struct dhd_dbg_ring_buf
{
void *dhd_pub;
};
extern struct dhd_dbg_ring_buf g_ring_buf;
#endif /* DHD_DEBUGABILITY_LOG_DUMP_RING */
typedef struct dhd_debug_dump_ring_entry {
log_dump_section_type_t type;
uint32 debug_dump_ring;
} dhd_debug_dump_ring_entry_t;
/* below structure describe ring buffer. */
struct dhd_log_dump_buf
{
#if defined(LINUX) || defined(linux) || defined(ANDROID) || defined(OEM_ANDROID)
spinlock_t lock;
#endif
void *dhd_pub;
unsigned int enable;
unsigned int wraparound;
unsigned long max;
unsigned int remain;
char* present;
char* front;
char* buffer;
};
typedef struct {
char *hdr_str;
log_dump_section_type_t sec_type;
} dld_hdr_t;
extern void dhd_log_dump_write(int type, char *binary_data,
int binary_len, const char *fmt, ...);
void dhd_schedule_log_dump(dhd_pub_t *dhdp, void *type);
void dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd);
void dhd_log_dump_vendor_trigger(dhd_pub_t *dhd_pub);
#ifdef DHD_DEBUGABILITY_DEBUG_DUMP
int dhd_debug_dump_get_ring_num(int sec_type);
#endif /* DHD_DEBUGABILITY_DEBUG_DUMP */
int dhd_log_dump_ring_to_file(dhd_pub_t *dhdp, void *ring_ptr, void *file,
unsigned long *file_posn, log_dump_section_hdr_t *sec_hdr, char *text_hdr,
uint32 sec_type);
int dhd_dump_debug_ring(dhd_pub_t *dhdp, void *ring_ptr, const void *user_buf,
log_dump_section_hdr_t *sec_hdr, char *text_hdr, int buflen, uint32 sec_type);
int dhd_log_dump_cookie_to_file(dhd_pub_t *dhdp, void *fp,
const void *user_buf, unsigned long *f_pos);
int dhd_log_dump_cookie(dhd_pub_t *dhdp, const void *user_buf);
uint32 dhd_log_dump_cookie_len(dhd_pub_t *dhdp);
int dhd_logdump_cookie_init(dhd_pub_t *dhdp, uint8 *buf, uint32 buf_size);
void dhd_logdump_cookie_deinit(dhd_pub_t *dhdp);
void dhd_logdump_cookie_save(dhd_pub_t *dhdp, char *cookie, char *type);
int dhd_logdump_cookie_get(dhd_pub_t *dhdp, char *ret_cookie, uint32 buf_size);
int dhd_logdump_cookie_count(dhd_pub_t *dhdp);
int dhd_get_dld_log_dump(void *dev, dhd_pub_t *dhdp, const void *user_buf, void *fp,
uint32 len, int type, void *pos);
#if defined(BCMPCIE)
int dhd_print_ext_trap_data(void *dev, dhd_pub_t *dhdp, const void *user_buf,
void *fp, uint32 len, void *pos);
uint32 dhd_get_ext_trap_len(void *ndev, dhd_pub_t *dhdp);
#endif /* BCMPCIE */
int dhd_print_dump_data(void *dev, dhd_pub_t *dhdp, const void *user_buf,
void *fp, uint32 len, void *pos);
int dhd_print_cookie_data(void *dev, dhd_pub_t *dhdp, const void *user_buf,
void *fp, uint32 len, void *pos);
int dhd_print_health_chk_data(void *dev, dhd_pub_t *dhdp, const void *user_buf,
void *fp, uint32 len, void *pos);
int dhd_print_time_str(const void *user_buf, void *fp, uint32 len, void *pos);
#ifdef DHD_DUMP_PCIE_RINGS
int dhd_print_flowring_data(void *dev, dhd_pub_t *dhdp, const void *user_buf,
void *fp, uint32 len, void *pos);
uint32 dhd_get_flowring_len(void *ndev, dhd_pub_t *dhdp);
#endif /* DHD_DUMP_PCIE_RINGS */
#ifdef DHD_STATUS_LOGGING
extern int dhd_print_status_log_data(void *dev, dhd_pub_t *dhdp,
const void *user_buf, void *fp, uint32 len, void *pos);
extern uint32 dhd_get_status_log_len(void *ndev, dhd_pub_t *dhdp);
#endif /* DHD_STATUS_LOGGING */
#ifdef DHD_MAP_PKTID_LOGGING
extern uint32 dhd_pktid_buf_len(dhd_pub_t *dhd, bool is_map);
extern int dhd_print_pktid_map_log_data(void *dev, dhd_pub_t *dhdp,
const void *user_buf, void *fp, uint32 len, void *pos, bool is_map);
extern int dhd_write_pktid_log_dump(dhd_pub_t *dhdp, const void *user_buf,
void *fp, uint32 len, unsigned long *pos, bool is_map);
extern uint32 dhd_get_pktid_map_logging_len(void *ndev, dhd_pub_t *dhdp, bool is_map);
#endif /* DHD_MAP_PKTID_LOGGING */
int dhd_print_ecntrs_data(void *dev, dhd_pub_t *dhdp, const void *user_buf,
void *fp, uint32 len, void *pos);
int dhd_print_rtt_data(void *dev, dhd_pub_t *dhdp, const void *user_buf,
void *fp, uint32 len, void *pos);
int dhd_get_debug_dump_file_name(void *dev, dhd_pub_t *dhdp,
char *dump_path, int size);
uint32 dhd_get_time_str_len(void);
uint32 dhd_get_health_chk_len(void *ndev, dhd_pub_t *dhdp);
uint32 dhd_get_dhd_dump_len(void *ndev, dhd_pub_t *dhdp);
uint32 dhd_get_cookie_log_len(void *ndev, dhd_pub_t *dhdp);
uint32 dhd_get_ecntrs_len(void *ndev, dhd_pub_t *dhdp);
uint32 dhd_get_rtt_len(void *ndev, dhd_pub_t *dhdp);
uint32 dhd_get_dld_len(int log_type);
void dhd_init_sec_hdr(log_dump_section_hdr_t *sec_hdr);
extern char *dhd_log_dump_get_timestamp(void);
bool dhd_log_dump_ecntr_enabled(void);
bool dhd_log_dump_rtt_enabled(void);
void dhd_nla_put_sssr_dump_len(void *ndev, uint32 *arr_len);
int dhd_get_debug_dump(void *dev, const void *user_buf, uint32 len, int type);
#ifdef DHD_SSSR_DUMP_BEFORE_SR
int
dhd_sssr_dump_d11_buf_before(void *dev, const void *user_buf, uint32 len, int core);
int
dhd_sssr_dump_dig_buf_before(void *dev, const void *user_buf, uint32 len);
#endif /* DHD_SSSR_DUMP_BEFORE_SR */
int
dhd_sssr_dump_d11_buf_after(void *dev, const void *user_buf, uint32 len, int core);
int
dhd_sssr_dump_dig_buf_after(void *dev, const void *user_buf, uint32 len);
#ifdef DHD_PKT_LOGGING
extern int dhd_os_get_pktlog_dump(void *dev, const void *user_buf, uint32 len);
extern spinlock_t* dhd_os_get_pktlog_lock(dhd_pub_t *dhdp);
extern uint32 dhd_os_get_pktlog_dump_size(struct net_device *dev);
extern void dhd_os_get_pktlogdump_filename(struct net_device *dev, char *dump_path, int len);
#endif /* DHD_PKT_LOGGING */
#ifdef DNGL_AXI_ERROR_LOGGING
extern int dhd_os_get_axi_error_dump(void *dev, const void *user_buf, uint32 len);
extern int dhd_os_get_axi_error_dump_size(struct net_device *dev);
extern void dhd_os_get_axi_error_filename(struct net_device *dev, char *dump_path, int len);
#endif /* DNGL_AXI_ERROR_LOGGING */
#ifdef DHD_DEBUGABILITY_DEBUG_DUMP
extern int dhd_debug_dump_to_ring(dhd_pub_t *dhdp);
#endif /* DHD_DEBUGABILITY_DEBUG_DUMP */
extern char *dhd_log_dump_get_timestamp(void);
extern void dhd_dbg_ring_write(int type, char *binary_data,
int binary_len, const char *fmt, ...);
void dhd_log_dump_init(dhd_pub_t *dhd);
void dhd_log_dump_deinit(dhd_pub_t *dhd);
void dhd_log_dump(void *handle, void *event_info, uint8 event);
int do_dhd_log_dump(dhd_pub_t *dhdp, log_dump_type_t *type);
void dhd_print_buf_addr(dhd_pub_t *dhdp, char *name, void *buf, unsigned int size);
void dhd_log_dump_buf_addr(dhd_pub_t *dhdp, log_dump_type_t *type);
int dhd_log_flush(dhd_pub_t *dhdp, log_dump_type_t *type);
extern void get_debug_dump_time(char *str);
extern void clear_debug_dump_time(char *str);
#if defined(WL_CFGVENDOR_SEND_HANG_EVENT) || defined(DHD_PKT_LOGGING)
extern void copy_debug_dump_time(char *dest, char *src);
#endif
void dhd_get_debug_dump_len(void *handle, struct sk_buff *skb, void *event_info, uint8 event);
void cfgvendor_log_dump_len(dhd_pub_t *dhdp, log_dump_type_t *type, struct sk_buff *skb);
#ifdef DHD_IOVAR_LOG_FILTER_DUMP
bool dhd_iovar_log_dump_check(dhd_pub_t *dhd_pub, uint32 cmd, char *msg);
#endif /* DHD_IOVAR_LOG_FILTER_DUMP */
#endif /* DHD_LOG_DUMP */
#endif /* !__DHD_LOG_DUMP_H__ */

View File

@ -1,746 +0,0 @@
/* 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

@ -1,34 +0,0 @@
/* 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,7 +1,7 @@
/*
* DHD debugability support
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -20,7 +20,7 @@
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_mschdbg.c 639872 2016-05-25 05:39:30Z sjadhav $
* $Id: dhd_mschdbg.c 639872 2016-05-25 05:39:30Z $
*/
#ifdef SHOW_LOGTRACE
#include <typedefs.h>
@ -47,17 +47,17 @@ static const char *head_log = "";
} \
} while (0)
#ifdef DHD_EFI
#if defined(CUSTOM_PREFIX)
#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; \
DBG_PRINT_SYSTEM_TIME; \
pr_cont args; \
} \
} while (0)
#else
#define MSCH_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0)
#endif /* DHD_EFI */
#endif
static uint64 solt_start_time[4], req_start_time[4], profiler_start_time[4];
static uint32 solt_chanspec[4] = {0, }, req_start[4] = {0, };

View File

@ -1,7 +1,7 @@
/*
* DHD debugability header file
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -20,7 +20,7 @@
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_mschdbg.h 571265 2015-07-14 20:50:18Z eccopark $
* $Id: dhd_mschdbg.h 571265 2015-07-14 20:50:18Z $
*/
#ifndef _dhd_mschdbg_h_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* Linux DHD Bus Module for PCIE
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -28,28 +28,8 @@
#include <bcmpcie.h>
#include <hnd_cons.h>
#include <fwpkg_utils.h>
#include <dhd_linux.h>
#ifdef SUPPORT_LINKDOWN_RECOVERY
#ifdef CONFIG_ARCH_MSM
#ifdef CONFIG_PCI_MSM
#include <linux/msm_pcie.h>
#else
#include <mach/msm_pcie.h>
#endif /* CONFIG_PCI_MSM */
#endif /* CONFIG_ARCH_MSM */
#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 /* !SUPPORT_EXYNOS7420 */
#endif /* CONFIG_ARCH_EXYNOS */
#endif /* SUPPORT_LINKDOWN_RECOVERY */
#ifdef DHD_PCIE_RUNTIMEPM
#include <linux/mutex.h>
#include <linux/wait.h>
#endif /* DHD_PCIE_RUNTIMEPM */
/* defines */
#define PCIE_SHARED_VERSION PCIE_SHARED_VERSION_7
@ -65,19 +45,6 @@ extern int exynos_pcie_deregister_event(struct exynos_pcie_register_event *reg);
#define REMAP_ENAB(bus) ((bus)->remap)
#define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize)))
#ifdef SUPPORT_LINKDOWN_RECOVERY
#ifdef CONFIG_ARCH_MSM
#define struct_pcie_notify struct msm_pcie_notify
#define struct_pcie_register_event struct msm_pcie_register_event
#endif /* CONFIG_ARCH_MSM */
#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 /* !SUPPORT_EXYNOS7420 */
#endif /* CONFIG_ARCH_EXYNOS */
#endif /* SUPPORT_LINKDOWN_RECOVERY */
#define MAX_DHD_TX_FLOWS 320
/* user defined data structures */
@ -186,7 +153,7 @@ typedef struct _dhd_ds_trace_t {
#define PCIE_FASTLPO_ENABLED(buscorerev) \
((buscorerev == 66) || (buscorerev == 67) || (buscorerev == 68) || \
(buscorerev == 70) || (buscorerev == 72))
(buscorerev == 70) || (buscorerev == 72) || (buscorerev == 76))
/*
* HW JIRA - CRWLPCIEGEN2-672
@ -264,6 +231,16 @@ typedef struct _dhd_flow_ring_status_trace_t {
} dhd_frs_trace_t;
#endif /* DHD_FLOW_RING_STATUS_TRACE */
typedef enum dhd_pcie_link_state {
DHD_PCIE_ALL_GOOD = 0,
DHD_PCIE_LINK_DOWN = 1,
DHD_PCIE_COMMON_BP_DOWN = 2,
DHD_PCIE_WLAN_BP_DOWN = 3
} dhd_pcie_link_state_type_t;
/* Max length of filename in IOVAR or in module parameter */
#define DHD_MAX_PATH 2048u
/** Instantiated once for each hardware (dongle) instance that this DHD manages */
typedef struct dhd_bus {
dhd_pub_t *dhd; /**< pointer to per hardware (dongle) unique instance */
@ -271,9 +248,6 @@ typedef struct dhd_bus {
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;
@ -349,14 +323,6 @@ typedef struct dhd_bus {
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;
@ -403,25 +369,8 @@ typedef struct dhd_bus {
bool irq_registered;
bool d2h_intr_method;
bool d2h_intr_control;
#ifdef SUPPORT_LINKDOWN_RECOVERY
#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 || 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 */
bool runtime_resume_done; /* For check runtime suspend end */
struct mutex pm_lock; /* Synchronize for system PM & runtime PM */
wait_queue_head_t rpm_queue; /* wait-queue for bus wake up */
#endif /* DHD_PCIE_RUNTIMEPM */
uint32 d3_inform_cnt;
uint32 d0_inform_cnt;
uint32 d0_inform_in_use_cnt;
@ -455,14 +404,14 @@ typedef struct dhd_bus {
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 */
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 host_irq_enable_count;
ulong host_irq_disable_count;
ulong dngl_intmask_disable_count;
ulong dngl_intmask_enable_count;
ulong dpc_return_busdown_count;
ulong non_ours_irq_count;
#ifdef BCMPCIE_OOB_HOST_WAKE
@ -475,6 +424,7 @@ typedef struct dhd_bus {
uint64 last_oob_irq_disable_time;
#endif /* BCMPCIE_OOB_HOST_WAKE */
uint64 isr_entry_time;
uint64 prev_isr_entry_time;
uint64 isr_exit_time;
uint64 isr_sched_dpc_time;
uint64 rpm_sched_dpc_time;
@ -482,6 +432,7 @@ typedef struct dhd_bus {
uint64 dpc_exit_time;
uint64 resched_dpc_time;
uint64 last_d3_inform_time;
uint64 last_d3_ack_time;
uint64 last_process_ctrlbuf_time;
uint64 last_process_flowring_time;
uint64 last_process_txcpl_time;
@ -493,6 +444,16 @@ typedef struct dhd_bus {
uint64 last_resume_start_time;
uint64 last_resume_end_time;
uint64 last_non_ours_irq_time;
uint64 dpc_time_usec;
uint64 *dpc_time_histo;
uint64 ctrl_cpl_post_time_usec;
uint64 *ctrl_cpl_post_time_histo;
uint64 tx_post_time_usec;
uint64 *tx_post_time_histo;
uint64 tx_cpl_time_usec;
uint64 *tx_cpl_time_histo;
uint64 rx_cpl_post_time_usec;
uint64 *rx_cpl_post_time_histo;
bool hwa_enabled;
bool idma_enabled;
bool ifrm_enabled;
@ -518,9 +479,6 @@ typedef struct dhd_bus {
#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 */
@ -536,6 +494,8 @@ typedef struct dhd_bus {
uint32 gdb_proxy_last_id;
/* True if firmware was started in bootloader mode */
bool gdb_proxy_bootloader_mode;
/* Counter incremented at each generated memory dump */
uint32 gdb_proxy_mem_dump_count;
#endif /* GDB_PROXY */
uint8 dma_chan;
@ -560,7 +520,7 @@ typedef struct dhd_bus {
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 fwsig_filename[DHD_MAX_PATH]; /* 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. */
@ -576,12 +536,9 @@ typedef struct dhd_bus {
#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 */
uint32 alp_to_ilp_ratio; /* ALP ticks per ILP ticks read from pmu_xtalfreq */
uint32 xtal_to_alp_ratio; /* xtal to ALP ratio which can change from chip to chip */
#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 */
@ -591,8 +548,27 @@ typedef struct dhd_bus {
uint64 rd_shared_pass_time;
uint32 hwa_mem_base;
uint32 hwa_mem_size;
dhd_pcie_link_state_type_t link_state;
bool dar_err_set;
uint32 ptm_ctrl_reg;
fwpkg_info_t fwpkg; /* combined fw package info structure */
bool lpm_mode; /* lpm enabled */
bool lpm_keep_in_reset; /* during LPM keep in FLR, if FLR force is enabled */
bool lpm_mem_kill; /* kill WLAN memories in LPM */
bool lpm_force_flr; /* Force F0 FLR on WLAN when in LPM */
uint32 lpbk_xfer_data_pattern_type; /* data Pattern type DMA lpbk */
} dhd_bus_t;
#define LPBK_DMA_XFER_DTPTRN_DEFAULT 0
#define LPBK_DMA_XFER_DTPTRN_0x00 1
#define LPBK_DMA_XFER_DTPTRN_0xFF 2
#define LPBK_DMA_XFER_DTPTRN_0x55 3
#define LPBK_DMA_XFER_DTPTRN_0xAA 4
#define LPM_MODE_LPM_ALL 0x1
#define LPM_MODE_NO_MEMKILL 0x010
#define LPM_MODE_NO_FLR 0x100
#ifdef DHD_MSI_SUPPORT
extern uint enable_msi;
#endif /* DHD_MSI_SUPPORT */
@ -759,6 +735,7 @@ 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);
extern void dhd_bus_dump_imp_cfg_registers(struct dhd_bus *bus);
#if defined(linux) || defined(LINUX)
extern uint32 dhdpcie_rc_config_read(dhd_bus_t *bus, uint offset);
@ -767,6 +744,7 @@ extern uint32 dhdpcie_rc_access_cap(dhd_bus_t *bus, int cap, uint offset, bool i
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 void dhdpcie_enable_irq_loop(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,
@ -774,7 +752,8 @@ static INLINE uint32 dhdpcie_rc_access_cap(dhd_bus_t *bus, int cap, uint offset,
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
static INLINE void dhdpcie_enable_irq_loop(dhd_bus_t *bus) { return; }
#endif /* LINUX || linux */
#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);
@ -794,9 +773,10 @@ uint32 dhdpcie_os_rtcm32(dhd_bus_t *bus, ulong offset);
void dhdpcie_os_wtcm64(dhd_bus_t *bus, ulong offset, uint64 data);
uint64 dhdpcie_os_rtcm64(dhd_bus_t *bus, ulong offset);
#endif
extern void dhd_dpc_kill(dhd_pub_t *dhdp);
#endif /* LINUX || linux */
#if defined(linux) || defined(LINUX) || defined(DHD_EFI)
#if defined(linux) || defined(LINUX)
extern int dhdpcie_enable_device(dhd_bus_t *bus);
#endif
@ -807,6 +787,9 @@ 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);
#ifdef PRINT_WAKEUP_GPIO_STATUS
extern int dhdpcie_get_oob_gpio_number(void);
#endif /* PRINT_WAKEUP_GPIO_STATUS */
#endif /* BCMPCIE_OOB_HOST_WAKE */
#ifdef PCIE_OOB
extern void dhd_oob_set_bt_reg_on(struct dhd_bus *bus, bool val);
@ -819,93 +802,14 @@ extern void dhd_os_ib_set_device_wake(struct dhd_bus *bus, bool val);
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 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 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)
#define MSM_PCIE_VENDOR_ID 0x17cb
#if defined(CONFIG_ARCH_APQ8084)
#define MSM_PCIE_DEVICE_ID 0x0101
#elif defined(CONFIG_ARCH_MSM8994)
#define MSM_PCIE_DEVICE_ID 0x0300
#elif defined(CONFIG_ARCH_MSM8996)
#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
#endif /* CONFIG_ARCH_MSM */
#if defined(CONFIG_X86)
#define X86_PCIE_VENDOR_ID 0x8086
#define X86_PCIE_DEVICE_ID 0x9c1a
#endif /* CONFIG_X86 */
#if defined(CONFIG_ARCH_TEGRA)
#define TEGRA_PCIE_VENDOR_ID 0x14e4
#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 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
#elif defined(CONFIG_X86)
#define PCIE_RC_VENDOR_ID X86_PCIE_VENDOR_ID
#define PCIE_RC_DEVICE_ID X86_PCIE_DEVICE_ID
#elif defined(CONFIG_ARCH_TEGRA)
#define PCIE_RC_VENDOR_ID TEGRA_PCIE_VENDOR_ID
#define PCIE_RC_DEVICE_ID TEGRA_PCIE_DEVICE_ID
#elif defined(BOARD_HIKEY)
#define PCIE_RC_VENDOR_ID HIKEY_PCIE_VENDOR_ID
#define PCIE_RC_DEVICE_ID HIKEY_PCIE_DEVICE_ID
#else
/* 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 DHD_SET_PCIE_DMA_MASK_FOR_GS101
/* This is only for GS101 platform. Others is done on RC side */
#define DHD_PCIE_DMA_MASK_FOR_GS101 36
#endif /* DHD_SET_PCIE_DMA_MASK_FOR_GS101 */
#ifdef CONFIG_ARCH_TEGRA
extern int tegra_pcie_pm_suspend(void);
extern int tegra_pcie_pm_resume(void);
@ -932,6 +836,8 @@ extern int dhdpcie_send_mb_data(dhd_bus_t *bus, uint32 h2d_mb_data);
#ifdef DHD_WAKE_STATUS
int bcmpcie_get_total_wake(struct dhd_bus *bus);
int bcmpcie_set_get_wake(struct dhd_bus *bus, int flag);
int bcmpcie_get_wake(struct dhd_bus *bus);
int bcmpcie_set_get_wake_pkt_dump(struct dhd_bus *bus, int wake_pkt_dump);
#endif /* DHD_WAKE_STATUS */
#ifdef DHD_MMIO_TRACE
extern void dhd_dump_bus_mmio_trace(dhd_bus_t *bus, struct bcmstrbuf *strbuf);
@ -950,6 +856,9 @@ extern enum dhd_bus_ds_state dhdpcie_bus_get_pcie_inband_dw_state(dhd_bus_t *bus
extern const char * dhd_convert_inb_state_names(enum dhd_bus_ds_state inbstate);
extern const char * dhd_convert_dsval(uint32 val, bool d2h);
extern int dhd_bus_inb_set_device_wake(struct dhd_bus *bus, bool val);
#ifdef PCIE_INB_DSACK_EXT_WAIT
extern void dhd_bus_ds_ack_debug_dump(struct dhd_bus *bus);
#endif /* PCIE_INB_DSACK_EXT_WAIT */
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);
@ -962,27 +871,11 @@ 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 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);
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 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);
@ -1022,18 +915,10 @@ extern int dhdpcie_get_fwpath_otp(dhd_bus_t *bus, char *fw_path, char *nv_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)
#if 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);
@ -1045,4 +930,11 @@ 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 */
extern bool dhd_check_htput_chip(dhd_bus_t *bus);
#if defined(DEVICE_TX_STUCK_DETECT) && defined(ASSOC_CHECK_SR)
void dhd_assoc_check_sr(dhd_pub_t *dhd, bool state);
#endif /* DEVICE_TX_STUCK_DETECT && ASSOC_CHECK_SR */
void dhd_init_bar1_switch_lock(dhd_bus_t *bus);
#endif /* dhd_pcie_h */

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/*
* DHD debugability packet logging support
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -32,6 +32,7 @@
#include <dhd_dbg.h>
#include <dhd_pktlog.h>
#include <dhd_wlfc.h>
#include <dhd_debug.h>
#ifdef DHD_COMPACT_PKT_LOG
#include <bcmip.h>
@ -41,6 +42,7 @@
#include <bcmicmp.h>
#include <bcmtlv.h>
#include <802.11.h>
#include <802.11u.h>
#include <eap.h>
#include <eapol.h>
#include <bcmendian.h>
@ -129,9 +131,37 @@ static int dhd_cpkt_log_init_tt(dhd_pub_t *dhdp);
static void dhd_cpkt_log_deinit_tt(dhd_pub_t *dhdp);
#endif /* DHD_COMPACT_PKT_LOG */
#ifdef DHD_PKT_LOGGING_DBGRING
#define DHD_PKT_LOGGING_DBGRING_MAX_SIZE 400u
const char dhd_eap_pattern[] = "12 0xffff 0x888e";
const char dhd_arp_pattern[] = "12 0xffff 0x0806";
const char dhd_icmp_pattern[] =
"12 0xffffff0000000000000000ff 0x080045000000000000000001";
const char dhd_icmpv6_pattern[] =
"12 0xfffff00000000000ff 0x86dd6000000000003a";
const char dhd_dhcp_pattern_01[] =
"12 0xffffff0000000000000000ff00000000000000000000ffffffff"
" 0x0800450000000000000000110000000000000000000000430044";
const char dhd_dhcp_pattern_02[] =
"12 0xffffff0000000000000000ff00000000000000000000ffffffff"
" 0x0800450000000000000000110000000000000000000000440043";
const char dhd_dns_pattern_01[] =
"12 0xffffff0000000000000000ff000000000000000000000000ffff"
" 0x0800450000000000000000110000000000000000000000000035";
const char dhd_dns_pattern_02[] =
"12 0xffffff0000000000000000ff00000000000000000000ffff0000"
" 0x0800450000000000000000110000000000000000000000350000";
const char dhd_dns_pattern_03[] =
"12 0xffffff0000000000000000ff00000000000000000000ffffffff"
" 0x0800450000000000000000110000000000000000000014e914e9";
#endif /* DHD_PKT_LOGGING_DBGRING */
int
dhd_os_attach_pktlog(dhd_pub_t *dhdp)
{
#ifdef DHD_PKT_LOGGING_DBGRING
char filter_pattern[MAX_FILTER_PATTERN_LEN];
#endif /* DHD_PKT_LOGGING_DBGRING */
dhd_pktlog_t *pktlog;
if (!dhdp) {
@ -139,7 +169,7 @@ dhd_os_attach_pktlog(dhd_pub_t *dhdp)
return -EINVAL;
}
pktlog = (dhd_pktlog_t *)MALLOCZ(dhdp->osh, sizeof(dhd_pktlog_t));
pktlog = (dhd_pktlog_t *)VMALLOCZ(dhdp->osh, sizeof(dhd_pktlog_t));
if (unlikely(!pktlog)) {
DHD_ERROR(("%s(): could not allocate memory for - "
"dhd_pktlog_t\n", __FUNCTION__));
@ -150,6 +180,9 @@ dhd_os_attach_pktlog(dhd_pub_t *dhdp)
pktlog->dhdp = dhdp;
OSL_ATOMIC_INIT(dhdp->osh, &pktlog->pktlog_status);
#ifdef DHD_PKT_LOGGING_DBGRING
OSL_ATOMIC_INIT(dhdp->osh, &pktlog->enable);
#endif /* DHD_PKT_LOGGING_DBGRING */
/* pktlog ring */
dhdp->pktlog->pktlog_ring = dhd_pktlog_ring_init(dhdp, MIN_PKTLOG_LEN);
@ -158,6 +191,16 @@ dhd_os_attach_pktlog(dhd_pub_t *dhdp)
dhd_cpkt_log_init_tt(dhdp);
#endif
#ifdef DHD_PKT_LOGGING_DBGRING
/* By default, EAP, ARP, ICMP, ICMPV6, DHCP packets are allowed. */
DHD_PKTLOG_FILTER_ADD(dhd_eap_pattern, filter_pattern, dhdp);
DHD_PKTLOG_FILTER_ADD(dhd_arp_pattern, filter_pattern, dhdp);
DHD_PKTLOG_FILTER_ADD(dhd_icmp_pattern, filter_pattern, dhdp);
DHD_PKTLOG_FILTER_ADD(dhd_icmpv6_pattern, filter_pattern, dhdp);
DHD_PKTLOG_FILTER_ADD(dhd_dhcp_pattern_01, filter_pattern, dhdp);
DHD_PKTLOG_FILTER_ADD(dhd_dhcp_pattern_02, filter_pattern, dhdp);
#endif /* DHD_PKT_LOGGING_DBGRING */
DHD_ERROR(("%s(): dhd_os_attach_pktlog attach\n", __FUNCTION__));
return BCME_OK;
@ -178,13 +221,80 @@ dhd_os_detach_pktlog(dhd_pub_t *dhdp)
dhd_cpkt_log_deinit_tt(dhdp);
#endif /* DHD_COMPACT_PKT_LOG */
DHD_ERROR(("%s(): dhd_os_attach_pktlog detach\n", __FUNCTION__));
DHD_INFO(("%s(): dhd_os_attach_pktlog detach\n", __FUNCTION__));
MFREE(dhdp->osh, dhdp->pktlog, sizeof(dhd_pktlog_t));
VMFREE(dhdp->osh, dhdp->pktlog, sizeof(dhd_pktlog_t));
return BCME_OK;
}
#ifdef DHD_PKT_LOGGING_DBGRING
int dhd_pktlog_is_enabled(dhd_pub_t *dhdp)
{
if (!dhdp || !dhdp->pktlog) {
DHD_ERROR(("%s(): dhdp=%p pktlog=%p\n",
__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
return BCME_ERROR;
}
if (!dhdp->pktlog->pktlog_ring) {
DHD_ERROR(("%s(): pktlog_ring=%p\n",
__FUNCTION__, dhdp->pktlog->pktlog_ring));
return BCME_ERROR;
}
return OSL_ATOMIC_READ(dhdp->osh, &dhdp->pktlog->enable);
}
void dhd_pktlog_resume(dhd_pub_t *dhdp)
{
struct dhd_pktlog_ring *pktlog_ring;
if (!dhdp || !dhdp->pktlog) {
DHD_ERROR(("%s(): dhdp=%p pktlog=%p\n",
__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
return;
}
if (!dhdp->pktlog->pktlog_ring) {
DHD_ERROR(("%s(): pktlog_ring=%p\n",
__FUNCTION__, dhdp->pktlog->pktlog_ring));
return;
}
pktlog_ring = dhdp->pktlog->pktlog_ring;
if (!OSL_ATOMIC_READ(dhdp->osh, &dhdp->pktlog->enable)) {
OSL_ATOMIC_SET(dhdp->osh, &dhdp->pktlog->enable, TRUE);
DHD_INFO(("pktlog ring is resumed. pktcount(%d)\n",
pktlog_ring->pktcount));
}
}
void dhd_pktlog_suspend(dhd_pub_t *dhdp)
{
struct dhd_pktlog_ring *pktlog_ring;
if (!dhdp || !dhdp->pktlog) {
DHD_ERROR(("%s(): dhdp=%p pktlog=%p\n",
__FUNCTION__, dhdp, (dhdp ? dhdp->pktlog : NULL)));
return;
}
if (!dhdp->pktlog->pktlog_ring) {
DHD_ERROR(("%s(): pktlog_ring=%p\n",
__FUNCTION__, dhdp->pktlog->pktlog_ring));
return;
}
pktlog_ring = dhdp->pktlog->pktlog_ring;
if (OSL_ATOMIC_READ(dhdp->osh, &dhdp->pktlog->enable)) {
OSL_ATOMIC_SET(dhdp->osh, &dhdp->pktlog->enable, FALSE);
DHD_INFO(("pktlog ring is suspended. pktcount(%d)\n",
pktlog_ring->pktcount));
}
}
#endif /* DHD_PKT_LOGGING_DBGRING */
dhd_pktlog_ring_t*
dhd_pktlog_ring_init(dhd_pub_t *dhdp, int size)
{
@ -196,7 +306,7 @@ dhd_pktlog_ring_init(dhd_pub_t *dhdp, int size)
return NULL;
}
ring = (dhd_pktlog_ring_t *)MALLOCZ(dhdp->osh, sizeof(dhd_pktlog_ring_t));
ring = (dhd_pktlog_ring_t *)VMALLOCZ(dhdp->osh, sizeof(dhd_pktlog_ring_t));
if (unlikely(!ring)) {
DHD_ERROR(("%s(): could not allocate memory for - "
"dhd_pktlog_ring_t\n", __FUNCTION__));
@ -206,7 +316,7 @@ dhd_pktlog_ring_init(dhd_pub_t *dhdp, int size)
dll_init(&ring->ring_info_head);
dll_init(&ring->ring_info_free);
ring->ring_info_mem = (dhd_pktlog_ring_info_t *)MALLOCZ(dhdp->osh,
ring->ring_info_mem = (dhd_pktlog_ring_info_t *)VMALLOCZ(dhdp->osh,
sizeof(dhd_pktlog_ring_info_t) * size);
if (unlikely(!ring->ring_info_mem)) {
DHD_ERROR(("%s(): could not allocate memory for - "
@ -225,13 +335,16 @@ dhd_pktlog_ring_init(dhd_pub_t *dhdp, int size)
ring->pktcount = 0;
ring->dhdp = dhdp;
ring->pktlog_ring_lock = osl_spin_lock_init(dhdp->osh);
#ifdef DHD_PKT_LOGGING_DBGRING
OSL_ATOMIC_SET(dhdp->osh, &dhdp->pktlog->enable, TRUE);
#endif /* DHD_PKT_LOGGING_DBGRING */
DHD_ERROR(("%s(): pktlog ring init success\n", __FUNCTION__));
DHD_INFO(("%s(): pktlog ring init success\n", __FUNCTION__));
return ring;
fail:
if (ring) {
MFREE(dhdp->osh, ring, sizeof(dhd_pktlog_ring_t));
VMFREE(dhdp->osh, ring, sizeof(dhd_pktlog_ring_t));
}
return NULL;
@ -290,7 +403,7 @@ dhd_pktlog_ring_deinit(dhd_pub_t *dhdp, dhd_pktlog_ring_t *ring)
}
if (ring->ring_info_mem) {
MFREE(ring->dhdp->osh, ring->ring_info_mem,
VMFREE(ring->dhdp->osh, ring->ring_info_mem,
sizeof(dhd_pktlog_ring_info_t) * ring->pktlog_len);
}
@ -298,13 +411,86 @@ dhd_pktlog_ring_deinit(dhd_pub_t *dhdp, dhd_pktlog_ring_t *ring)
osl_spin_lock_deinit(ring->dhdp->osh, ring->pktlog_ring_lock);
}
MFREE(dhdp->osh, ring, sizeof(dhd_pktlog_ring_t));
VMFREE(dhdp->osh, ring, sizeof(dhd_pktlog_ring_t));
DHD_ERROR(("%s(): pktlog ring deinit\n", __FUNCTION__));
DHD_INFO(("%s(): pktlog ring deinit\n", __FUNCTION__));
return ret;
}
#ifdef DHD_PKT_LOGGING_DBGRING
int
dhd_pktlog_ring_reinit(dhd_pub_t *dhdp)
{
dhd_pktlog_ring_info_t *ring_info;
dhd_pktlog_ring_t *pktlog_ring;
dll_t *item, *next_p;
int waitcounts = 0;
dhd_dbg_ring_t *ring;
DHD_ERROR(("%s: ENTER\n", __FUNCTION__));
if (!dhdp) {
DHD_ERROR(("%s(): dhdp is NULL\n", __FUNCTION__));
return -EINVAL;
}
pktlog_ring = dhdp->pktlog->pktlog_ring;
ring = &dhdp->dbg->dbg_rings[PACKET_LOG_RING_ID];
if (!ring) {
DHD_ERROR(("%s(): ring is NULL\n", __FUNCTION__));
return -EINVAL;
}
/* stop pkt log */
OSL_ATOMIC_SET(dhdp->osh, &pktlog_ring->start, FALSE);
/* waiting TX/RX/TXS context is done, max timeout 1 second */
while ((waitcounts++ < DHD_PKTLOG_WAIT_MAXCOUNT)) {
if (!OSL_ATOMIC_READ(dhdp->osh, &dhdp->pktlog->pktlog_status))
break;
OSL_SLEEP(1);
}
if (waitcounts >= DHD_PKTLOG_WAIT_MAXCOUNT) {
DHD_ERROR(("%s(): pktlog wait timeout pktlog_status : 0x%x \n",
__FUNCTION__,
OSL_ATOMIC_READ(dhdp->osh, &dhdp->pktlog->pktlog_status)));
ASSERT(0);
return -EINVAL;
}
/* free ring_info->info.pkt */
for (item = dll_head_p(&pktlog_ring->ring_info_head);
!dll_end(&pktlog_ring->ring_info_head, item);
item = next_p) {
next_p = dll_next_p(item);
ring_info = (dhd_pktlog_ring_info_t *)item;
dll_delete((dll_t *)item);
if (ring_info->info.pkt) {
PKTFREE(pktlog_ring->dhdp->osh, ring_info->info.pkt, TRUE);
DHD_PKT_LOG(("%s(): pkt free pos %p\n",
__FUNCTION__, ring_info->info.pkt));
}
dll_append(&pktlog_ring->ring_info_free, (dll_t *)item);
}
/* reset stats and pktcount */
pktlog_ring->pktcount = 0;
memset(&ring->stat, 0, sizeof(struct ring_statistics));
/* start pkt log */
OSL_ATOMIC_SET(dhdp->osh, &pktlog_ring->start, TRUE);
#ifdef DHD_PKT_LOGGING_DBGRING
OSL_ATOMIC_SET(dhdp->osh, &dhdp->pktlog->enable, TRUE);
#endif /* DHD_PKT_LOGGING_DBGRING */
DHD_ERROR(("%s: EXIT\n", __FUNCTION__));
return BCME_OK;
}
#endif /* DHD_PKT_LOGGING_DBGRING */
/*
* dhd_pktlog_ring_add_pkts : add filtered packets into pktlog ring
* pktid : incase of rx, pktid is not used (pass DHD_INVALID_PKID)
@ -316,10 +502,16 @@ dhd_pktlog_ring_add_pkts(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pktid
dhd_pktlog_ring_info_t *pkts;
dhd_pktlog_ring_t *pktlog_ring;
dhd_pktlog_filter_t *pktlog_filter;
u64 ts_nsec;
uint32 pktlog_case = 0;
unsigned long rem_nsec;
unsigned long flags = 0;
#ifdef DHD_PKT_LOGGING_DBGRING
struct timespec64 ts;
dhd_dbg_ring_t *ring;
ring = &dhdp->dbg->dbg_rings[PACKET_LOG_RING_ID];
#else
u64 ts_nsec;
unsigned long rem_nsec;
#endif /* DHD_PKT_LOGGING_DBGRING */
/*
* dhdp, dhdp->pktlog, dhd->pktlog_ring, pktlog_ring->start
@ -335,6 +527,16 @@ dhd_pktlog_ring_add_pkts(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pktid
pktlog_case = PKTLOG_RXPKT_CASE;
}
if (pktlog_filter && pktlog_filter->list_cnt == 0) {
/* There is no packet log list */
return BCME_OK;
}
#ifdef DHD_PKT_LOGGING_DBGRING
if (ring->log_level == RING_LOG_LEVEL_EXCESSIVE) {
/* In excessive log level, pass through without pattern matching */
} else
#endif /* DHD_PKT_LOGGING_DBGRING */
if ((direction != PKT_WAKERX) &&
dhd_pktlog_filter_matched(pktlog_filter, pktdata, pktlog_case)
== FALSE) {
@ -361,17 +563,36 @@ dhd_pktlog_ring_add_pkts(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pktid
}
/* Update packet information */
#ifdef DHD_PKT_LOGGING_DBGRING
ktime_get_real_ts64(&ts);
pkts->info.driver_ts_sec = (uint32)ts.tv_sec;
pkts->info.driver_ts_usec = (uint32)(ts.tv_nsec/NSEC_PER_USEC);
#else
ts_nsec = local_clock();
rem_nsec = do_div(ts_nsec, NSEC_PER_SEC);
pkts->info.pkt = PKTDUP(dhdp->osh, pkt);
pkts->info.pkt_len = PKTLEN(dhdp->osh, pkt);
pkts->info.driver_ts_sec = (uint32)ts_nsec;
pkts->info.driver_ts_usec = (uint32)(rem_nsec/NSEC_PER_USEC);
#endif /* DHD_PKT_LOGGING_DBGRING */
pkts->info.pkt = PKTDUP(dhdp->osh, pkt);
/*
* skb clone can be NULL, but pktlog feature assume it alway can be cloned
* The dummy pkt info will be added in the list to fit pktcount & list items
* and handled in the dhd_pktlog_dump_write() with ignoring info.pkt
*/
if (pkts->info.pkt == NULL) {
DHD_ERROR(("%s : skb clone returns NULL \n", __FUNCTION__));
}
pkts->info.pkt_len = PKTLEN(dhdp->osh, pkt);
pkts->info.firmware_ts = 0U;
pkts->info.payload_type = FRAME_TYPE_ETHERNET_II;
pkts->info.direction = direction;
pkts->info.tx_status_ts_sec = 0;
pkts->info.tx_status_ts_usec = 0;
if (direction == PKT_TX) {
pkts->info.pkt_hash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid);
pkts->tx_fate = TX_PKT_FATE_DRV_QUEUED;
@ -391,6 +612,12 @@ dhd_pktlog_ring_add_pkts(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pktid
dll_append(&pktlog_ring->ring_info_head, (dll_t *)pkts);
pktlog_ring->pktcount++;
DHD_PKT_LOG_UNLOCK(pktlog_ring->pktlog_ring_lock, flags);
#ifdef DHD_PKT_LOGGING_DBGRING
dhd_dbg_update_to_ring(dhdp, pktlog_ring->dbg_ring,
dhd_pktlog_get_item_length(pkts));
#endif /* DHD_PKT_LOGGING_DBGRING */
DHD_PKT_LOG(("%s(): pktcount=%d\n", __FUNCTION__, pktlog_ring->pktcount));
return BCME_OK;
}
@ -405,7 +632,8 @@ dhd_pktlog_ring_tx_status(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pkti
dhd_pktlog_filter_t *pktlog_filter;
dll_t *item_p, *next_p;
unsigned long flags = 0;
u64 ts_nsec;
unsigned long rem_nsec;
#ifdef BDC
struct bdc_header *h;
BCM_REFERENCE(h);
@ -426,6 +654,9 @@ dhd_pktlog_ring_tx_status(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pkti
pkt_hash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid);
pkt_fate = __dhd_dbg_map_tx_status_to_pkt_fate(status);
ts_nsec = local_clock();
rem_nsec = do_div(ts_nsec, NSEC_PER_SEC);
/* find the sent tx packet and adding pkt_fate info */
DHD_PKT_LOG_LOCK(pktlog_ring->pktlog_ring_lock, flags);
/* Inverse traverse from the last packets */
@ -446,6 +677,8 @@ dhd_pktlog_ring_tx_status(dhd_pub_t *dhdp, void *pkt, void *pktdata, uint32 pkti
PKTPULL(dhdp->osh, tx_pkt->info.pkt, BDC_HEADER_LEN);
PKTPULL(dhdp->osh, tx_pkt->info.pkt, (h->dataOffset << DHD_WORD_TO_LEN_SHIFT));
#endif /* BDC */
tx_pkt->info.tx_status_ts_sec = (uint32)ts_nsec;
tx_pkt->info.tx_status_ts_usec = (uint32)(rem_nsec/NSEC_PER_USEC);
DHD_PKT_LOG(("%s(): Found pkt hash in prev pos\n", __FUNCTION__));
break;
}
@ -491,7 +724,7 @@ dhd_pktlog_filter_init(int size)
filter->enable = PKTLOG_TXPKT_CASE | PKTLOG_TXSTATUS_CASE | PKTLOG_RXPKT_CASE;
DHD_ERROR(("%s(): pktlog filter init success\n", __FUNCTION__));
DHD_INFO(("%s(): pktlog filter init success\n", __FUNCTION__));
return filter;
fail:
@ -517,7 +750,7 @@ dhd_pktlog_filter_deinit(dhd_pktlog_filter_t *filter)
}
kfree(filter);
DHD_ERROR(("%s(): pktlog filter deinit\n", __FUNCTION__));
DHD_INFO(("%s(): pktlog filter deinit\n", __FUNCTION__));
return ret;
}
@ -837,6 +1070,7 @@ dhd_pktlog_filter_matched(dhd_pktlog_filter_t *filter, char *data, uint32 pktlog
/* Ethernet Type MAC Header 12 bytes + Frame payload 10 bytes */
#define PKTLOG_MINIMIZE_REPORT_LEN 22
#ifndef DHD_PKT_LOGGING_DBGRING
static char pktlog_minmize_mask_table[] = {
0xff, 0x00, 0x00, 0x00, 0xff, 0x0f, /* Ethernet Type MAC Header - Destination MAC Address */
0xff, 0x00, 0x00, 0x00, 0xff, 0x0f, /* Ethernet Type MAC Header - Source MAC Address */
@ -890,6 +1124,7 @@ dhd_pktlog_minimize_report(char *pkt, uint32 frame_len,
}
vfree(mem_buf);
}
#endif /* !DHD_PKT_LOGGING_DBGRING */
dhd_pktlog_ring_t*
dhd_pktlog_ring_change_size(dhd_pktlog_ring_t *ringbuf, int size)
@ -1018,27 +1253,39 @@ dhd_pktlog_get_item_length(dhd_pktlog_ring_info_t *report_ptr)
} else {
frame_len = (uint32)min(report_ptr->info.pkt_len, (size_t)MAX_FRAME_LEN_80211_MGMT);
}
bytes_user_data = sprintf(buf, "%s:%s:%02d\n", DHD_PKTLOG_FATE_INFO_FORMAT,
(report_ptr->tx_fate ? "Failure" : "Succeed"), report_ptr->tx_fate);
#ifdef DHD_PKT_LOGGING_DBGRING
frame_len = (uint32)min(frame_len, DHD_PKT_LOGGING_DBGRING_MAX_SIZE);
bytes_user_data = snprintf(buf, sizeof(buf), "%s:%s:%02d\n",
DHD_PKTLOG_FATE_INFO_FORMAT,
(report_ptr->tx_fate ? "Failure" : "Succeed"), report_ptr->tx_fate);
#else
bytes_user_data = snprintf(buf, sizeof(buf), "%s:%s:%02d:%s:%d.%d s\n",
DHD_PKTLOG_FATE_INFO_FORMAT,
(report_ptr->tx_fate ? "Failure" : "Succeed"), report_ptr->tx_fate,
(report_ptr->info.direction == PKT_TX) ? "TX" : "RX",
report_ptr->info.tx_status_ts_sec, report_ptr->info.tx_status_ts_usec);
#endif /* DHD_PKT_LOGGING_DBGRING */
write_frame_len = frame_len + bytes_user_data;
/* pcap pkt head has incl_len and orig_len */
len += (uint32)sizeof(write_frame_len);
len += (uint32)sizeof(write_frame_len);
len += frame_len;
len += bytes_user_data;
len += write_frame_len;
return len;
}
uint32
int
dhd_pktlog_get_dump_length(dhd_pub_t *dhdp)
{
dhd_pktlog_ring_info_t *report_ptr;
dhd_pktlog_ring_t *pktlog_ring;
uint32 len;
uint32 len = 0;
dll_t *item_p, *next_p;
#ifdef DHD_PKT_LOGGING_DBGRING
dhd_dbg_ring_t *ring;
ring = &dhdp->dbg->dbg_rings[PACKET_LOG_RING_ID];
#endif /* DHD_PKT_LOGGING_DBGRING */
if (!dhdp || !dhdp->pktlog) {
DHD_PKT_LOG(("%s(): dhdp=%p pktlog=%p\n",
@ -1054,15 +1301,20 @@ dhd_pktlog_get_dump_length(dhd_pub_t *dhdp)
pktlog_ring = dhdp->pktlog->pktlog_ring;
OSL_ATOMIC_SET(dhdp->osh, &pktlog_ring->start, FALSE);
#ifndef DHD_PKT_LOGGING_DBGRING
len = sizeof(dhd_pktlog_pcap_hdr_t);
#endif /* !DHD_PKT_LOGGING_DBGRING */
for (item_p = dll_head_p(&pktlog_ring->ring_info_head);
!dll_end(&pktlog_ring->ring_info_head, item_p);
item_p = next_p) {
next_p = dll_next_p(item_p);
report_ptr = (dhd_pktlog_ring_info_t *)item_p;
len += dhd_pktlog_get_item_length(report_ptr);
#ifdef DHD_PKT_LOGGING_DBGRING
if (len >= ring->threshold) {
break;
}
#endif /* DHD_PKT_LOGGING_DBGRING */
}
OSL_ATOMIC_SET(dhdp->osh, &pktlog_ring->start, TRUE);
DHD_PKT_LOG(("calcuated pkt log dump len:%d\n", len));
@ -1071,17 +1323,27 @@ dhd_pktlog_get_dump_length(dhd_pub_t *dhdp)
}
int
#ifdef DHD_PKT_LOGGING_DBGRING
dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, const void *user_buf,
uint32 *written_bytes)
#else
dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, const void *user_buf, uint32 size)
#endif /* DHD_PKT_LOGGING_DBGRING */
{
dhd_pktlog_ring_info_t *report_ptr;
dhd_pktlog_ring_t *pktlog_ring;
char buf[DHD_PKTLOG_FATE_INFO_STR_LEN];
#ifndef DHD_PKT_LOGGING_DBGRING
dhd_pktlog_pcap_hdr_t pcap_h;
loff_t pos = 0;
#else
uint32 size = 0;
unsigned long flags = 0;
#endif /* !DHD_PKT_LOGGING_DBGRING */
uint32 write_frame_len;
uint32 frame_len;
ulong len;
ulong len = 0;
int bytes_user_data = 0;
loff_t pos = 0;
int ret = BCME_OK;
dll_t *item_p, *next_p;
@ -1097,10 +1359,23 @@ dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, const void *user_buf, uint32
return -EINVAL;
}
#ifdef DHD_PKT_LOGGING_DBGRING
if (user_buf) {
size = *written_bytes;
} else if (file) {
/* With DHD_PKT_LOGGING_DBGRING, this path is not allowed. */
return BCME_UNSUPPORTED;
}
#endif /* DHD_PKT_LOGGING_DBGRING */
if (file && !user_buf && (size == 0)) {
DHD_ERROR(("Local file pktlog dump requested\n"));
} else if (!file && user_buf && (size > 0)) {
#ifdef DHD_PKT_LOGGING_DBGRING
DHD_INFO(("HAL file pktlog dump %d bytes requested\n", size));
#else
DHD_ERROR(("HAL file pktlog dump %d bytes requested\n", size));
#endif /* DHD_PKT_LOGGING_DBGRING */
} else {
DHD_ERROR(("Wrong type pktlog dump requested\n"));
return -EINVAL;
@ -1108,7 +1383,7 @@ dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, const void *user_buf, uint32
pktlog_ring = dhdp->pktlog->pktlog_ring;
OSL_ATOMIC_SET(dhdp->osh, &pktlog_ring->start, FALSE);
#ifndef DHD_PKT_LOGGING_DBGRING
pcap_h.magic_number = PKTLOG_PCAP_MAGIC_NUM;
pcap_h.version_major = PKTLOG_PCAP_MAJOR_VER;
pcap_h.version_minor = PKTLOG_PCAP_MINOR_VER;
@ -1119,20 +1394,90 @@ dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, const void *user_buf, uint32
ret = dhd_export_debug_data((char *)&pcap_h, file, user_buf, sizeof(pcap_h), &pos);
len = sizeof(pcap_h);
#endif /* !DHD_PKT_LOGGING_DBGRING */
#ifdef DHD_PKT_LOGGING_DBGRING
DHD_PKT_LOG_LOCK(dhd_os_get_pktlog_lock(dhdp), flags);
#endif /* DHD_PKT_LOGGING_DBGRING */
for (item_p = dll_head_p(&pktlog_ring->ring_info_head);
!dll_end(&pktlog_ring->ring_info_head, item_p);
item_p = next_p) {
#ifdef DHD_PKT_LOGGING_DBGRING
uint32 captured_frame_len;
#endif /* DHD_PKT_LOGGING_DBGRING */
next_p = dll_next_p(item_p);
report_ptr = (dhd_pktlog_ring_info_t *)item_p;
#ifdef DHD_PKT_LOGGING_DBGRING
if (report_ptr->info.direction == PKT_TX &&
report_ptr->tx_fate == TX_PKT_FATE_DRV_QUEUED) {
/* Not updated txfate yet, postpone some time. */
report_ptr->tx_fate |= TX_PKT_FATE_DRV_WAIT_UPDATE;
continue;
}
#endif /* DHD_PKT_LOGGING_DBGRING */
if ((file == NULL) &&
(len + dhd_pktlog_get_item_length(report_ptr) > size)) {
#ifdef DHD_PKT_LOGGING_DBGRING
DHD_INFO(("overflowed pkt logs are dropped\n"));
#else
DHD_ERROR(("overflowed pkt logs are dropped\n"));
#endif /* DHD_PKT_LOGGING_DBGRING */
break;
}
if (report_ptr->info.pkt == NULL) {
DHD_ERROR(("%s : pkt isn't located skip it\n", __FUNCTION__));
continue;
}
#ifdef DHD_PKT_LOGGING_DBGRING
ret = memcpy_s((void*)(user_buf + len), size - len,
(char*)&report_ptr->info.driver_ts_sec,
sizeof(report_ptr->info.driver_ts_sec));
len += sizeof(report_ptr->info.driver_ts_sec);
ret = memcpy_s((void*)(user_buf + len), size - len,
(char*)&report_ptr->info.driver_ts_usec,
sizeof(report_ptr->info.driver_ts_usec));
len += sizeof(report_ptr->info.driver_ts_usec);
if (report_ptr->info.payload_type == FRAME_TYPE_ETHERNET_II) {
frame_len = (uint32)min(report_ptr->info.pkt_len,
(size_t)MAX_FRAME_LEN_ETHERNET);
} else {
frame_len = (uint32)min(report_ptr->info.pkt_len,
(size_t)MAX_FRAME_LEN_80211_MGMT);
}
bytes_user_data = snprintf(buf, sizeof(buf), "%s:%s:%02d\n",
DHD_PKTLOG_FATE_INFO_FORMAT,
(report_ptr->tx_fate ? "Failure" : "Succeed"),
(report_ptr->tx_fate & ~(TX_PKT_FATE_DRV_WAIT_UPDATE)));
write_frame_len = frame_len + bytes_user_data;
frame_len = (uint32)min(frame_len, DHD_PKT_LOGGING_DBGRING_MAX_SIZE);
captured_frame_len = frame_len + bytes_user_data;
/* pcap pkt head has incl_len and orig_len */
ret = memcpy_s((void*)(user_buf + len), size - len,
(char*)&captured_frame_len, sizeof(captured_frame_len));
len += sizeof(captured_frame_len);
ret = memcpy_s((void*)(user_buf + len), size - len,
(char*)&write_frame_len, sizeof(write_frame_len));
len += sizeof(write_frame_len);
ret = memcpy_s((void*)(user_buf + len), size - len, PKTDATA(pktlog_ring->dhdp->osh,
report_ptr->info.pkt), frame_len);
len += frame_len;
ret = memcpy_s((void*)(user_buf + len), size - len, buf, bytes_user_data);
len += bytes_user_data;
dll_delete((dll_t *)report_ptr);
PKTFREE(pktlog_ring->dhdp->osh, report_ptr->info.pkt, TRUE);
pktlog_ring->pktcount--;
dll_append(&pktlog_ring->ring_info_free, (dll_t *)report_ptr);
#else
ret = dhd_export_debug_data((char*)&report_ptr->info.driver_ts_sec, file,
user_buf, sizeof(report_ptr->info.driver_ts_sec), &pos);
len += sizeof(report_ptr->info.driver_ts_sec);
@ -1150,8 +1495,13 @@ dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, const void *user_buf, uint32
(size_t)MAX_FRAME_LEN_80211_MGMT);
}
bytes_user_data = sprintf(buf, "%s:%s:%02d\n", DHD_PKTLOG_FATE_INFO_FORMAT,
(report_ptr->tx_fate ? "Failure" : "Succeed"), report_ptr->tx_fate);
bytes_user_data = snprintf(buf, sizeof(buf), "%s:%s:%02d:%s:%d.%d s\n",
DHD_PKTLOG_FATE_INFO_FORMAT,
(report_ptr->tx_fate ? "Failure" : "Succeed"),
report_ptr->tx_fate,
(report_ptr->info.direction == PKT_TX) ? "TX" : "RX",
report_ptr->info.tx_status_ts_sec,
report_ptr->info.tx_status_ts_usec);
write_frame_len = frame_len + bytes_user_data;
/* pcap pkt head has incl_len and orig_len */
@ -1174,7 +1524,12 @@ dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, const void *user_buf, uint32
ret = dhd_export_debug_data(buf, file, user_buf, bytes_user_data, &pos);
len += bytes_user_data;
#endif /* DHD_PKT_LOGGING_DBGRING */
}
#ifdef DHD_PKT_LOGGING_DBGRING
DHD_PKT_LOG_UNLOCK(dhd_os_get_pktlog_lock(dhdp), flags);
*written_bytes = len;
#endif /* DHD_PKT_LOGGING_DBGRING */
OSL_ATOMIC_SET(dhdp->osh, &pktlog_ring->start, TRUE);
return ret;
@ -1183,7 +1538,11 @@ dhd_pktlog_dump_write(dhd_pub_t *dhdp, void *file, const void *user_buf, uint32
int
dhd_pktlog_dump_write_memory(dhd_pub_t *dhdp, const void *user_buf, uint32 size)
{
#ifdef DHD_PKT_LOGGING_DBGRING
int ret = dhd_pktlog_dump_write(dhdp, NULL, user_buf, &size);
#else
int ret = dhd_pktlog_dump_write(dhdp, NULL, user_buf, size);
#endif /* DHD_PKT_LOGGING_DBGRING */
if (ret < 0) {
DHD_ERROR(("dhd_pktlog_dump_write_memory error\n"));
}
@ -1195,17 +1554,21 @@ dhd_pktlog_dump_write_file(dhd_pub_t *dhdp)
{
struct file *w_pcap_fp = NULL;
uint32 file_mode;
#ifdef get_fs
mm_segment_t old_fs;
#endif /* get_fs */
char pktlogdump_path[128];
int ret = BCME_OK;
dhd_pktlog_get_filename(dhdp, pktlogdump_path, 128);
#ifdef get_fs
old_fs = get_fs();
set_fs(KERNEL_DS);
#endif /* get_fs */
file_mode = O_CREAT | O_WRONLY;
w_pcap_fp = filp_open(pktlogdump_path, file_mode, 0664);
if (IS_ERR(w_pcap_fp)) {
w_pcap_fp = dhd_filp_open(pktlogdump_path, file_mode, 0664);
if (IS_ERR(w_pcap_fp) || (w_pcap_fp == NULL)) {
DHD_ERROR(("%s: Couldn't open file '%s' err %ld\n",
__FUNCTION__, pktlogdump_path, PTR_ERR(w_pcap_fp)));
ret = BCME_ERROR;
@ -1219,18 +1582,18 @@ dhd_pktlog_dump_write_file(dhd_pub_t *dhdp)
}
/* Sync file from filesystem to physical media */
ret = vfs_fsync(w_pcap_fp, 0);
ret = dhd_vfs_fsync(w_pcap_fp, 0);
if (ret < 0) {
DHD_ERROR(("%s(): sync pcap file error, err = %d\n", __FUNCTION__, ret));
goto fail;
}
fail:
if (!IS_ERR(w_pcap_fp)) {
filp_close(w_pcap_fp, NULL);
dhd_filp_close(w_pcap_fp, NULL);
}
#ifdef get_fs
set_fs(old_fs);
#endif /* get_fs */
#ifdef DHD_DUMP_MNGR
if (ret >= 0) {
dhd_dump_file_manage_enqueue(dhdp, pktlogdump_path, DHD_PKTLOG_DUMP_TYPE);

View File

@ -1,7 +1,7 @@
/*
* DHD debugability packet logging header file
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -58,6 +58,8 @@ typedef struct dhd_dbg_pktlog_info {
uint32 driver_ts_usec;
uint32 firmware_ts;
uint32 pkt_hash;
uint32 tx_status_ts_sec;
uint32 tx_status_ts_usec;
bool direction;
void *pkt;
} dhd_dbg_pktlog_info_t;
@ -84,6 +86,9 @@ typedef struct dhd_pktlog_ring
spinlock_t *pktlog_ring_lock;
dhd_pub_t *dhdp;
dhd_pktlog_ring_info_t *ring_info_mem; /* ring_info mem pointer */
#ifdef DHD_PKT_LOGGING_DBGRING
void *dbg_ring;
#endif /* DHD_PKT_LOGGING_DBGRING */
} dhd_pktlog_ring_t;
typedef struct dhd_pktlog_filter_info
@ -112,6 +117,9 @@ typedef struct dhd_pktlog
#ifdef DHD_COMPACT_PKT_LOG
struct rb_root cpkt_log_tt_rbt;
#endif /* DHD_COMPACT_PKT_LOG */
#ifdef DHD_PKT_LOGGING_DBGRING
osl_atomic_t enable; /* logging suspend/resume */
#endif /* DHD_PKT_LOGGING_DBGRING */
} dhd_pktlog_t;
typedef struct dhd_pktlog_pcap_hdr
@ -133,6 +141,12 @@ typedef struct dhd_pktlog_pcap_hdr
extern int dhd_os_attach_pktlog(dhd_pub_t *dhdp);
extern int dhd_os_detach_pktlog(dhd_pub_t *dhdp);
#ifdef DHD_PKT_LOGGING_DBGRING
extern int dhd_pktlog_is_enabled(dhd_pub_t *dhdp);
extern void dhd_pktlog_suspend(dhd_pub_t *dhdp);
extern void dhd_pktlog_resume(dhd_pub_t *dhdp);
extern int dhd_pktlog_ring_reinit(dhd_pub_t *dhdp);
#endif /* DHD_PKT_LOGGING_DBGRING */
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);
@ -298,7 +312,7 @@ extern int dhd_pktlog_dump_write_file(dhd_pub_t *dhdp);
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 int 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

View File

@ -1,7 +1,7 @@
/*
* DHD Linux platform header file
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -26,6 +26,8 @@
#ifndef __DHD_PLAT_H__
#define __DHD_PLAT_H__
#if defined(__linux__)
#include <linuxver.h>
#if !defined(CONFIG_WIFI_CONTROL_FUNC)
@ -38,7 +40,7 @@ struct wifi_platform_data {
#ifdef DHD_COREDUMP
int (*set_coredump)(const char *buf, int buf_len, const char *info);
#endif /* DHD_COREDUMP */
#ifdef BCMDHD_MDRIVER
#if defined(BCMDHD_MDRIVER) && !defined(DHD_STATIC_IN_DRIVER)
void *(*mem_prealloc)(uint bus_type, int index, int section, unsigned long size);
#else
void *(*mem_prealloc)(int section, unsigned long size);
@ -53,6 +55,49 @@ struct wifi_platform_data {
void *(*get_country_code)(char *ccode);
#endif
};
#endif /* CONFIG_WIFI_CONTROL_FUNC */
#endif
#include <linux/pci.h>
/*
* Plat Layer defines the interfaces that the BSP specific file should override
* The default implementation of the interfaces are present in dhd_linux_platdev.c
* The data structure/handle to be passed by the DHD to BSP specific file is opaque
* called plat_info. The data structure is to be maintained purely inside the
* BSP specific file and hence its kept opaque.
*
* There are two types of interface functions
* 1) Functions that need the interface structure plat_info to be passed down
* from DHD.
* 2) Functions that queries for certain information in BSP specific way and just
* returns to DHD - These functions does not take the plat_info as argument.
*
* The declarations are grouped accordingly. While adding a new interface function
* declaration based on the group it belongs to add it in the appropriate section
*/
typedef void (*dhd_pcie_event_cb_t) (struct pci_dev *pdev);
extern int dhd_plat_pcie_register_event(void *plat_info,
struct pci_dev *pdev, dhd_pcie_event_cb_t pfn);
extern void dhd_plat_pcie_deregister_event(void *plat_info);
extern void dhd_plat_report_bh_sched(void *plat_info, int resched);
extern int dhd_plat_pcie_suspend(void *plat_info);
extern int dhd_plat_pcie_resume(void *plat_info);
extern void dhd_plat_pcie_register_dump(void *plat_info);
extern void dhd_plat_pin_dbg_show(void *plat_info);
extern uint32 dhd_plat_get_info_size(void);
extern void dhd_plat_l1ss_ctrl(bool ctrl);
/* To be called when we intend to exit L1 while performing wreg, rreg operations */
extern void dhd_plat_l1_exit_io(void);
/* To be called when we intend to exit L1 in non-io case */
extern void dhd_plat_l1_exit(void);
extern uint32 dhd_plat_get_rc_vendor_id(void);
extern uint32 dhd_plat_get_rc_device_id(void);
extern uint16 dhd_plat_align_rxbuf_size(uint16 rxbufpost_sz);
#endif /* __linux__ */
#endif /* __DHD_PLAT_H__ */

View File

@ -2,7 +2,7 @@
* Broadcom Dongle Host Driver (DHD)
* Prefered Network Offload and Wi-Fi Location Service(WLS) code.
*
* Copyright (C) 2020, Broadcom.
* Copyright (C) 2022, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@ -22,7 +22,7 @@
* <<Broadcom-WL-IPTag/Dual:>>
*/
#if defined (GSCAN_SUPPORT) && !defined(PNO_SUPPORT)
#if defined(GSCAN_SUPPORT) && !defined(PNO_SUPPORT)
#error "GSCAN needs PNO to be enabled!"
#endif
@ -35,13 +35,11 @@
#include <bcmendian.h>
#ifdef OEM_ANDROID
#include <linuxver.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/sort.h>
#endif
#include <dngl_stats.h>
#include <wlioctl.h>
@ -74,15 +72,34 @@
#define dtohchanspec(i) (i)
#endif /* IL_BIGENDINA */
#ifdef OEM_ANDROID
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0))
#define COMPLETION_WAIT_QUEUE_ACTIVE(wait_queue) swait_active(wait_queue)
#else
#define COMPLETION_WAIT_QUEUE_ACTIVE(wait_queue) waitqueue_active(wait_queue)
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) */
#ifdef CUSTOM_PREFIX
#define PNO_PRINT_PREFIX "[%s]"CUSTOM_PREFIX, OSL_GET_RTCTIME()
#define PNO_PRINT_SYSTEM_TIME pr_cont(PNO_PRINT_PREFIX)
#define PNO_CONS_ONLY(args) \
do { \
PNO_PRINT_SYSTEM_TIME; \
pr_cont args; \
} while (0)
#else
#define PNO_PRINT_SYSTEM_TIME
#define PNO_CONS_ONLY(args) do { printf args;} while (0)
#endif /* CUSTOM_PREFIX */
#define NULL_CHECK(p, s, err) \
do { \
if (!(p)) { \
printf("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \
err = BCME_ERROR; \
return err; \
} \
} while (0)
do { \
if (!(p)) { \
PNO_CONS_ONLY(("NULL POINTER (%s) : %s\n", __FUNCTION__, (s))); \
err = BCME_ERROR; \
return err; \
} \
} while (0)
#define PNO_GET_PNOSTATE(dhd) ((dhd_pno_status_info_t *)dhd->pno_state)
#define PNO_BESTNET_LEN WLC_IOCTL_MEDLEN
@ -103,8 +120,6 @@
- (uint32)(timestamp2/1000)))
#define TIME_DIFF_MS(timestamp1, timestamp2) (abs((uint32)(timestamp1) \
- (uint32)(timestamp2)))
#define TIMESPEC_TO_US(ts) (((uint64)(ts).tv_sec * USEC_PER_SEC) + \
(ts).tv_nsec / NSEC_PER_USEC)
#define ENTRY_OVERHEAD strlen("bssid=\nssid=\nfreq=\nlevel=\nage=\ndist=\ndistSd=\n====")
#define TIME_MIN_DIFF 5
@ -210,7 +225,7 @@ dhd_is_legacy_pno_enabled(dhd_pub_t *dhd)
static uint64
convert_fw_rel_time_to_systime(struct osl_timespec *ts, uint32 fw_ts_ms)
{
return ((uint64)(TIMESPEC_TO_US(*ts)) - (uint64)(fw_ts_ms * 1000));
return ((uint64)(TIMESPEC64_TO_US(*ts)) - (uint64)(fw_ts_ms * USEC_PER_MSEC));
}
static void
@ -382,6 +397,7 @@ _dhd_pno_suspend(dhd_pub_t *dhd)
exit:
return err;
}
static int
_dhd_pno_enable(dhd_pub_t *dhd, int enable)
{
@ -402,15 +418,6 @@ _dhd_pno_enable(dhd_pub_t *dhd, int enable)
err = BCME_BADOPTION;
goto exit;
}
if (enable) {
if ((_pno_state->pno_mode & DHD_PNO_LEGACY_MODE) &&
dhd_is_associated(dhd, 0, NULL)) {
DHD_ERROR(("%s Legacy PNO mode cannot be enabled "
"in assoc mode , ignore it\n", __FUNCTION__));
err = BCME_BADOPTION;
goto exit;
}
}
/* Enable/Disable PNO */
err = dhd_iovar(dhd, 0, "pfn", (char *)&enable, sizeof(enable), NULL, 0, TRUE);
if (err < 0) {
@ -432,28 +439,71 @@ static int
_dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t mode)
{
int err = BCME_OK;
wl_pfn_param_t pfn_param;
wl_pfn_param_v3_t pfn_param;
dhd_pno_params_t *_params;
dhd_pno_status_info_t *_pno_state;
bool combined_scan = FALSE;
uint16 size;
bool use_v3 = FALSE;
DHD_PNO(("%s enter\n", __FUNCTION__));
NULL_CHECK(dhd, "dhd is NULL", err);
NULL_CHECK(dhd->pno_state, "pno_state is NULL", err);
_pno_state = PNO_GET_PNOSTATE(dhd);
memset(&pfn_param, 0, sizeof(pfn_param));
/* Query pfn version */
bzero(&pfn_param, sizeof(pfn_param));
err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param),
(char *)&pfn_param, sizeof(pfn_param), FALSE);
if (err < 0) {
if (err == BCME_UNSUPPORTED) {
DHD_PNO(("%s : PFN versioning not supported. Use v2\n",
__FUNCTION__));
use_v3 = FALSE;
} else {
DHD_ERROR(("%s : failed to query pfn_set %d\n", __FUNCTION__, err));
goto exit;
}
} else {
if (pfn_param.version == PFN_VERSION_V3) {
DHD_ERROR(("%s : using pfn_param v3\n", __FUNCTION__));
use_v3 = TRUE;
} else if (pfn_param.version == PFN_VERSION_V2) {
DHD_ERROR(("%s : using pfn_param v2\n", __FUNCTION__));
use_v3 = FALSE;
} else {
DHD_ERROR(("unsupported pfn ver:%d\n", pfn_param.version));
err = BCME_UNSUPPORTED;
goto exit;
}
}
/* set pfn parameters */
pfn_param.version = htod32(PFN_VERSION);
bzero(&pfn_param, sizeof(pfn_param));
if (use_v3) {
pfn_param.version = PFN_VERSION_V3;
pfn_param.version = htod32(pfn_param.version);
size = sizeof(wl_pfn_param_v3_t);
pfn_param.length = htod32(size);
} else {
wl_pfn_param_v2_t *pfn_param_v2 = (wl_pfn_param_v2_t *)&pfn_param;
pfn_param_v2->version = PFN_VERSION_V2;
pfn_param_v2->version = htod32(pfn_param_v2->version);
size = sizeof(wl_pfn_param_v2_t);
}
pfn_param.flags = ((PFN_LIST_ORDER << SORT_CRITERIA_BIT) |
(ENABLE << IMMEDIATE_SCAN_BIT) | (ENABLE << REPORT_SEPERATELY_BIT));
#ifdef WL_SCHED_SCAN
/* bit to select the pfn partial scan result event logic */
pfn_param.flags |= htod16(ENABLE << PFN_FULL_SCAN_RESULT_BIT);
#endif /* WL_SCHED_SCAN */
if (mode == DHD_PNO_LEGACY_MODE) {
pfn_param.repeat = (uchar) (pno_params->params_legacy.pno_repeat);
/* check and set extra pno params */
if ((pno_params->params_legacy.pno_repeat != 0) ||
if ((pno_params->params_legacy.pno_repeat != 0) &&
(pno_params->params_legacy.pno_freq_expo_max != 0)) {
pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT);
pfn_param.repeat = (uchar) (pno_params->params_legacy.pno_repeat);
pfn_param.exp = (uchar) (pno_params->params_legacy.pno_freq_expo_max);
}
/* set up pno scan fr */
@ -590,7 +640,7 @@ _dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t
goto exit;
}
}
#if (!defined(WL_USE_RANDOMIZED_SCAN))
#if !defined(WL_USE_RANDOMIZED_SCAN)
err = dhd_set_rand_mac_oui(dhd);
/* Ignore if chip doesnt support the feature */
if (err < 0 && err != BCME_UNSUPPORTED) {
@ -622,7 +672,7 @@ _dhd_pno_set(dhd_pub_t *dhd, const dhd_pno_params_t *pno_params, dhd_pno_mode_t
DHD_PNO((" returned mscan : %d, set bestn : %d mscan %d\n", _tmp, pfn_param.bestn,
pfn_param.mscan));
}
err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, sizeof(pfn_param), NULL, 0, TRUE);
err = dhd_iovar(dhd, 0, "pfn_set", (char *)&pfn_param, size, NULL, 0, TRUE);
if (err < 0) {
DHD_ERROR(("%s : failed to execute pfn_set %d\n", __FUNCTION__, err));
goto exit;
@ -970,6 +1020,15 @@ _dhd_pno_cfg(dhd_pub_t *dhd, uint16 *channel_list, int nchan)
int err = BCME_OK;
int i = 0;
wl_pfn_cfg_t pfncfg_param;
bool use_chanspec = FALSE;
#if defined(WL_6G_BAND) || defined(CFG80211_6G_SUPPORT)
/* When enable 6G, force to use chanspec list */
if (FW_SUPPORTED((dhd), 6g)) {
use_chanspec = TRUE;
}
#endif /* WL_6G_BAND || CFG80211_6G_SUPPORT */
NULL_CHECK(dhd, "dhd is NULL", err);
if (nchan) {
if (nchan > WL_NUMCHANNELS) {
@ -980,8 +1039,8 @@ _dhd_pno_cfg(dhd_pub_t *dhd, uint16 *channel_list, int nchan)
pfncfg_param.channel_num = htod32(0);
for (i = 0; i < nchan; i++) {
if (dhd->wlc_ver_major >= DHD_PNO_CHSPEC_SUPPORT_VER) {
pfncfg_param.channel_list[i] = CH20MHZ_CHSPEC(channel_list[i]);
if ((dhd->wlc_ver_major >= DHD_PNO_CHSPEC_SUPPORT_VER) || use_chanspec) {
pfncfg_param.channel_list[i] = wf_chspec_ctlchspec(channel_list[i]);
} else {
pfncfg_param.channel_list[i] = channel_list[i];
}
@ -1564,13 +1623,13 @@ dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params)
sizeof(_params->params_batch.chan_list[0]), _dhd_pno_cmpfunc, NULL);
}
#ifdef PNO_DEBUG
{
{
DHD_PNO(("Channel list : "));
for (i = 0; i < _params->params_batch.nchan; i++) {
DHD_PNO(("%d ", _params->params_batch.chan_list[i]));
}
DHD_PNO(("\n"));
}
}
#endif
if (_params->params_batch.nchan) {
/* copy the channel list into local array */
@ -2111,7 +2170,7 @@ dhd_pno_set_for_gscan(dhd_pub_t *dhd, struct dhd_pno_gscan_params *gscan_params)
goto exit;
}
pfn_gscan_cfg_t->version = WL_GSCAN_CFG_VERSION;
pfn_gscan_cfg_t->version = WL_GSCAN_CFG_VERSION_1;
if (gscan_params->mscan)
pfn_gscan_cfg_t->buffer_threshold = gscan_params->buffer_threshold;
else
@ -2480,7 +2539,7 @@ dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag)
if (old_flag != gscan_params->send_all_results_flag) {
wl_pfn_gscan_cfg_t gscan_cfg;
gscan_cfg.version = WL_GSCAN_CFG_VERSION;
gscan_cfg.version = WL_GSCAN_CFG_VERSION_1;
gscan_cfg.flags = (gscan_params->send_all_results_flag &
GSCAN_SEND_ALL_RESULTS_MASK);
gscan_cfg.flags |= GSCAN_CFG_FLAGS_ONLY_MASK;
@ -2904,7 +2963,7 @@ exit:
}
#endif /* GSCAN_SUPPORT */
#if defined (GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
static void *
dhd_get_gscan_batch_results(dhd_pub_t *dhd, uint32 *len)
{
@ -3098,8 +3157,6 @@ _dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason)
STATIC_ASSERT(sizeof(wl_pfn_net_info_v1_t) == sizeof(wl_pfn_net_info_v2_t));
STATIC_ASSERT(sizeof(wl_pfn_lnet_info_v1_t) == sizeof(wl_pfn_lnet_info_v2_t));
STATIC_ASSERT(sizeof(wl_pfn_subnet_info_v1_t) == sizeof(wl_pfn_subnet_info_v2_t));
ASSERT(OFFSETOF(wl_pfn_subnet_info_v1_t, SSID) ==
OFFSETOF(wl_pfn_subnet_info_v2_t, u.SSID));
DHD_PNO(("%s enter\n", __FUNCTION__));
_pno_state = PNO_GET_PNOSTATE(dhd);
@ -3466,15 +3523,8 @@ exit:
}
mutex_unlock(&_pno_state->pno_mutex);
exit_no_unlock:
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0))
if (waitqueue_active(&_pno_state->get_batch_done)) {
_pno_state->batch_recvd = TRUE;
wake_up(&_pno_state->get_batch_done);
}
#else
if (waitqueue_active(&_pno_state->get_batch_done.wait))
if (COMPLETION_WAIT_QUEUE_ACTIVE(&_pno_state->get_batch_done.wait))
complete(&_pno_state->get_batch_done);
#endif
return err;
}
@ -3554,15 +3604,8 @@ dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason)
params_batch->get_batch.bufsize = bufsize;
params_batch->get_batch.reason = reason;
params_batch->get_batch.bytes_written = 0;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0))
_pno_state->batch_recvd = FALSE;
#endif
schedule_work(&_pno_state->work);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0))
wait_event(_pno_state->get_batch_done, _pno_state->batch_recvd);
#else
wait_for_completion(&_pno_state->get_batch_done);
#endif
}
#ifdef GSCAN_SUPPORT
@ -3749,14 +3792,14 @@ dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid,
sizeof(_params->params_hotlist.chan_list[0]), _dhd_pno_cmpfunc, NULL);
}
#ifdef PNO_DEBUG
{
{
int i;
DHD_PNO(("Channel list : "));
for (i = 0; i < _params->params_batch.nchan; i++) {
DHD_PNO(("%d ", _params->params_batch.chan_list[i]));
}
DHD_PNO(("\n"));
}
}
#endif
if (_params->params_hotlist.nchan) {
/* copy the channel list into local array */
@ -3975,8 +4018,8 @@ dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type)
void *
dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, int *size)
{
wl_bss_info_t *bi = NULL;
wl_gscan_result_t *gscan_result;
wl_bss_info_v109_t *bi = NULL;
wl_gscan_result_v2_t *gscan_result;
wifi_gscan_full_result_t *result = NULL;
u32 bi_length = 0;
uint8 channel;
@ -3987,7 +4030,7 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, int
*size = 0;
GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
gscan_result = (wl_gscan_result_t *)data;
gscan_result = (wl_gscan_result_v2_t *)data;
GCC_DIAGNOSTIC_POP();
if (!gscan_result) {
DHD_ERROR(("Invalid gscan result (NULL pointer)\n"));
@ -4006,7 +4049,8 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, int
bi = &gscan_result->bss_info[0].info;
bi_length = dtoh32(bi->length);
if (bi_length != (dtoh32(gscan_result->buflen) -
WL_GSCAN_RESULTS_FIXED_SIZE - WL_GSCAN_INFO_FIXED_FIELD_SIZE)) {
OFFSETOF(wl_gscan_result_v2_t, bss_info) -
OFFSETOF(wl_gscan_bss_info_v2_t, info))) {
DHD_ERROR(("Invalid bss_info length %d: ignoring\n", bi_length));
goto exit;
}
@ -4039,7 +4083,7 @@ dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *data, uint32 len, int
result->fixed.rtt = 0;
result->fixed.rtt_sd = 0;
osl_get_monotonic_boottime(&ts);
result->fixed.ts = (uint64) TIMESPEC_TO_US(ts);
result->fixed.ts = (uint64) TIMESPEC64_TO_US(ts);
result->fixed.beacon_period = dtoh16(bi->beacon_period);
result->fixed.capability = dtoh16(bi->capability);
result->ie_length = bi_ie_length;
@ -4508,12 +4552,7 @@ dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data)
{
struct dhd_pno_batch_params *params_batch;
params_batch = &_pno_state->pno_params_arr[INDEX_OF_BATCH_PARAMS].params_batch;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0))
if (!waitqueue_active(&_pno_state->get_batch_done))
#else
if (!waitqueue_active(&_pno_state->get_batch_done.wait))
#endif
{
if (!COMPLETION_WAIT_QUEUE_ACTIVE(&_pno_state->get_batch_done.wait)) {
DHD_PNO(("%s : WLC_E_PFN_BEST_BATCHING\n", __FUNCTION__));
params_batch->get_batch.buf = NULL;
params_batch->get_batch.bufsize = 0;
@ -4553,11 +4592,7 @@ int dhd_pno_init(dhd_pub_t *dhd)
_pno_state->dhd = dhd;
mutex_init(&_pno_state->pno_mutex);
INIT_WORK(&_pno_state->work, _dhd_pno_get_batch_handler);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0))
init_waitqueue_head(&_pno_state->get_batch_done);
#else
init_completion(&_pno_state->get_batch_done);
#endif
#ifdef GSCAN_SUPPORT
init_waitqueue_head(&_pno_state->batch_get_wait);
#endif /* GSCAN_SUPPORT */
@ -4617,7 +4652,6 @@ int dhd_pno_deinit(dhd_pub_t *dhd)
dhd->pno_state = NULL;
return err;
}
#endif /* OEM_ANDROID */
#ifndef OEM_ANDROID
#if defined(NDIS)

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