net: wifi: rockchip_wlan: add wifi6 support for bcmdhd chipset

1. support wifi6
2. support sta/ap coex for Android P
3. support sta/ap coex for Linux Connman(Connection Manager)

notice:
  As the new drivers are unstable, the vendor suggests to maintain
two sets of drivers, and delete them after the new drivers are stable.

Signed-off-by: Yao Xiao <xiaoyao@rock-chips.com>
Change-Id: I6c98e6e031aee1d619a7f1f4a357b09975237d80
This commit is contained in:
Yao Xiao
2020-04-08 15:17:54 +08:00
committed by Tao Huang
parent ca8b52d209
commit 9d5a7a9c5a
231 changed files with 291347 additions and 9 deletions

View File

@@ -28,15 +28,24 @@ config WIFI_GENERATE_RANDOM_MAC_ADDR
help
Wifi generate random mac address and save to vendor storage for cob chip
menuconfig BCMDHD
bool "Broadcom Wireless Device Driver Support"
default y
if BCMDHD
source "drivers/net/wireless/rockchip_wlan/rkwifi/Kconfig"
source "drivers/net/wireless/rockchip_wlan/cywdhd/Kconfig"
endif
menuconfig RTL_WIRELESS_SOLUTION
bool "Realtek Wireless Device Driver Support"
default y
bool "Realtek Wireless Device Driver Support"
default n
if RTL_WIRELESS_SOLUTION
source "drivers/net/wireless/rockchip_wlan/rtl8723cs/Kconfig"
source "drivers/net/wireless/rockchip_wlan/rtl8822bs/Kconfig"
endif
source "drivers/net/wireless/rockchip_wlan/mvl88w8977/Kconfig"
source "drivers/net/wireless/rockchip_wlan/cywdhd/Kconfig"
endif # WL_ROCKCHIP

View File

@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_AP6XXX) += rkwifi/
obj-$(CONFIG_BCMDHD) += rkwifi/
obj-$(CONFIG_RTL8723CS) += rtl8723cs/
obj-$(CONFIG_RTL8822BS) += rtl8822bs/
obj-$(CONFIG_MVL88W8977) += mvl88w8977/

View File

@@ -1,9 +1,9 @@
# SPDX-License-Identifier: GPL-2.0
config CYW_BCMDHD
tristate "Cypress wireless sdio cards support"
depends on (!AP6XXX)
select WIRELESS_EXT
select WEXT_PRIV
depends on (!BCMDHD)
#select CFG80211
#select MAC80211
select CFG80211_WEXT

View File

@@ -1,9 +1,12 @@
# SPDX-License-Identifier: GPL-2.0
choice
prompt "Select driver version for ap6xxx chips"
config AP6XXX
tristate "ap6xxx wireless sdio cards support"
tristate "stable version (wifi5)"
#depends on MMC && WLAN_80211
select CFG80211
select MAC80211
select CFG80211
select MAC80211
---help---
This module adds support for wireless adapters based on
Broadcom ap6xxx chipset.
@@ -13,3 +16,19 @@ config AP6XXX
If you choose to build a module, it'll be called dhd. Say M if
unsure.
config AP6XXX_WIFI6
tristate "support wifi6(80211ax)"
#depends on MMC && WLAN_80211
select CFG80211
select MAC80211
---help---
This driver supports wifi6 for ap6xxx chipset.
This driver uses the kernel's wireless extensions subsystem.
If you choose to build a module, it'll be called dhd. Say M if
unsure.
if AP6XXX_WIFI6
source "drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd_wifi6/Kconfig"
endif
endchoice

View File

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

View File

@@ -6,7 +6,7 @@ CONFIG_BCMDHD_SDIO := y
#CONFIG_BCMDHD_PCIE := y
#CONFIG_BCMDHD_USB := y
CONFIG_BCMDHD_OOB := y
CONFIG_BCMDHD_OOB := n
#CONFIG_BCMDHD_CUSB := y
CONFIG_BCMDHD_PROPTXSTATUS := y
CONFIG_BCMDHD_AG := y

View File

@@ -0,0 +1,59 @@
# SPDX-License-Identifier: GPL-2.0
config BCMDHD_FW_PATH
depends on BCMDHD
string "Firmware path"
default "/vendor/etc/firmware/fw_bcmdhd.bin"
---help---
Path to the firmware file.
config BCMDHD_NVRAM_PATH
depends on BCMDHD
string "NVRAM path"
default "/vendor/etc/firmware/nvram.txt"
---help---
Path to the calibration file.
config BCMDHD_WEXT
bool "Enable WEXT support"
depends on BCMDHD && CFG80211 = n
select WIRELESS_EXT
select WEXT_PRIV
help
Enables WEXT support
config BCMDHD_STATIC_IF
bool "Enable wlan1 support"
choice
prompt "Enable Chip Interface"
depends on BCMDHD
---help---
Enable Chip Interface.
config BCMDHD_SDIO
bool "SDIO bus interface support"
depends on BCMDHD && MMC
config BCMDHD_PCIE
bool "PCIe bus interface support"
depends on BCMDHD && PCI
config BCMDHD_USB
bool "USB bus interface support"
depends on BCMDHD && USB
endchoice
choice
depends on BCMDHD && BCMDHD_SDIO
prompt "Interrupt type"
default BCMDHD_OOB
---help---
Interrupt type
config BCMDHD_OOB
depends on BCMDHD && BCMDHD_SDIO
bool "Out-of-Band Interrupt"
---help---
Interrupt from WL_HOST_WAKE.
config BCMDHD_SDIO_IRQ
depends on BCMDHD && BCMDHD_SDIO
bool "In-Band Interrupt"
---help---
Interrupt from SDIO DAT[1]
endchoice

View File

@@ -0,0 +1,210 @@
# SPDX-License-Identifier: GPL-2.0
# bcmdhd
MODULE_NAME := bcmdhd_wifi6
CONFIG_BCMDHD_SDIO := y
#CONFIG_BCMDHD_PCIE := y
#CONFIG_BCMDHD_USB := y
CONFIG_BCMDHD_OOB := y
#CONFIG_BCMDHD_CUSB := y
CONFIG_BCMDHD_PROPTXSTATUS := y
CONFIG_BCMDHD_AG := y
#CONFIG_DHD_USE_STATIC_BUF := y
CONFIG_VTS_SUPPORT := y
#CONFIG_BCMDHD_DEBUG := y
CONFIG_MACH_PLATFORM := y
#CONFIG_BCMDHD_DTS := y
DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \
-DBCMDONGLEHOST -DBCMDMA32 -DBCMFILEIMAGE \
-DDHDTHREAD -DDHD_DEBUG -DSHOW_EVENTS -DBCMDBG -DGET_OTP_MAC_ENABLE \
-DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DSUPPORT_PM2_ONLY \
-DKEEP_ALIVE -DPKT_FILTER_SUPPORT -DDHDTCPACK_SUPPRESS \
-DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT \
-DMULTIPLE_SUPPLICANT -DTSQ_MULTIPLIER -DMFP -DDHD_8021X_DUMP \
-DPOWERUP_MAX_RETRY=0 -DIFACE_HANG_FORCE_DEV_CLOSE -DWAIT_DEQUEUE \
-DWL_EXT_IAPSTA -DWL_ESCAN \
-DENABLE_INSMOD_NO_FW_LOAD \
-Idrivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd_wifi6 \
-Idrivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd_wifi6/include
DHDOFILES = aiutils.o siutils.o sbutils.o bcmutils.o bcmwifi_channels.o \
dhd_linux.o dhd_linux_platdev.o dhd_linux_sched.o dhd_pno.o \
dhd_common.o dhd_ip.o dhd_linux_wq.o dhd_custom_gpio.o \
bcmevent.o hndpmu.o linux_osl.o wldev_common.o wl_android.o \
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_config.o wl_event.o wl_android_ext.o wl_escan.o
ifeq ($(BCMDHD_STATIC_IF),y)
DHDCFLAGS += -DWL_STATIC_IF
endif
ifneq ($(CONFIG_WIRELESS_EXT),)
DHDOFILES += wl_iw.o
DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT -DUSE_IW
endif
ifneq ($(CONFIG_CFG80211),)
DHDOFILES += wl_cfg80211.o wl_cfgscan.o wl_cfgp2p.o
DHDOFILES += wl_linux_mon.o wl_cfg_btcoex.o wl_cfgvendor.o
DHDOFILES += dhd_cfg80211.o
DHDCFLAGS += -DWL_CFG80211 -DWLP2P -DWL_CFG80211_STA_EVENT
# DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS
DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=10
DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL
DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES
DHDCFLAGS += -DESCAN_RESULT_PATCH -DESCAN_BUF_OVERFLOW_MGMT
DHDCFLAGS += -DVSDB -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST
DHDCFLAGS += -DWLTDLS -DMIRACAST_AMPDU_SIZE=8
DHDCFLAGS += -DWL_VIRTUAL_APSTA
DHDCFLAGS += -DPNO_SUPPORT -DEXPLICIT_DISCIF_CLEANUP
DHDCFLAGS += -DDHD_USE_SCAN_WAKELOCK
# DHDCFLAGS += -DWL_STATIC_IF
# DHDCFLAGS += -DWL_SAE
endif
#BCMDHD_SDIO
ifneq ($(CONFIG_BCMDHD_SDIO),)
DHDCFLAGS += -DBCMSDIO -DMMC_SDIO_ABORT -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR \
-DSDTEST -DBDC -DDHD_USE_IDLECOUNT -DCUSTOM_SDIO_F2_BLKSIZE=256 \
-DBCMSDIOH_TXGLOM -DBCMSDIOH_TXGLOM_EXT -DRXFRAME_THREAD \
-DDHDENABLE_TAILPAD -DSUPPORT_P2P_GO_PS \
-DBCMSDIO_RXLIM_POST -DCONSOLE_DPC
ifeq ($(CONFIG_BCMDHD_OOB),y)
DHDCFLAGS += -DOOB_INTR_ONLY -DCUSTOMER_OOB -DHW_OOB
ifeq ($(CONFIG_BCMDHD_DISABLE_WOWLAN),y)
DHDCFLAGS += -DDISABLE_WOWLAN
endif
else
DHDCFLAGS += -DSDIO_ISR_THREAD
endif
DHDOFILES += bcmsdh.o bcmsdh_linux.o bcmsdh_sdmmc.o bcmsdh_sdmmc_linux.o \
dhd_sdio.o dhd_cdc.o dhd_wlfc.o
endif
#BCMDHD_PCIE
ifneq ($(CONFIG_BCMDHD_PCIE),)
DHDCFLAGS += -DPCIE_FULL_DONGLE -DBCMPCIE -DCUSTOM_DPC_PRIO_SETTING=-1 \
-DDONGLE_ENABLE_ISOLATION
DHDCFLAGS += -DDHD_LB -DDHD_LB_RXP -DDHD_LB_STATS -DDHD_LB_TXP
DHDCFLAGS += -DDHD_PKTID_AUDIT_ENABLED
ifeq ($(CONFIG_BCMDHD_OOB),y)
DHDCFLAGS += -DCUSTOMER_OOB -DBCMPCIE_OOB_HOST_WAKE
endif
ifneq ($(CONFIG_PCI_MSI),)
DHDCFLAGS += -DDHD_MSI_SUPPORT
endif
DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o \
dhd_msgbuf.o dhd_linux_lb.o
endif
#BCMDHD_USB
ifneq ($(CONFIG_BCMDHD_USB),)
DHDCFLAGS += -DUSBOS_TX_THREAD -DBCMDBUS -DBCMTRXV2 -DDBUS_USB_LOOPBACK \
-DBDC
DHDCFLAGS += -DBCM_REQUEST_FW -DEXTERNAL_FW_PATH
#DHDCFLAGS :=$(filter-out -DENABLE_INSMOD_NO_FW_LOAD,$(DHDCFLAGS))
ifneq ($(CONFIG_BCMDHD_CUSB),)
DHDCFLAGS += -DBCMUSBDEV_COMPOSITE
DHDCFLAGS :=$(filter-out -DENABLE_INSMOD_NO_FW_LOAD,$(DHDCFLAGS))
endif
DHDOFILES += dbus.o dbus_usb.o dbus_usb_linux.o dhd_cdc.o dhd_wlfc.o
endif
#PROPTXSTATUS
ifeq ($(CONFIG_BCMDHD_PROPTXSTATUS),y)
ifneq ($(CONFIG_BCMDHD_USB),)
DHDCFLAGS += -DPROP_TXSTATUS
endif
ifneq ($(CONFIG_BCMDHD_SDIO),)
DHDCFLAGS += -DPROP_TXSTATUS
endif
ifneq ($(CONFIG_CFG80211),)
DHDCFLAGS += -DPROP_TXSTATUS_VSDB
endif
endif
ifeq ($(CONFIG_64BIT),y)
DHDCFLAGS := $(filter-out -DBCMDMA32,$(DHDCFLAGS))
DHDCFLAGS += -DBCMDMA64OSL
endif
#VTS_SUPPORT
ifeq ($(CONFIG_VTS_SUPPORT),y)
ifneq ($(CONFIG_CFG80211),)
DHDCFLAGS += -DGSCAN_SUPPORT -DRTT_SUPPORT -DLINKSTAT_SUPPORT \
-DCUSTOM_COUNTRY_CODE -DDHD_GET_VALID_CHANNELS \
-DDEBUGABILITY -DDBG_PKT_MON -DDHD_LOG_DUMP -DDHD_FW_COREDUMP \
-DAPF -DNDO_CONFIG_SUPPORT -DRSSI_MONITOR_SUPPORT -DDHD_WAKE_STATUS
DHDOFILES += dhd_rtt.o bcm_app_utils.o
endif
endif
# For Debug
ifneq ($(CONFIG_BCMDHD_DEBUG),)
DHDCFLAGS += -DDEBUGFS_CFG80211
DHDCFLAGS += -DSHOW_LOGTRACE -DDHD_LOG_DUMP -DDHD_FW_COREDUMP \
-DBCMASSERT_LOG -DSI_ERROR_ENFORCE
ifneq ($(CONFIG_BCMDHD_PCIE),)
DHDCFLAGS += -DEWP_EDL
DHDCFLAGS += -DDNGL_EVENT_SUPPORT
DHDCFLAGS += -DDHD_SSSR_DUMP
endif
endif
# MESH support for kernel 3.10 later
ifeq ($(CONFIG_WL_MESH),y)
DHDCFLAGS += -DWLMESH
ifneq ($(CONFIG_CFG80211),)
DHDCFLAGS += -DWLMESH_CFG80211
endif
ifneq ($(CONFIG_BCMDHD_PCIE),)
DHDCFLAGS += -DBCM_HOST_BUF -DDMA_HOST_BUFFER_LEN=0x80000
endif
DHDCFLAGS += -DDHD_UPDATE_INTF_MAC
DHDCFLAGS :=$(filter-out -DDHD_FW_COREDUMP,$(DHDCFLAGS))
DHDCFLAGS :=$(filter-out -DWL_STATIC_IF,$(DHDCFLAGS))
endif
ifeq ($(CONFIG_WL_EASYMESH),y)
DHDCFLAGS :=$(filter-out -DDHD_FW_COREDUMP,$(DHDCFLAGS))
DHDCFLAGS :=$(filter-out -DDHD_LOG_DUMP,$(DHDCFLAGS))
DHDCFLAGS += -DWLEASYMESH -DWL_STATIC_IF -DWLDWDS -DFOURADDR_AUTO_BRG
endif
#obj-$(CONFIG_RKWIFI) += $(MODULE_NAME).o
obj-$(CONFIG_AP6XXX_WIFI6) += $(MODULE_NAME).o
$(MODULE_NAME)-objs += $(DHDOFILES)
ifeq ($(CONFIG_MACH_PLATFORM),y)
DHDOFILES += dhd_gpio.o
ifeq ($(CONFIG_BCMDHD_DTS),y)
DHDCFLAGS += -DCONFIG_DTS
else
DHDCFLAGS += -DCUSTOMER_HW -DDHD_OF_SUPPORT
endif
# DHDCFLAGS += -DBCMWAPI_WPI -DBCMWAPI_WAI
endif
ifeq ($(CONFIG_BCMDHD_AG),y)
DHDCFLAGS += -DBAND_AG
endif
ifeq ($(CONFIG_DHD_USE_STATIC_BUF),y)
obj-m += dhd_static_buf.o
DHDCFLAGS += -DSTATIC_WL_PRIV_STRUCT -DENHANCED_STATIC_BUF
DHDCFLAGS += -DCONFIG_DHD_USE_STATIC_BUF
DHDCFLAGS += -DDHD_USE_STATIC_MEMDUMP
endif
EXTRA_CFLAGS = $(DHDCFLAGS)
ifeq ($(CONFIG_BCMDHD),m)
EXTRA_LDFLAGS += --strip-debug
endif
EXTRA_CFLAGS += -Wno-parentheses-equality
EXTRA_CFLAGS += -Wno-unused-const-variable
EXTRA_CFLAGS += -Wno-non-literal-null-conversion

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,243 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Bloom filter support
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmbloom.c 788740 2018-11-13 21:45:01Z $
*/
#include <typedefs.h>
#include <bcmdefs.h>
#include <stdarg.h>
#ifdef BCMDRIVER
#include <osl.h>
#include <bcmutils.h>
#else /* !BCMDRIVER */
#include <stdio.h>
#include <string.h>
#ifndef ASSERT
#define ASSERT(exp)
#endif // endif
#endif /* !BCMDRIVER */
#include <bcmutils.h>
#include <bcmbloom.h>
#define BLOOM_BIT_LEN(_x) ((_x) << 3)
struct bcm_bloom_filter {
void *cb_ctx;
uint max_hash;
bcm_bloom_hash_t *hash; /* array of hash functions */
uint filter_size; /* in bytes */
uint8 *filter; /* can be NULL for validate only */
};
/* public interface */
int
bcm_bloom_create(bcm_bloom_alloc_t alloc_cb,
bcm_bloom_free_t free_cb, void *cb_ctx, uint max_hash,
uint filter_size, bcm_bloom_filter_t **bloom)
{
int err = BCME_OK;
bcm_bloom_filter_t *bp = NULL;
if (!bloom || !alloc_cb || (max_hash == 0)) {
err = BCME_BADARG;
goto done;
}
bp = (*alloc_cb)(cb_ctx, sizeof(*bp));
if (!bp) {
err = BCME_NOMEM;
goto done;
}
memset(bp, 0, sizeof(*bp));
bp->cb_ctx = cb_ctx;
bp->max_hash = max_hash;
bp->hash = (*alloc_cb)(cb_ctx, sizeof(*bp->hash) * max_hash);
memset(bp->hash, 0, sizeof(*bp->hash) * max_hash);
if (!bp->hash) {
err = BCME_NOMEM;
goto done;
}
if (filter_size > 0) {
bp->filter = (*alloc_cb)(cb_ctx, filter_size);
if (!bp->filter) {
err = BCME_NOMEM;
goto done;
}
bp->filter_size = filter_size;
memset(bp->filter, 0, filter_size);
}
*bloom = bp;
done:
if (err != BCME_OK)
bcm_bloom_destroy(&bp, free_cb);
return err;
}
int
bcm_bloom_destroy(bcm_bloom_filter_t **bloom, bcm_bloom_free_t free_cb)
{
int err = BCME_OK;
bcm_bloom_filter_t *bp;
if (!bloom || !*bloom || !free_cb)
goto done;
bp = *bloom;
*bloom = NULL;
if (bp->filter)
(*free_cb)(bp->cb_ctx, bp->filter, bp->filter_size);
if (bp->hash)
(*free_cb)(bp->cb_ctx, bp->hash,
sizeof(*bp->hash) * bp->max_hash);
(*free_cb)(bp->cb_ctx, bp, sizeof(*bp));
done:
return err;
}
int
bcm_bloom_add_hash(bcm_bloom_filter_t *bp, bcm_bloom_hash_t hash, uint *idx)
{
uint i;
if (!bp || !hash || !idx)
return BCME_BADARG;
for (i = 0; i < bp->max_hash; ++i) {
if (bp->hash[i] == NULL)
break;
}
if (i >= bp->max_hash)
return BCME_NORESOURCE;
bp->hash[i] = hash;
*idx = i;
return BCME_OK;
}
int
bcm_bloom_remove_hash(bcm_bloom_filter_t *bp, uint idx)
{
if (!bp)
return BCME_BADARG;
if (idx >= bp->max_hash)
return BCME_NOTFOUND;
bp->hash[idx] = NULL;
return BCME_OK;
}
bool
bcm_bloom_is_member(bcm_bloom_filter_t *bp,
const uint8 *tag, uint tag_len, const uint8 *buf, uint buf_len)
{
uint i;
int err = BCME_OK;
if (!tag || (tag_len == 0)) /* empty tag is always a member */
goto done;
/* use internal buffer if none was specified */
if (!buf || (buf_len == 0)) {
if (!bp->filter) /* every one is a member of empty filter */
goto done;
buf = bp->filter;
buf_len = bp->filter_size;
}
for (i = 0; i < bp->max_hash; ++i) {
uint pos;
if (!bp->hash[i])
continue;
pos = (*bp->hash[i])(bp->cb_ctx, i, tag, tag_len);
/* all bits must be set for a match */
CLANG_DIAGNOSTIC_PUSH_SUPPRESS_CAST()
if (isclr(buf, pos % BLOOM_BIT_LEN(buf_len))) {
CLANG_DIAGNOSTIC_POP()
err = BCME_NOTFOUND;
break;
}
}
done:
return err;
}
int
bcm_bloom_add_member(bcm_bloom_filter_t *bp, const uint8 *tag, uint tag_len)
{
uint i;
if (!bp || !tag || (tag_len == 0))
return BCME_BADARG;
if (!bp->filter) /* validate only */
return BCME_UNSUPPORTED;
for (i = 0; i < bp->max_hash; ++i) {
uint pos;
if (!bp->hash[i])
continue;
pos = (*bp->hash[i])(bp->cb_ctx, i, tag, tag_len);
setbit(bp->filter, pos % BLOOM_BIT_LEN(bp->filter_size));
}
return BCME_OK;
}
int bcm_bloom_get_filter_data(bcm_bloom_filter_t *bp,
uint buf_size, uint8 *buf, uint *buf_len)
{
if (!bp)
return BCME_BADARG;
if (buf_len)
*buf_len = bp->filter_size;
if (buf_size < bp->filter_size)
return BCME_BUFTOOSHORT;
if (bp->filter && bp->filter_size)
memcpy(buf, bp->filter, bp->filter_size);
return BCME_OK;
}

View File

@@ -0,0 +1,396 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* bcmevent read-only data shared by kernel or app layers
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmevent.c 807989 2019-03-05 07:57:42Z $
*/
#include <typedefs.h>
#include <bcmutils.h>
#include <bcmendian.h>
#include <ethernet.h>
#include <bcmeth.h>
#include <bcmevent.h>
#include <802.11.h>
/* Table of event name strings for UIs and debugging dumps */
typedef struct {
uint event;
const char *name;
} bcmevent_name_str_t;
/* Use the actual name for event tracing */
#define BCMEVENT_NAME(_event) {(_event), #_event}
static const bcmevent_name_str_t bcmevent_names[] = {
BCMEVENT_NAME(WLC_E_SET_SSID),
BCMEVENT_NAME(WLC_E_JOIN),
BCMEVENT_NAME(WLC_E_START),
BCMEVENT_NAME(WLC_E_AUTH),
BCMEVENT_NAME(WLC_E_AUTH_IND),
BCMEVENT_NAME(WLC_E_DEAUTH),
BCMEVENT_NAME(WLC_E_DEAUTH_IND),
BCMEVENT_NAME(WLC_E_ASSOC),
BCMEVENT_NAME(WLC_E_ASSOC_IND),
BCMEVENT_NAME(WLC_E_REASSOC),
BCMEVENT_NAME(WLC_E_REASSOC_IND),
BCMEVENT_NAME(WLC_E_DISASSOC),
BCMEVENT_NAME(WLC_E_DISASSOC_IND),
BCMEVENT_NAME(WLC_E_QUIET_START),
BCMEVENT_NAME(WLC_E_QUIET_END),
BCMEVENT_NAME(WLC_E_BEACON_RX),
BCMEVENT_NAME(WLC_E_LINK),
BCMEVENT_NAME(WLC_E_MIC_ERROR),
BCMEVENT_NAME(WLC_E_NDIS_LINK),
BCMEVENT_NAME(WLC_E_ROAM),
BCMEVENT_NAME(WLC_E_TXFAIL),
BCMEVENT_NAME(WLC_E_PMKID_CACHE),
BCMEVENT_NAME(WLC_E_RETROGRADE_TSF),
BCMEVENT_NAME(WLC_E_PRUNE),
BCMEVENT_NAME(WLC_E_AUTOAUTH),
BCMEVENT_NAME(WLC_E_EAPOL_MSG),
BCMEVENT_NAME(WLC_E_SCAN_COMPLETE),
BCMEVENT_NAME(WLC_E_ADDTS_IND),
BCMEVENT_NAME(WLC_E_DELTS_IND),
BCMEVENT_NAME(WLC_E_BCNSENT_IND),
BCMEVENT_NAME(WLC_E_BCNRX_MSG),
BCMEVENT_NAME(WLC_E_BCNLOST_MSG),
BCMEVENT_NAME(WLC_E_ROAM_PREP),
BCMEVENT_NAME(WLC_E_PFN_NET_FOUND),
BCMEVENT_NAME(WLC_E_PFN_SCAN_ALLGONE),
BCMEVENT_NAME(WLC_E_PFN_NET_LOST),
BCMEVENT_NAME(WLC_E_JOIN_START),
BCMEVENT_NAME(WLC_E_ROAM_START),
BCMEVENT_NAME(WLC_E_ASSOC_START),
#if defined(IBSS_PEER_DISCOVERY_EVENT)
BCMEVENT_NAME(WLC_E_IBSS_ASSOC),
#endif /* defined(IBSS_PEER_DISCOVERY_EVENT) */
BCMEVENT_NAME(WLC_E_RADIO),
BCMEVENT_NAME(WLC_E_PSM_WATCHDOG),
BCMEVENT_NAME(WLC_E_PROBREQ_MSG),
BCMEVENT_NAME(WLC_E_SCAN_CONFIRM_IND),
BCMEVENT_NAME(WLC_E_PSK_SUP),
BCMEVENT_NAME(WLC_E_COUNTRY_CODE_CHANGED),
BCMEVENT_NAME(WLC_E_EXCEEDED_MEDIUM_TIME),
BCMEVENT_NAME(WLC_E_ICV_ERROR),
BCMEVENT_NAME(WLC_E_UNICAST_DECODE_ERROR),
BCMEVENT_NAME(WLC_E_MULTICAST_DECODE_ERROR),
BCMEVENT_NAME(WLC_E_TRACE),
BCMEVENT_NAME(WLC_E_IF),
#ifdef WLP2P
BCMEVENT_NAME(WLC_E_P2P_DISC_LISTEN_COMPLETE),
#endif // endif
BCMEVENT_NAME(WLC_E_RSSI),
BCMEVENT_NAME(WLC_E_PFN_SCAN_COMPLETE),
BCMEVENT_NAME(WLC_E_ACTION_FRAME),
BCMEVENT_NAME(WLC_E_ACTION_FRAME_RX),
BCMEVENT_NAME(WLC_E_ACTION_FRAME_COMPLETE),
#ifdef BCMWAPI_WAI
BCMEVENT_NAME(WLC_E_WAI_STA_EVENT),
BCMEVENT_NAME(WLC_E_WAI_MSG),
#endif /* BCMWAPI_WAI */
BCMEVENT_NAME(WLC_E_ESCAN_RESULT),
BCMEVENT_NAME(WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE),
#ifdef WLP2P
BCMEVENT_NAME(WLC_E_PROBRESP_MSG),
BCMEVENT_NAME(WLC_E_P2P_PROBREQ_MSG),
#endif // endif
#ifdef PROP_TXSTATUS
BCMEVENT_NAME(WLC_E_FIFO_CREDIT_MAP),
#endif // endif
BCMEVENT_NAME(WLC_E_WAKE_EVENT),
BCMEVENT_NAME(WLC_E_DCS_REQUEST),
BCMEVENT_NAME(WLC_E_RM_COMPLETE),
BCMEVENT_NAME(WLC_E_OVERLAY_REQ),
BCMEVENT_NAME(WLC_E_CSA_COMPLETE_IND),
BCMEVENT_NAME(WLC_E_EXCESS_PM_WAKE_EVENT),
BCMEVENT_NAME(WLC_E_PFN_SCAN_NONE),
BCMEVENT_NAME(WLC_E_PFN_SCAN_ALLGONE),
#ifdef SOFTAP
BCMEVENT_NAME(WLC_E_GTK_PLUMBED),
#endif // endif
BCMEVENT_NAME(WLC_E_ASSOC_REQ_IE),
BCMEVENT_NAME(WLC_E_ASSOC_RESP_IE),
BCMEVENT_NAME(WLC_E_BEACON_FRAME_RX),
#ifdef WLTDLS
BCMEVENT_NAME(WLC_E_TDLS_PEER_EVENT),
#endif /* WLTDLS */
BCMEVENT_NAME(WLC_E_NATIVE),
#ifdef WLPKTDLYSTAT
BCMEVENT_NAME(WLC_E_PKTDELAY_IND),
#endif /* WLPKTDLYSTAT */
BCMEVENT_NAME(WLC_E_SERVICE_FOUND),
BCMEVENT_NAME(WLC_E_GAS_FRAGMENT_RX),
BCMEVENT_NAME(WLC_E_GAS_COMPLETE),
BCMEVENT_NAME(WLC_E_P2PO_ADD_DEVICE),
BCMEVENT_NAME(WLC_E_P2PO_DEL_DEVICE),
#ifdef WLWNM
BCMEVENT_NAME(WLC_E_WNM_STA_SLEEP),
#endif /* WLWNM */
#if defined(WL_PROXDETECT) || defined(RTT_SUPPORT)
BCMEVENT_NAME(WLC_E_PROXD),
#endif // endif
BCMEVENT_NAME(WLC_E_CCA_CHAN_QUAL),
BCMEVENT_NAME(WLC_E_BSSID),
#ifdef PROP_TXSTATUS
BCMEVENT_NAME(WLC_E_BCMC_CREDIT_SUPPORT),
#endif // endif
BCMEVENT_NAME(WLC_E_PSTA_PRIMARY_INTF_IND),
BCMEVENT_NAME(WLC_E_TXFAIL_THRESH),
#ifdef GSCAN_SUPPORT
BCMEVENT_NAME(WLC_E_PFN_GSCAN_FULL_RESULT),
BCMEVENT_NAME(WLC_E_PFN_SSID_EXT),
#endif /* GSCAN_SUPPORT */
#ifdef WLBSSLOAD_REPORT
BCMEVENT_NAME(WLC_E_BSS_LOAD),
#endif // endif
#if defined(BT_WIFI_HANDOVER) || defined(WL_TBOW)
BCMEVENT_NAME(WLC_E_BT_WIFI_HANDOVER_REQ),
#endif // endif
#ifdef WLFBT
BCMEVENT_NAME(WLC_E_FBT),
#endif /* WLFBT */
BCMEVENT_NAME(WLC_E_AUTHORIZED),
BCMEVENT_NAME(WLC_E_PROBREQ_MSG_RX),
BCMEVENT_NAME(WLC_E_CSA_START_IND),
BCMEVENT_NAME(WLC_E_CSA_DONE_IND),
BCMEVENT_NAME(WLC_E_CSA_FAILURE_IND),
BCMEVENT_NAME(WLC_E_RMC_EVENT),
BCMEVENT_NAME(WLC_E_DPSTA_INTF_IND),
BCMEVENT_NAME(WLC_E_ALLOW_CREDIT_BORROW),
BCMEVENT_NAME(WLC_E_MSCH),
BCMEVENT_NAME(WLC_E_ULP),
BCMEVENT_NAME(WLC_E_NAN),
BCMEVENT_NAME(WLC_E_PKT_FILTER),
BCMEVENT_NAME(WLC_E_DMA_TXFLUSH_COMPLETE),
BCMEVENT_NAME(WLC_E_PSK_AUTH),
BCMEVENT_NAME(WLC_E_SDB_TRANSITION),
BCMEVENT_NAME(WLC_E_PFN_SCAN_BACKOFF),
BCMEVENT_NAME(WLC_E_PFN_BSSID_SCAN_BACKOFF),
BCMEVENT_NAME(WLC_E_AGGR_EVENT),
BCMEVENT_NAME(WLC_E_TVPM_MITIGATION),
#ifdef WL_NAN
BCMEVENT_NAME(WLC_E_NAN_CRITICAL),
BCMEVENT_NAME(WLC_E_NAN_NON_CRITICAL),
BCMEVENT_NAME(WLC_E_NAN),
#endif /* WL_NAN */
BCMEVENT_NAME(WLC_E_RPSNOA),
BCMEVENT_NAME(WLC_E_PHY_CAL),
BCMEVENT_NAME(WLC_E_WA_LQM),
};
const char *bcmevent_get_name(uint event_type)
{
/* note: first coded this as a static const but some
* ROMs already have something called event_name so
* changed it so we don't have a variable for the
* 'unknown string
*/
const char *event_name = NULL;
uint idx;
for (idx = 0; idx < (uint)ARRAYSIZE(bcmevent_names); idx++) {
if (bcmevent_names[idx].event == event_type) {
event_name = bcmevent_names[idx].name;
break;
}
}
/* if we find an event name in the array, return it.
* otherwise return unknown string.
*/
return ((event_name) ? event_name : "Unknown Event");
}
void
wl_event_to_host_order(wl_event_msg_t * evt)
{
/* Event struct members passed from dongle to host are stored in network
* byte order. Convert all members to host-order.
*/
evt->event_type = ntoh32(evt->event_type);
evt->flags = ntoh16(evt->flags);
evt->status = ntoh32(evt->status);
evt->reason = ntoh32(evt->reason);
evt->auth_type = ntoh32(evt->auth_type);
evt->datalen = ntoh32(evt->datalen);
evt->version = ntoh16(evt->version);
}
void
wl_event_to_network_order(wl_event_msg_t * evt)
{
/* Event struct members passed from dongle to host are stored in network
* byte order. Convert all members to host-order.
*/
evt->event_type = hton32(evt->event_type);
evt->flags = hton16(evt->flags);
evt->status = hton32(evt->status);
evt->reason = hton32(evt->reason);
evt->auth_type = hton32(evt->auth_type);
evt->datalen = hton32(evt->datalen);
evt->version = hton16(evt->version);
}
/*
* Validate if the event is proper and if valid copy event header to event.
* If proper event pointer is passed, to just validate, pass NULL to event.
*
* Return values are
* BCME_OK - It is a BRCM event or BRCM dongle event
* BCME_NOTFOUND - Not BRCM, not an event, may be okay
* BCME_BADLEN - Bad length, should not process, just drop
*/
int
is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype,
bcm_event_msg_u_t *out_event)
{
uint16 evlen = 0; /* length in bcmeth_hdr */
uint16 subtype;
uint16 usr_subtype;
bcm_event_t *bcm_event;
uint8 *pktend;
uint8 *evend;
int err = BCME_OK;
uint32 data_len = 0; /* data length in bcm_event */
pktend = (uint8 *)pktdata + pktlen;
bcm_event = (bcm_event_t *)pktdata;
/* only care about 16-bit subtype / length versions */
if ((uint8 *)&bcm_event->bcm_hdr < pktend) {
uint8 short_subtype = *(uint8 *)&bcm_event->bcm_hdr;
if (!(short_subtype & 0x80)) {
err = BCME_NOTFOUND;
goto done;
}
}
/* must have both ether_header and bcmeth_hdr */
if (pktlen < OFFSETOF(bcm_event_t, event)) {
err = BCME_BADLEN;
goto done;
}
/* check length in bcmeth_hdr */
/* temporary - header length not always set properly. When the below
* !BCMDONGLEHOST is in all branches that use trunk DHD, the code
* under BCMDONGLEHOST can be removed.
*/
evlen = (uint16)(pktend - (uint8 *)&bcm_event->bcm_hdr.version);
evend = (uint8 *)&bcm_event->bcm_hdr.version + evlen;
if (evend != pktend) {
err = BCME_BADLEN;
goto done;
}
/* match on subtype, oui and usr subtype for BRCM events */
subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.subtype);
if (subtype != BCMILCP_SUBTYPE_VENDOR_LONG) {
err = BCME_NOTFOUND;
goto done;
}
if (bcmp(BRCM_OUI, &bcm_event->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
err = BCME_NOTFOUND;
goto done;
}
/* if it is a bcm_event or bcm_dngl_event_t, validate it */
usr_subtype = ntoh16_ua((void *)&bcm_event->bcm_hdr.usr_subtype);
switch (usr_subtype) {
case BCMILCP_BCM_SUBTYPE_EVENT:
/* check that header length and pkt length are sufficient */
if ((pktlen < sizeof(bcm_event_t)) ||
(evend < ((uint8 *)bcm_event + sizeof(bcm_event_t)))) {
err = BCME_BADLEN;
goto done;
}
/* ensure data length in event is not beyond the packet. */
data_len = ntoh32_ua((void *)&bcm_event->event.datalen);
if ((sizeof(bcm_event_t) + data_len +
BCMILCP_BCM_SUBTYPE_EVENT_DATA_PAD) != pktlen) {
err = BCME_BADLEN;
goto done;
}
if (exp_usr_subtype && (exp_usr_subtype != usr_subtype)) {
err = BCME_NOTFOUND;
goto done;
}
if (out_event) {
/* ensure BRCM event pkt aligned */
memcpy(&out_event->event, &bcm_event->event, sizeof(wl_event_msg_t));
}
break;
case BCMILCP_BCM_SUBTYPE_DNGLEVENT:
#if defined(DNGL_EVENT_SUPPORT)
if ((pktlen < sizeof(bcm_dngl_event_t)) ||
(evend < ((uint8 *)bcm_event + sizeof(bcm_dngl_event_t)))) {
err = BCME_BADLEN;
goto done;
}
/* ensure data length in event is not beyond the packet. */
data_len = ntoh16_ua((void *)&((bcm_dngl_event_t *)pktdata)->dngl_event.datalen);
if ((sizeof(bcm_dngl_event_t) + data_len +
BCMILCP_BCM_SUBTYPE_EVENT_DATA_PAD) != pktlen) {
err = BCME_BADLEN;
goto done;
}
if (exp_usr_subtype && (exp_usr_subtype != usr_subtype)) {
err = BCME_NOTFOUND;
goto done;
}
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));
}
break;
#else
err = BCME_UNSUPPORTED;
break;
#endif // endif
default:
err = BCME_NOTFOUND;
goto done;
}
BCM_REFERENCE(data_len);
done:
return err;
}

View File

@@ -0,0 +1,884 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* BCMSDH interface glue
* implement bcmsdh API for SDIOH driver
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmsdh.c 727623 2017-10-21 01:00:32Z $
*/
/**
* @file bcmsdh.c
*/
/* ****************** BCMSDH Interface Functions *************************** */
#include <typedefs.h>
#include <bcmdevs.h>
#include <bcmendian.h>
#include <bcmutils.h>
#include <hndsoc.h>
#include <siutils.h>
#include <osl.h>
#include <bcmsdh.h> /* BRCM API for SDIO clients (such as wl, dhd) */
#include <bcmsdbus.h> /* common SDIO/controller interface */
#include <sbsdio.h> /* SDIO device core hardware definitions. */
#include <sdio.h> /* SDIO Device and Protocol Specs */
#if defined(BT_OVER_SDIO)
#include <dhd_bt_interface.h>
#endif /* defined (BT_OVER_SDIO) */
#define SDIOH_API_ACCESS_RETRY_LIMIT 2
const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL;
/* local copy of bcm sd handler */
bcmsdh_info_t * l_bcmsdh = NULL;
#if defined(BT_OVER_SDIO)
struct sdio_func *func_f3 = NULL;
static f3intr_handler processf3intr = NULL;
static dhd_hang_notification process_dhd_hang_notification = NULL;
static dhd_hang_state_t g_dhd_hang_state = NO_HANG_STATE;
#endif /* defined (BT_OVER_SDIO) */
#if defined(OOB_INTR_ONLY) && defined(HW_OOB) || defined(FORCE_WOWLAN)
extern int
sdioh_enable_hw_oob_intr(void *sdioh, bool enable);
void
bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable)
{
sdioh_enable_hw_oob_intr(sdh->sdioh, enable);
}
#endif // endif
#if defined(BT_OVER_SDIO)
void bcmsdh_btsdio_process_hang_state(dhd_hang_state_t new_state)
{
bool state_change = false;
BCMSDH_ERROR(("%s: DHD hang state changed - [%d] -> [%d]\n",
__FUNCTION__, g_dhd_hang_state, new_state));
if (g_dhd_hang_state == new_state)
return;
switch (g_dhd_hang_state) {
case NO_HANG_STATE:
if (HANG_START_STATE == new_state)
state_change = true;
break;
case HANG_START_STATE:
if (HANG_RECOVERY_STATE == new_state ||
NO_HANG_STATE == new_state)
state_change = true;
break;
case HANG_RECOVERY_STATE:
if (NO_HANG_STATE == new_state)
state_change = true;
break;
default:
BCMSDH_ERROR(("%s: Unhandled Hang state\n", __FUNCTION__));
break;
}
if (!state_change) {
BCMSDH_ERROR(("%s: Hang state cannot be changed\n", __FUNCTION__));
return;
}
g_dhd_hang_state = new_state;
}
void bcmsdh_btsdio_process_f3_intr(void)
{
if (processf3intr && (g_dhd_hang_state == NO_HANG_STATE))
processf3intr(func_f3);
}
void bcmsdh_btsdio_process_dhd_hang_notification(bool wifi_recovery_completed)
{
bcmsdh_btsdio_process_hang_state(HANG_START_STATE);
if (process_dhd_hang_notification)
process_dhd_hang_notification(func_f3, wifi_recovery_completed);
/* WiFi was off, so HANG_RECOVERY_STATE is not needed */
if (wifi_recovery_completed)
bcmsdh_btsdio_process_hang_state(NO_HANG_STATE);
else {
bcmsdh_btsdio_process_hang_state(HANG_RECOVERY_STATE);
}
}
void bcmsdh_btsdio_interface_init(struct sdio_func *func,
f3intr_handler f3intr_fun, dhd_hang_notification hang_notification)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)l_bcmsdh;
BCMSDH_INFO(("%s: func %p \n", __FUNCTION__, func));
func_f3 = func;
processf3intr = f3intr_fun;
sdioh_sdmmc_card_enable_func_f3(bcmsdh->sdioh, func);
process_dhd_hang_notification = hang_notification;
} EXPORT_SYMBOL(bcmsdh_btsdio_interface_init);
#endif /* defined (BT_OVER_SDIO) */
/* Attach BCMSDH layer to SDIO Host Controller Driver
*
* @param osh OSL Handle.
* @param cfghdl Configuration Handle.
* @param regsva Virtual address of controller registers.
* @param irq Interrupt number of SDIO controller.
*
* @return bcmsdh_info_t Handle to BCMSDH context.
*/
bcmsdh_info_t *
bcmsdh_attach(osl_t *osh, void *sdioh, ulong *regsva)
{
bcmsdh_info_t *bcmsdh;
if ((bcmsdh = (bcmsdh_info_t *)MALLOC(osh, sizeof(bcmsdh_info_t))) == NULL) {
BCMSDH_ERROR(("bcmsdh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
return NULL;
}
bzero((char *)bcmsdh, sizeof(bcmsdh_info_t));
bcmsdh->sdioh = sdioh;
bcmsdh->osh = osh;
bcmsdh->init_success = TRUE;
*regsva = si_enum_base(0);
bcmsdh_force_sbwad_calc(bcmsdh, FALSE);
/* Report the BAR, to fix if needed */
bcmsdh->sbwad = si_enum_base(0);
/* save the handler locally */
l_bcmsdh = bcmsdh;
return bcmsdh;
}
int
bcmsdh_detach(osl_t *osh, void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
if (bcmsdh != NULL) {
MFREE(osh, bcmsdh, sizeof(bcmsdh_info_t));
}
l_bcmsdh = NULL;
return 0;
}
int
bcmsdh_iovar_op(void *sdh, const char *name,
void *params, uint plen, void *arg, uint len, bool set)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
return sdioh_iovar_op(bcmsdh->sdioh, name, params, plen, arg, len, set);
}
bool
bcmsdh_intr_query(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
bool on;
ASSERT(bcmsdh);
status = sdioh_interrupt_query(bcmsdh->sdioh, &on);
if (SDIOH_API_SUCCESS(status))
return FALSE;
else
return on;
}
int
bcmsdh_intr_enable(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
#ifdef BCMSPI_ANDROID
uint32 data;
#endif /* BCMSPI_ANDROID */
ASSERT(bcmsdh);
status = sdioh_interrupt_set(bcmsdh->sdioh, TRUE);
#ifdef BCMSPI_ANDROID
data = bcmsdh_cfg_read_word(sdh, 0, 4, NULL);
data |= 0xE0E70000;
bcmsdh_cfg_write_word(sdh, 0, 4, data, NULL);
#endif /* BCMSPI_ANDROID */
return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
}
int
bcmsdh_intr_disable(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
#ifdef BCMSPI_ANDROID
uint32 data;
#endif /* BCMSPI_ANDROID */
ASSERT(bcmsdh);
status = sdioh_interrupt_set(bcmsdh->sdioh, FALSE);
#ifdef BCMSPI_ANDROID
data = bcmsdh_cfg_read_word(sdh, 0, 4, NULL);
data &= ~0xE0E70000;
bcmsdh_cfg_write_word(sdh, 0, 4, data, NULL);
#endif /* BCMSPI_ANDROID */
return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
}
int
bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh);
status = sdioh_interrupt_register(bcmsdh->sdioh, fn, argh);
return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
}
int
bcmsdh_intr_dereg(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh);
status = sdioh_interrupt_deregister(bcmsdh->sdioh);
return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
}
#if defined(DHD_DEBUG)
bool
bcmsdh_intr_pending(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
ASSERT(sdh);
return sdioh_interrupt_pending(bcmsdh->sdioh);
}
#endif // endif
int
bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh)
{
ASSERT(sdh);
/* don't support yet */
return BCME_UNSUPPORTED;
}
/**
* Read from SDIO Configuration Space
* @param sdh SDIO Host context.
* @param func_num Function number to read from.
* @param addr Address to read from.
* @param err Error return.
* @return value read from SDIO configuration space.
*/
uint8
bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
int32 retry = 0;
#endif // endif
uint8 data = 0;
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh->init_success);
#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
do {
if (retry) /* wait for 1 ms till bus get settled down */
OSL_DELAY(1000);
#endif // endif
status = sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data);
#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
} while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
#endif // endif
if (err)
*err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__,
fnc_num, addr, data));
return data;
} EXPORT_SYMBOL(bcmsdh_cfg_read);
void
bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
int32 retry = 0;
#endif // endif
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh->init_success);
#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
do {
if (retry) /* wait for 1 ms till bus get settled down */
OSL_DELAY(1000);
#endif // endif
status = sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data);
#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
} while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
#endif // endif
if (err)
*err = SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR;
BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__,
fnc_num, addr, data));
} EXPORT_SYMBOL(bcmsdh_cfg_write);
uint32
bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
uint32 data = 0;
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh->init_success);
status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_READ, fnc_num,
addr, &data, 4);
if (err)
*err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__,
fnc_num, addr, data));
return data;
}
void
bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh->init_success);
status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, fnc_num,
addr, &data, 4);
if (err)
*err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, fnc_num,
addr, data));
}
int
bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
uint8 *tmp_buf, *tmp_ptr;
uint8 *ptr;
bool ascii = func & ~0xf;
func &= 0x7;
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh->init_success);
ASSERT(cis);
ASSERT(length <= SBSDIO_CIS_SIZE_LIMIT);
status = sdioh_cis_read(bcmsdh->sdioh, func, cis, length);
if (ascii) {
/* Move binary bits to tmp and format them into the provided buffer. */
if ((tmp_buf = (uint8 *)MALLOC(bcmsdh->osh, length)) == NULL) {
BCMSDH_ERROR(("%s: out of memory\n", __FUNCTION__));
return BCME_NOMEM;
}
bcopy(cis, tmp_buf, length);
for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4); tmp_ptr++) {
ptr += snprintf((char*)ptr, (cis + length - ptr - 4),
"%.2x ", *tmp_ptr & 0xff);
if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0)
ptr += snprintf((char *)ptr, (cis + length - ptr -4), "\n");
}
MFREE(bcmsdh->osh, tmp_buf, length);
}
return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
}
int
bcmsdh_cisaddr_read(void *sdh, uint func, uint8 *cisd, uint32 offset)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
func &= 0x7;
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh->init_success);
ASSERT(cisd);
status = sdioh_cisaddr_read(bcmsdh->sdioh, func, cisd, offset);
return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
}
int
bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set)
{
int err = 0;
uint bar0 = address & ~SBSDIO_SB_OFT_ADDR_MASK;
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
if (bar0 != bcmsdh->sbwad || force_set) {
bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
(address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
if (!err)
bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
(address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
if (!err)
bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
(address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
if (!err)
bcmsdh->sbwad = bar0;
else
/* invalidate cached window var */
bcmsdh->sbwad = 0;
}
return err;
}
uint32
bcmsdh_reg_read(void *sdh, uintptr addr, uint size)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
uint32 word = 0;
BCMSDH_INFO(("%s:fun = 1, addr = 0x%x\n", __FUNCTION__, (unsigned int)addr));
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh->init_success);
if (bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, bcmsdh->force_sbwad_calc)) {
bcmsdh->regfail = TRUE; // terence 20130621: prevent dhd_dpc in dead lock
return 0xFFFFFFFF;
}
addr &= SBSDIO_SB_OFT_ADDR_MASK;
if (size == 4)
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL,
SDIOH_READ, SDIO_FUNC_1, addr, &word, size);
bcmsdh->regfail = !(SDIOH_API_SUCCESS(status));
BCMSDH_INFO(("uint32data = 0x%x\n", word));
/* if ok, return appropriately masked word */
if (SDIOH_API_SUCCESS(status)) {
switch (size) {
case sizeof(uint8):
return (word & 0xff);
case sizeof(uint16):
return (word & 0xffff);
case sizeof(uint32):
return word;
default:
bcmsdh->regfail = TRUE;
}
}
/* otherwise, bad sdio access or invalid size */
BCMSDH_ERROR(("%s: error reading addr 0x%x size %d\n",
__FUNCTION__, (unsigned int)addr, size));
return 0xFFFFFFFF;
}
uint32
bcmsdh_reg_write(void *sdh, uintptr addr, uint size, uint32 data)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
int err = 0;
BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
__FUNCTION__, (unsigned int)addr, size*8, data));
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh->init_success);
if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, bcmsdh->force_sbwad_calc))) {
bcmsdh->regfail = TRUE; // terence 20130621:
return err;
}
addr &= SBSDIO_SB_OFT_ADDR_MASK;
if (size == 4)
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, SDIO_FUNC_1,
addr, &data, size);
bcmsdh->regfail = !(SDIOH_API_SUCCESS(status));
if (SDIOH_API_SUCCESS(status))
return 0;
BCMSDH_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n",
__FUNCTION__, data, (unsigned int)addr, size));
return 0xFFFFFFFF;
}
bool
bcmsdh_regfail(void *sdh)
{
return ((bcmsdh_info_t *)sdh)->regfail;
}
int
bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags,
uint8 *buf, uint nbytes, void *pkt,
bcmsdh_cmplt_fn_t complete_fn, void *handle)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
uint incr_fix;
uint width;
int err = 0;
ASSERT(bcmsdh);
ASSERT(bcmsdh->init_success);
BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
__FUNCTION__, fn, addr, nbytes));
/* Async not implemented yet */
ASSERT(!(flags & SDIO_REQ_ASYNC));
if (flags & SDIO_REQ_ASYNC)
return BCME_UNSUPPORTED;
if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)))
return err;
addr &= SBSDIO_SB_OFT_ADDR_MASK;
incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
if (width == 4)
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix,
SDIOH_READ, fn, addr, width, nbytes, buf, pkt);
return (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
}
int
bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags,
uint8 *buf, uint nbytes, void *pkt,
bcmsdh_cmplt_fn_t complete_fn, void *handle)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
uint incr_fix;
uint width;
int err = 0;
ASSERT(bcmsdh);
ASSERT(bcmsdh->init_success);
BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
__FUNCTION__, fn, addr, nbytes));
/* Async not implemented yet */
ASSERT(!(flags & SDIO_REQ_ASYNC));
if (flags & SDIO_REQ_ASYNC)
return BCME_UNSUPPORTED;
if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)))
return err;
addr &= SBSDIO_SB_OFT_ADDR_MASK;
incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
if (width == 4)
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix,
SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt);
return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
}
int
bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
SDIOH_API_RC status;
ASSERT(bcmsdh);
ASSERT(bcmsdh->init_success);
ASSERT((addr & SBSDIO_SBWINDOW_MASK) == 0);
addr &= SBSDIO_SB_OFT_ADDR_MASK;
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, SDIOH_DATA_INC,
(rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1,
addr, 4, nbytes, buf, NULL);
return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
}
int
bcmsdh_abort(void *sdh, uint fn)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
return sdioh_abort(bcmsdh->sdioh, fn);
}
int
bcmsdh_start(void *sdh, int stage)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
return sdioh_start(bcmsdh->sdioh, stage);
}
int
bcmsdh_stop(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
return sdioh_stop(bcmsdh->sdioh);
}
int
bcmsdh_waitlockfree(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
return sdioh_waitlockfree(bcmsdh->sdioh);
}
int
bcmsdh_query_device(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0;
return (bcmsdh->vendevid);
}
uint
bcmsdh_query_iofnum(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
if (!bcmsdh)
bcmsdh = l_bcmsdh;
return (sdioh_query_iofnum(bcmsdh->sdioh));
}
int
bcmsdh_reset(bcmsdh_info_t *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
return sdioh_sdio_reset(bcmsdh->sdioh);
}
void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh)
{
ASSERT(sdh);
return sdh->sdioh;
}
/* Function to pass device-status bits to DHD. */
uint32
bcmsdh_get_dstatus(void *sdh)
{
#ifdef BCMSPI
bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
return sdioh_get_dstatus(sd);
#else
return 0;
#endif /* BCMSPI */
}
uint32
bcmsdh_cur_sbwad(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
if (!bcmsdh)
bcmsdh = l_bcmsdh;
return (bcmsdh->sbwad);
}
/* example usage: if force is TRUE, forces the bcmsdhsdio_set_sbaddr_window to
* calculate sbwad always instead of caching.
*/
void
bcmsdh_force_sbwad_calc(void *sdh, bool force)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
if (!bcmsdh)
bcmsdh = l_bcmsdh;
bcmsdh->force_sbwad_calc = force;
}
void
bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev)
{
#ifdef BCMSPI
bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
sdioh_chipinfo(sd, chip, chiprev);
#else
return;
#endif /* BCMSPI */
}
#ifdef BCMSPI
void
bcmsdh_dwordmode(void *sdh, bool set)
{
bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
sdioh_dwordmode(sd, set);
return;
}
#endif /* BCMSPI */
int
bcmsdh_sleep(void *sdh, bool enab)
{
#ifdef SDIOH_SLEEP_ENABLED
bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
return sdioh_sleep(sd, enab);
#else
return BCME_UNSUPPORTED;
#endif // endif
}
int
bcmsdh_gpio_init(void *sdh)
{
bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
return sdioh_gpio_init(sd);
}
bool
bcmsdh_gpioin(void *sdh, uint32 gpio)
{
bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
return sdioh_gpioin(sd, gpio);
}
int
bcmsdh_gpioouten(void *sdh, uint32 gpio)
{
bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
return sdioh_gpioouten(sd, gpio);
}
int
bcmsdh_gpioout(void *sdh, uint32 gpio, bool enab)
{
bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
return sdioh_gpioout(sd, gpio, enab);
}
uint
bcmsdh_set_mode(void *sdh, uint mode)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
return (sdioh_set_mode(bcmsdh->sdioh, mode));
}

View File

@@ -0,0 +1,524 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* SDIO access interface for drivers - linux specific (pci only)
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmsdh_linux.c 689948 2017-03-14 05:21:03Z $
*/
/**
* @file bcmsdh_linux.c
*/
#define __UNDEF_NO_VERSION__
#include <typedefs.h>
#include <linuxver.h>
#include <linux/pci.h>
#include <linux/completion.h>
#include <osl.h>
#include <pcicfg.h>
#include <bcmdefs.h>
#include <bcmdevs.h>
#include <linux/irq.h>
extern void dhdsdio_isr(void * args);
#include <bcmutils.h>
#include <dngl_stats.h>
#include <dhd.h>
#include <dhd_linux.h>
/* driver info, initialized when bcmsdh_register is called */
static bcmsdh_driver_t drvinfo = {NULL, NULL, NULL, NULL};
typedef enum {
DHD_INTR_INVALID = 0,
DHD_INTR_INBAND,
DHD_INTR_HWOOB,
DHD_INTR_SWOOB
} DHD_HOST_INTR_TYPE;
/* the BCMSDH module comprises the generic part (bcmsdh.c) and OS specific layer (e.g.
* bcmsdh_linux.c). Put all OS specific variables (e.g. irq number and flags) here rather
* than in the common structure bcmsdh_info. bcmsdh_info only keeps a handle (os_ctx) to this
* structure.
*/
typedef struct bcmsdh_os_info {
DHD_HOST_INTR_TYPE intr_type;
int oob_irq_num; /* valid when hardware or software oob in use */
unsigned long oob_irq_flags; /* valid when hardware or software oob in use */
bool oob_irq_registered;
bool oob_irq_enabled;
bool oob_irq_wake_enabled;
spinlock_t oob_irq_spinlock;
bcmsdh_cb_fn_t oob_irq_handler;
void *oob_irq_handler_context;
void *context; /* context returned from upper layer */
void *sdioh; /* handle to lower layer (sdioh) */
void *dev; /* handle to the underlying device */
bool dev_wake_enabled;
} bcmsdh_os_info_t;
/* debugging macros */
#define SDLX_ERR(x) printf x
#define SDLX_MSG(x) printf x
/**
* Checks to see if vendor and device IDs match a supported SDIO Host Controller.
*/
bool
bcmsdh_chipmatch(uint16 vendor, uint16 device)
{
/* Add other vendors and devices as required */
#ifdef BCMSDIOH_STD
/* Check for Arasan host controller */
if (vendor == VENDOR_SI_IMAGE) {
return (TRUE);
}
/* Check for BRCM 27XX Standard host controller */
if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) {
return (TRUE);
}
/* Check for BRCM Standard host controller */
if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) {
return (TRUE);
}
/* Check for TI PCIxx21 Standard host controller */
if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) {
return (TRUE);
}
if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) {
return (TRUE);
}
/* Ricoh R5C822 Standard SDIO Host */
if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) {
return (TRUE);
}
/* JMicron Standard SDIO Host */
if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) {
return (TRUE);
}
#endif /* BCMSDIOH_STD */
#ifdef BCMSDIOH_SPI
/* This is the PciSpiHost. */
if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) {
printf("Found PCI SPI Host Controller\n");
return (TRUE);
}
#endif /* BCMSDIOH_SPI */
return (FALSE);
}
void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type,
uint bus_num, uint slot_num)
{
ulong regs;
bcmsdh_info_t *bcmsdh;
uint32 vendevid;
bcmsdh_os_info_t *bcmsdh_osinfo = NULL;
bcmsdh = bcmsdh_attach(osh, sdioh, &regs);
if (bcmsdh == NULL) {
SDLX_ERR(("%s: bcmsdh_attach failed\n", __FUNCTION__));
goto err;
}
bcmsdh_osinfo = MALLOC(osh, sizeof(bcmsdh_os_info_t));
if (bcmsdh_osinfo == NULL) {
SDLX_ERR(("%s: failed to allocate bcmsdh_os_info_t\n", __FUNCTION__));
goto err;
}
bzero((char *)bcmsdh_osinfo, sizeof(bcmsdh_os_info_t));
bcmsdh->os_cxt = bcmsdh_osinfo;
bcmsdh_osinfo->sdioh = sdioh;
bcmsdh_osinfo->dev = dev;
osl_set_bus_handle(osh, bcmsdh);
#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
if (dev && device_init_wakeup(dev, true) == 0)
bcmsdh_osinfo->dev_wake_enabled = TRUE;
#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */
#if defined(OOB_INTR_ONLY)
spin_lock_init(&bcmsdh_osinfo->oob_irq_spinlock);
/* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */
bcmsdh_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter_info,
&bcmsdh_osinfo->oob_irq_flags);
if (bcmsdh_osinfo->oob_irq_num < 0) {
SDLX_ERR(("%s: Host OOB irq is not defined\n", __FUNCTION__));
goto err;
}
#endif /* defined(BCMLXSDMMC) */
/* Read the vendor/device ID from the CIS */
vendevid = bcmsdh_query_device(bcmsdh);
/* try to attach to the target device */
bcmsdh_osinfo->context = drvinfo.probe((vendevid >> 16), (vendevid & 0xFFFF), bus_num,
slot_num, 0, bus_type, (void *)regs, osh, bcmsdh);
if (bcmsdh_osinfo->context == NULL) {
SDLX_ERR(("%s: device attach failed\n", __FUNCTION__));
goto err;
}
return bcmsdh;
/* error handling */
err:
if (bcmsdh != NULL)
bcmsdh_detach(osh, bcmsdh);
if (bcmsdh_osinfo != NULL)
MFREE(osh, bcmsdh_osinfo, sizeof(bcmsdh_os_info_t));
return NULL;
}
int bcmsdh_remove(bcmsdh_info_t *bcmsdh)
{
bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
if (bcmsdh_osinfo->dev)
device_init_wakeup(bcmsdh_osinfo->dev, false);
bcmsdh_osinfo->dev_wake_enabled = FALSE;
#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */
drvinfo.remove(bcmsdh_osinfo->context);
MFREE(bcmsdh->osh, bcmsdh->os_cxt, sizeof(bcmsdh_os_info_t));
bcmsdh_detach(bcmsdh->osh, bcmsdh);
return 0;
}
#ifdef DHD_WAKE_STATUS
int bcmsdh_get_total_wake(bcmsdh_info_t *bcmsdh)
{
return bcmsdh->total_wake_count;
}
int bcmsdh_set_get_wake(bcmsdh_info_t *bcmsdh, int flag)
{
#if defined(OOB_INTR_ONLY)
bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
unsigned long flags;
#endif
int ret = 0;
#if defined(OOB_INTR_ONLY)
spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags);
ret = bcmsdh->pkt_wake;
bcmsdh->total_wake_count += flag;
bcmsdh->pkt_wake = flag;
spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags);
#endif
return ret;
}
#endif /* DHD_WAKE_STATUS */
int bcmsdh_suspend(bcmsdh_info_t *bcmsdh)
{
bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
if (drvinfo.suspend && drvinfo.suspend(bcmsdh_osinfo->context))
return -EBUSY;
return 0;
}
int bcmsdh_resume(bcmsdh_info_t *bcmsdh)
{
bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
if (drvinfo.resume)
return drvinfo.resume(bcmsdh_osinfo->context);
return 0;
}
extern int bcmsdh_register_client_driver(void);
extern void bcmsdh_unregister_client_driver(void);
extern int sdio_func_reg_notify(void* semaphore);
extern void sdio_func_unreg_notify(void);
#if defined(BCMLXSDMMC)
int bcmsdh_reg_sdio_notify(void* semaphore)
{
return sdio_func_reg_notify(semaphore);
}
void bcmsdh_unreg_sdio_notify(void)
{
sdio_func_unreg_notify();
}
#endif /* defined(BCMLXSDMMC) */
int
bcmsdh_register(bcmsdh_driver_t *driver)
{
int error = 0;
drvinfo = *driver;
SDLX_MSG(("%s: register client driver\n", __FUNCTION__));
error = bcmsdh_register_client_driver();
if (error)
SDLX_ERR(("%s: failed %d\n", __FUNCTION__, error));
return error;
}
void
bcmsdh_unregister(void)
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
if (bcmsdh_pci_driver.node.next == NULL)
return;
#endif // endif
bcmsdh_unregister_client_driver();
}
void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *bcmsdh)
{
#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
pm_stay_awake(bcmsdh_osinfo->dev);
#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */
}
void bcmsdh_dev_relax(bcmsdh_info_t *bcmsdh)
{
#if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
pm_relax(bcmsdh_osinfo->dev);
#endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */
}
bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *bcmsdh)
{
bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
return bcmsdh_osinfo->dev_wake_enabled;
}
#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
void bcmsdh_oob_intr_set(bcmsdh_info_t *bcmsdh, bool enable)
{
unsigned long flags;
bcmsdh_os_info_t *bcmsdh_osinfo;
if (!bcmsdh)
return;
bcmsdh_osinfo = bcmsdh->os_cxt;
spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags);
if (bcmsdh_osinfo->oob_irq_enabled != enable) {
if (enable)
enable_irq(bcmsdh_osinfo->oob_irq_num);
else
disable_irq_nosync(bcmsdh_osinfo->oob_irq_num);
bcmsdh_osinfo->oob_irq_enabled = enable;
}
spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags);
}
static irqreturn_t wlan_oob_irq(int irq, void *dev_id)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)dev_id;
bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
#ifndef BCMSPI_ANDROID
bcmsdh_oob_intr_set(bcmsdh, FALSE);
#endif /* !BCMSPI_ANDROID */
bcmsdh_osinfo->oob_irq_handler(bcmsdh_osinfo->oob_irq_handler_context);
return IRQ_HANDLED;
}
int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handler,
void* oob_irq_handler_context)
{
int err = 0;
bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
if (bcmsdh_osinfo->oob_irq_registered) {
SDLX_ERR(("%s: irq is already registered\n", __FUNCTION__));
return -EBUSY;
}
#ifdef HW_OOB
SDLX_MSG(("%s: HW_OOB irq=%d flags=0x%X\n", __FUNCTION__,
(int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags));
#else
SDLX_MSG(("%s: SW_OOB irq=%d flags=0x%X\n", __FUNCTION__,
(int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags));
#endif
bcmsdh_osinfo->oob_irq_handler = oob_irq_handler;
bcmsdh_osinfo->oob_irq_handler_context = oob_irq_handler_context;
bcmsdh_osinfo->oob_irq_enabled = TRUE;
bcmsdh_osinfo->oob_irq_registered = TRUE;
err = request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq,
bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh);
if (err) {
SDLX_ERR(("%s: request_irq failed with %d\n", __FUNCTION__, err));
bcmsdh_osinfo->oob_irq_enabled = FALSE;
bcmsdh_osinfo->oob_irq_registered = FALSE;
return err;
}
#if defined(DISABLE_WOWLAN)
SDLX_MSG(("%s: disable_irq_wake\n", __FUNCTION__));
bcmsdh_osinfo->oob_irq_wake_enabled = FALSE;
#else
#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
if (device_may_wakeup(bcmsdh_osinfo->dev)) {
#endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
err = enable_irq_wake(bcmsdh_osinfo->oob_irq_num);
if (err)
SDLX_ERR(("%s: enable_irq_wake failed with %d\n", __FUNCTION__, err));
else
bcmsdh_osinfo->oob_irq_wake_enabled = TRUE;
#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
}
#endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
#endif
return 0;
}
void bcmsdh_oob_intr_unregister(bcmsdh_info_t *bcmsdh)
{
int err = 0;
bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
SDLX_MSG(("%s: Enter\n", __FUNCTION__));
if (!bcmsdh_osinfo->oob_irq_registered) {
SDLX_MSG(("%s: irq is not registered\n", __FUNCTION__));
return;
}
if (bcmsdh_osinfo->oob_irq_wake_enabled) {
#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
if (device_may_wakeup(bcmsdh_osinfo->dev)) {
#endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
err = disable_irq_wake(bcmsdh_osinfo->oob_irq_num);
if (!err)
bcmsdh_osinfo->oob_irq_wake_enabled = FALSE;
#if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
}
#endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
}
if (bcmsdh_osinfo->oob_irq_enabled) {
disable_irq(bcmsdh_osinfo->oob_irq_num);
bcmsdh_osinfo->oob_irq_enabled = FALSE;
}
free_irq(bcmsdh_osinfo->oob_irq_num, bcmsdh);
bcmsdh_osinfo->oob_irq_registered = FALSE;
}
#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
/* Module parameters specific to each host-controller driver */
extern uint sd_msglevel; /* Debug message level */
module_param(sd_msglevel, uint, 0);
extern uint sd_power; /* 0 = SD Power OFF, 1 = SD Power ON. */
module_param(sd_power, uint, 0);
extern uint sd_clock; /* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */
module_param(sd_clock, uint, 0);
extern uint sd_divisor; /* Divisor (-1 means external clock) */
module_param(sd_divisor, uint, 0);
extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */
module_param(sd_sdmode, uint, 0);
extern uint sd_hiok; /* Ok to use hi-speed mode */
module_param(sd_hiok, uint, 0);
extern uint sd_f2_blocksize;
module_param(sd_f2_blocksize, int, 0);
extern uint sd_f1_blocksize;
module_param(sd_f1_blocksize, int, 0);
#ifdef BCMSDIOH_STD
extern int sd_uhsimode;
module_param(sd_uhsimode, int, 0);
extern uint sd_tuning_period;
module_param(sd_tuning_period, uint, 0);
extern int sd_delay_value;
module_param(sd_delay_value, uint, 0);
/* SDIO Drive Strength for UHSI mode specific to SDIO3.0 */
extern char dhd_sdiod_uhsi_ds_override[2];
module_param_string(dhd_sdiod_uhsi_ds_override, dhd_sdiod_uhsi_ds_override, 2, 0);
#endif // endif
#ifdef BCMSDH_MODULE
EXPORT_SYMBOL(bcmsdh_attach);
EXPORT_SYMBOL(bcmsdh_detach);
EXPORT_SYMBOL(bcmsdh_intr_query);
EXPORT_SYMBOL(bcmsdh_intr_enable);
EXPORT_SYMBOL(bcmsdh_intr_disable);
EXPORT_SYMBOL(bcmsdh_intr_reg);
EXPORT_SYMBOL(bcmsdh_intr_dereg);
#if defined(DHD_DEBUG)
EXPORT_SYMBOL(bcmsdh_intr_pending);
#endif // endif
#if defined(BT_OVER_SDIO)
EXPORT_SYMBOL(bcmsdh_btsdio_interface_init);
#endif /* defined (BT_OVER_SDIO) */
EXPORT_SYMBOL(bcmsdh_devremove_reg);
EXPORT_SYMBOL(bcmsdh_cfg_read);
EXPORT_SYMBOL(bcmsdh_cfg_write);
EXPORT_SYMBOL(bcmsdh_cis_read);
EXPORT_SYMBOL(bcmsdh_reg_read);
EXPORT_SYMBOL(bcmsdh_reg_write);
EXPORT_SYMBOL(bcmsdh_regfail);
EXPORT_SYMBOL(bcmsdh_send_buf);
EXPORT_SYMBOL(bcmsdh_recv_buf);
EXPORT_SYMBOL(bcmsdh_rwdata);
EXPORT_SYMBOL(bcmsdh_abort);
EXPORT_SYMBOL(bcmsdh_query_device);
EXPORT_SYMBOL(bcmsdh_query_iofnum);
EXPORT_SYMBOL(bcmsdh_iovar_op);
EXPORT_SYMBOL(bcmsdh_register);
EXPORT_SYMBOL(bcmsdh_unregister);
EXPORT_SYMBOL(bcmsdh_chipmatch);
EXPORT_SYMBOL(bcmsdh_reset);
EXPORT_SYMBOL(bcmsdh_waitlockfree);
EXPORT_SYMBOL(bcmsdh_get_dstatus);
EXPORT_SYMBOL(bcmsdh_cfg_read_word);
EXPORT_SYMBOL(bcmsdh_cfg_write_word);
EXPORT_SYMBOL(bcmsdh_cur_sbwad);
EXPORT_SYMBOL(bcmsdh_chipinfo);
#endif /* BCMSDH_MODULE */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,383 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Proprietary,Open:>>
*
* $Id: bcmsdh_sdmmc_linux.c 825481 2019-06-14 10:06:03Z $
*/
#include <typedefs.h>
#include <bcmutils.h>
#include <sdio.h> /* SDIO Device and Protocol Specs */
#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
#include <sdiovar.h> /* to get msglevel bit values */
#include <linux/sched.h> /* request_irq() */
#include <linux/mmc/core.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <dhd_linux.h>
#include <bcmsdh_sdmmc.h>
#include <dhd_dbg.h>
#include <bcmdevs.h>
#if !defined(SDIO_VENDOR_ID_BROADCOM)
#define SDIO_VENDOR_ID_BROADCOM 0x02d0
#endif /* !defined(SDIO_VENDOR_ID_BROADCOM) */
#define SDIO_DEVICE_ID_BROADCOM_DEFAULT 0x0000
extern void wl_cfg80211_set_parent_dev(void *dev);
extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd);
extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd);
extern void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type,
uint bus_num, uint slot_num);
extern int bcmsdh_remove(bcmsdh_info_t *bcmsdh);
int sdio_function_init(void);
void sdio_function_cleanup(void);
#define DESCRIPTION "bcmsdh_sdmmc Driver"
#define AUTHOR "Broadcom Corporation"
/* module param defaults */
static int clockoverride = 0;
module_param(clockoverride, int, 0644);
MODULE_PARM_DESC(clockoverride, "SDIO card clock override");
#ifdef GLOBAL_SDMMC_INSTANCE
PBCMSDH_SDMMC_INSTANCE gInstance;
#endif
/* Maximum number of bcmsdh_sdmmc devices supported by driver */
#define BCMSDH_SDMMC_MAX_DEVICES 1
extern volatile bool dhd_mmc_suspend;
static int sdioh_probe(struct sdio_func *func)
{
int host_idx = func->card->host->index;
uint32 rca = func->card->rca;
wifi_adapter_info_t *adapter;
osl_t *osh = NULL;
sdioh_info_t *sdioh = NULL;
sd_err(("bus num (host idx)=%d, slot num (rca)=%d\n", host_idx, rca));
adapter = dhd_wifi_platform_get_adapter(SDIO_BUS, host_idx, rca);
if (adapter != NULL) {
sd_err(("found adapter info '%s'\n", adapter->name));
#ifdef BUS_POWER_RESTORE
adapter->sdio_func = func;
#endif
} else
sd_err(("can't find adapter info for this chip\n"));
#ifdef WL_CFG80211
wl_cfg80211_set_parent_dev(&func->dev);
#endif // endif
/* allocate SDIO Host Controller state info */
osh = osl_attach(&func->dev, SDIO_BUS, TRUE);
if (osh == NULL) {
sd_err(("%s: osl_attach failed\n", __FUNCTION__));
goto fail;
}
osl_static_mem_init(osh, adapter);
sdioh = sdioh_attach(osh, func);
if (sdioh == NULL) {
sd_err(("%s: sdioh_attach failed\n", __FUNCTION__));
goto fail;
}
sdioh->bcmsdh = bcmsdh_probe(osh, &func->dev, sdioh, adapter, SDIO_BUS, host_idx, rca);
if (sdioh->bcmsdh == NULL) {
sd_err(("%s: bcmsdh_probe failed\n", __FUNCTION__));
goto fail;
}
sdio_set_drvdata(func, sdioh);
return 0;
fail:
if (sdioh != NULL)
sdioh_detach(osh, sdioh);
if (osh != NULL)
osl_detach(osh);
return -ENOMEM;
}
static void sdioh_remove(struct sdio_func *func)
{
sdioh_info_t *sdioh;
osl_t *osh;
sdioh = sdio_get_drvdata(func);
if (sdioh == NULL) {
sd_err(("%s: error, no sdioh handler found\n", __FUNCTION__));
return;
}
sd_err(("%s: Enter\n", __FUNCTION__));
osh = sdioh->osh;
bcmsdh_remove(sdioh->bcmsdh);
sdioh_detach(osh, sdioh);
osl_detach(osh);
}
static int bcmsdh_sdmmc_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
int ret = 0;
if (func == NULL)
return -EINVAL;
sd_err(("%s: Enter num=%d\n", __FUNCTION__, func->num));
sd_info(("sdio_bcmsdh: func->class=%x\n", func->class));
sd_info(("sdio_vendor: 0x%04x\n", func->vendor));
sd_info(("sdio_device: 0x%04x\n", func->device));
sd_info(("Function#: 0x%04x\n", func->num));
#ifdef GLOBAL_SDMMC_INSTANCE
gInstance->func[func->num] = func;
#endif
/* 4318 doesn't have function 2 */
if ((func->num == 2) || (func->num == 1 && func->device == 0x4))
ret = sdioh_probe(func);
return ret;
}
static void bcmsdh_sdmmc_remove(struct sdio_func *func)
{
if (func == NULL) {
sd_err(("%s is called with NULL SDIO function pointer\n", __FUNCTION__));
return;
}
sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__));
sd_info(("sdio_bcmsdh: func->class=%x\n", func->class));
sd_info(("sdio_vendor: 0x%04x\n", func->vendor));
sd_info(("sdio_device: 0x%04x\n", func->device));
sd_info(("Function#: 0x%04x\n", func->num));
if ((func->num == 2) || (func->num == 1 && func->device == 0x4))
sdioh_remove(func);
}
/* devices we support, null terminated */
static const struct sdio_device_id bcmsdh_sdmmc_ids[] = {
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM4362_CHIP_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43751_CHIP_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43752_CHIP_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43012_CHIP_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43014_CHIP_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43014_D11N_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43014_D11N2G_ID) },
{ SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, BCM43014_D11N5G_ID) },
/* { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_ANY_ID) }, */
{ SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) },
/* end: all zeroes */
{ 0, 0, 0, 0},
};
MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
static int bcmsdh_sdmmc_suspend(struct device *pdev)
{
int err;
sdioh_info_t *sdioh;
struct sdio_func *func = dev_to_sdio_func(pdev);
mmc_pm_flag_t sdio_flags;
printf("%s Enter func->num=%d\n", __FUNCTION__, func->num);
if (func->num != 2)
return 0;
dhd_mmc_suspend = TRUE;
sdioh = sdio_get_drvdata(func);
err = bcmsdh_suspend(sdioh->bcmsdh);
if (err) {
printf("%s bcmsdh_suspend err=%d\n", __FUNCTION__, err);
dhd_mmc_suspend = FALSE;
return err;
}
sdio_flags = sdio_get_host_pm_caps(func);
if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
sd_err(("%s: can't keep power while host is suspended\n", __FUNCTION__));
dhd_mmc_suspend = FALSE;
return -EINVAL;
}
/* keep power while host suspended */
err = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
if (err) {
sd_err(("%s: error while trying to keep power\n", __FUNCTION__));
dhd_mmc_suspend = FALSE;
return err;
}
smp_mb();
printf("%s Exit\n", __FUNCTION__);
return 0;
}
static int bcmsdh_sdmmc_resume(struct device *pdev)
{
sdioh_info_t *sdioh;
struct sdio_func *func = dev_to_sdio_func(pdev);
printf("%s Enter func->num=%d\n", __FUNCTION__, func->num);
if (func->num != 2)
return 0;
dhd_mmc_suspend = FALSE;
sdioh = sdio_get_drvdata(func);
bcmsdh_resume(sdioh->bcmsdh);
smp_mb();
printf("%s Exit\n", __FUNCTION__);
return 0;
}
static const struct dev_pm_ops bcmsdh_sdmmc_pm_ops = {
.suspend = bcmsdh_sdmmc_suspend,
.resume = bcmsdh_sdmmc_resume,
};
#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */
#if defined(BCMLXSDMMC)
static struct semaphore *notify_semaphore = NULL;
static int dummy_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
if (func && (func->num != 2)) {
return 0;
}
if (notify_semaphore)
up(notify_semaphore);
return 0;
}
static void dummy_remove(struct sdio_func *func)
{
}
static struct sdio_driver dummy_sdmmc_driver = {
.probe = dummy_probe,
.remove = dummy_remove,
.name = "dummy_sdmmc",
.id_table = bcmsdh_sdmmc_ids,
};
int sdio_func_reg_notify(void* semaphore)
{
notify_semaphore = semaphore;
return sdio_register_driver(&dummy_sdmmc_driver);
}
void sdio_func_unreg_notify(void)
{
OSL_SLEEP(15);
sdio_unregister_driver(&dummy_sdmmc_driver);
}
#endif /* defined(BCMLXSDMMC) */
static struct sdio_driver bcmsdh_sdmmc_driver = {
.probe = bcmsdh_sdmmc_probe,
.remove = bcmsdh_sdmmc_remove,
.name = "bcmsdh_sdmmc",
.id_table = bcmsdh_sdmmc_ids,
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
.drv = {
.pm = &bcmsdh_sdmmc_pm_ops,
},
#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */
};
struct sdos_info {
sdioh_info_t *sd;
spinlock_t lock;
};
/* Interrupt enable/disable */
SDIOH_API_RC
sdioh_interrupt_set(sdioh_info_t *sd, bool enable)
{
if (!sd)
return BCME_BADARG;
sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling"));
return SDIOH_API_RC_SUCCESS;
}
#ifdef BCMSDH_MODULE
static int __init
bcmsdh_module_init(void)
{
int error = 0;
error = sdio_function_init();
return error;
}
static void __exit
bcmsdh_module_cleanup(void)
{
sdio_function_cleanup();
}
module_init(bcmsdh_module_init);
module_exit(bcmsdh_module_cleanup);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION(DESCRIPTION);
MODULE_AUTHOR(AUTHOR);
#endif /* BCMSDH_MODULE */
/*
* module init
*/
int bcmsdh_register_client_driver(void)
{
return sdio_register_driver(&bcmsdh_sdmmc_driver);
}
/*
* module cleanup
*/
void bcmsdh_unregister_client_driver(void)
{
sdio_unregister_driver(&bcmsdh_sdmmc_driver);
}

View File

@@ -0,0 +1,438 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Broadcom SPI Host Controller Driver - Linux Per-port
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmsdspi_linux.c 514727 2014-11-12 03:02:48Z $
*/
#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
#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())
#endif // 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 // 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 // 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;
#else
write = msg_out[1] & 0x80;
#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;
#else
write = msg_out[3] & 0x80;
#endif /* !(defined(SPI_PIO_RW_BIGENDIAN) && defined(SPI_PIO_32BIT_RW)) */
if (bcmgspi_dump) {
hexdump(" OUT: ", msg_out, msglen);
}
tx_len = write ? msglen-4 : 4;
sd_trace(("spi_sendrecv: %s, wordlen %d, cmd : 0x%02x 0x%02x 0x%02x 0x%02x\n",
write ? "WR" : "RD", sd->wordlen,
msg_out[0], msg_out[1], msg_out[2], msg_out[3]));
t[0].tx_buf = (char *)&msg_out[0];
t[0].rx_buf = 0;
t[0].len = tx_len;
spi_message_add_tail(&t[0], &msg);
t[1].rx_buf = (char *)&msg_in[tx_len];
t[1].tx_buf = 0;
t[1].len = msglen-tx_len;
spi_message_add_tail(&t[1], &msg);
spi_sync(gBCMSPI, &msg);
if (bcmgspi_dump) {
hexdump(" IN : ", msg_in, msglen);
}
}
#endif /* !BCMSPI_ANDROID */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,307 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Broadcom Secure Standard Library.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id $
*/
#include <bcm_cfg.h>
#include <typedefs.h>
#include <bcmdefs.h>
#ifdef BCMDRIVER
#include <osl.h>
#else /* BCMDRIVER */
#include <stddef.h>
#include <string.h>
#endif /* else BCMDRIVER */
#include <bcmstdlib_s.h>
#include <bcmutils.h>
/*
* __SIZE_MAX__ value is depending on platform:
* Firmware Dongle: RAMSIZE (Dongle Specific Limit).
* LINUX NIC/Windows/MACOSX/Application: OS Native or
* 0xFFFFFFFFu if not defined.
*/
#ifndef SIZE_MAX
#ifndef __SIZE_MAX__
#define __SIZE_MAX__ 0xFFFFFFFFu
#endif /* __SIZE_MAX__ */
#define SIZE_MAX __SIZE_MAX__
#endif /* SIZE_MAX */
#define RSIZE_MAX (SIZE_MAX >> 1u)
#if !defined(__STDC_WANT_SECURE_LIB__) && !(defined(__STDC_LIB_EXT1__) && \
defined(__STDC_WANT_LIB_EXT1__))
/*
* memmove_s - secure memmove
* dest : pointer to the object to copy to
* destsz : size of the destination buffer
* src : pointer to the object to copy from
* n : number of bytes to copy
* Return Value : zero on success and non-zero on error
* Also on error, if dest is not a null pointer and destsz not greater
* 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)
{
int err = BCME_OK;
if ((!dest) || (((char *)dest + destsz) < (char *)dest)) {
err = BCME_BADARG;
goto exit;
}
if (destsz > RSIZE_MAX) {
err = BCME_BADLEN;
goto exit;
}
if (destsz < n) {
memset(dest, 0, destsz);
err = BCME_BADLEN;
goto exit;
}
if ((!src) || (((const char *)src + n) < (const char *)src)) {
memset(dest, 0, destsz);
err = BCME_BADARG;
goto exit;
}
memmove(dest, src, n);
exit:
return err;
}
/*
* memcpy_s - secure memcpy
* dest : pointer to the object to copy to
* destsz : size of the destination buffer
* src : pointer to the object to copy from
* n : number of bytes to copy
* Return Value : zero on success and non-zero on error
* Also on error, if dest is not a null pointer and destsz not greater
* than RSIZE_MAX, writes destsz zero bytes into the dest object.
*/
int
memcpy_s(void *dest, size_t destsz, const void *src, size_t n)
{
int err = BCME_OK;
char *d = dest;
const char *s = src;
if ((!d) || ((d + destsz) < d)) {
err = BCME_BADARG;
goto exit;
}
if (destsz > RSIZE_MAX) {
err = BCME_BADLEN;
goto exit;
}
if (destsz < n) {
memset(dest, 0, destsz);
err = BCME_BADLEN;
goto exit;
}
if ((!s) || ((s + n) < s)) {
memset(dest, 0, destsz);
err = BCME_BADARG;
goto exit;
}
/* overlap checking between dest and src */
if (!(((d + destsz) <= s) || (d >= (s + n)))) {
memset(dest, 0, destsz);
err = BCME_BADARG;
goto exit;
}
(void)memcpy(dest, src, n);
exit:
return err;
}
/*
* memset_s - secure memset
* dest : pointer to the object to be set
* destsz : size of the destination buffer
* c : byte value
* n : number of bytes to be set
* Return Value : zero on success and non-zero on error
* Also on error, if dest is not a null pointer and destsz not greater
* than RSIZE_MAX, writes destsz bytes with value c into the dest object.
*/
int
memset_s(void *dest, size_t destsz, int c, size_t n)
{
int err = BCME_OK;
if ((!dest) || (((char *)dest + destsz) < (char *)dest)) {
err = BCME_BADARG;
goto exit;
}
if (destsz > RSIZE_MAX) {
err = BCME_BADLEN;
goto exit;
}
if (destsz < n) {
(void)memset(dest, c, destsz);
err = BCME_BADLEN;
goto exit;
}
(void)memset(dest, c, n);
exit:
return err;
}
#endif /* !__STDC_WANT_SECURE_LIB__ && !(__STDC_LIB_EXT1__ && __STDC_WANT_LIB_EXT1__) */
#if 0
/**
* strlcpy - Copy a %NUL terminated string into a sized buffer
* @dest: Where to copy the string to
* @src: Where to copy the string from
* @size: size of destination buffer 0 if input parameters are NOK
* return: string leng of src (assume src is NUL terminated)
*
* Compatible with *BSD: the result is always a valid
* NUL-terminated string that fits in the buffer (unless,
* 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)
{
const char *s = src;
size_t n;
if (dest == NULL) {
return 0;
}
/* terminate dest if src is NULL and return 0 as only NULL was added */
if (s == NULL) {
*dest = '\0';
return 0;
}
/* allows us to handle size 0 */
if (size == 0) {
n = 0;
} else {
n = size - 1u;
}
/* perform copy */
while (*s && n != 0) {
*dest++ = *s++;
n--;
}
*dest = '\0';
/* count to end of s or compensate for NULL */
if (n == 0) {
while (*s++)
;
} else {
s++;
}
/* return bytes copied not accounting NUL */
return (s - src - 1u);
}
#endif // endif
/**
* strlcat_s - Concatenate a %NUL terminated string with a sized buffer
* @dest: Where to concatenate the string to
* @src: Where to copy the string from
* @size: size of destination buffer
* return: string length of created string (i.e. the initial length of dest plus the length of src)
* not including the NUL char, up until size
*
* Unlike strncat(), strlcat() take the full size of the buffer (not just the number of bytes to
* copy) and guarantee to NUL-terminate the result (even when there's nothing to concat).
* If the length of dest string concatinated with the src string >= size, truncation occurs.
*
* Compatible with *BSD: the result is always a valid NUL-terminated string that fits in the buffer
* (unless, of course, the buffer size is zero).
*
* If either src or dest is not NUL-terminated, dest[size-1] will be set to NUL.
* If size < strlen(dest) + strlen(src), dest[size-1] will be set to NUL.
* If size == 0, dest[0] will be set to NUL.
*/
size_t
strlcat_s(char *dest, const char *src, size_t size)
{
char *d = dest;
const char *s = src; /* point to the start of the src string */
size_t n = size;
size_t dlen;
size_t bytes_to_copy = 0;
if (dest == NULL) {
return 0;
}
/* set d to point to the end of dest string (up to size) */
while (n != 0 && *d != '\0') {
d++;
n--;
}
dlen = (size_t)(d - dest);
if (s != NULL) {
size_t slen = 0;
/* calculate src len in case it's not null-terminated */
n = size;
while (n-- != 0 && *(s + slen) != '\0') {
++slen;
}
n = size - dlen; /* maximum num of chars to copy */
if (n != 0) {
/* copy relevant chars (until end of src buf or given size is reached) */
bytes_to_copy = MIN(slen - (size_t)(s - src), n - 1);
(void)memcpy(d, s, bytes_to_copy);
d += bytes_to_copy;
}
}
if (n == 0 && dlen != 0) {
--d; /* nothing to copy, but NUL-terminate dest anyway */
}
*d = '\0'; /* NUL-terminate dest */
return (dlen + bytes_to_copy);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,816 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Misc utility routines for WL and Apps
* This header file housing the define and function prototype use by
* both the wl driver, tools & Apps.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmwifi_channels.h 806092 2019-02-21 08:19:13Z $
*/
#ifndef _bcmwifi_channels_h_
#define _bcmwifi_channels_h_
/* A chanspec holds the channel number, band, bandwidth and primary 20MHz sideband */
typedef uint16 chanspec_t;
typedef uint16 chanspec_band_t;
typedef uint16 chanspec_bw_t;
typedef uint16 chanspec_subband_t;
/* channel defines */
#define CH_80MHZ_APART 16
#define CH_40MHZ_APART 8
#define CH_20MHZ_APART 4
#define CH_10MHZ_APART 2
#define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */
#define CH_MIN_2G_CHANNEL 1u /* Min channel in 2G band */
#define CH_MAX_2G_CHANNEL 14u /* Max channel in 2G band */
#define CH_MIN_2G_40M_CHANNEL 3u /* Min 40MHz center channel in 2G band */
#define CH_MAX_2G_40M_CHANNEL 11u /* Max 40MHz center channel in 2G band */
/* maximum # channels the s/w supports */
#define MAXCHANNEL 224 /* max # supported channels. The max channel no is above,
* this is that + 1 rounded up to a multiple of NBBY (8).
* DO NOT MAKE it > 255: channels are uint8's all over
*/
#define MAXCHANNEL_NUM (MAXCHANNEL - 1) /* max channel number */
#define INVCHANNEL 255 /* error value for a bad channel */
/* channel bitvec */
typedef struct {
uint8 vec[MAXCHANNEL/8]; /* bitvec of channels */
} chanvec_t;
/* make sure channel num is within valid range */
#define CH_NUM_VALID_RANGE(ch_num) ((ch_num) > 0 && (ch_num) <= MAXCHANNEL_NUM)
#define CHSPEC_CTLOVLP(sp1, sp2, sep) \
(ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < (sep))
/* All builds use the new 11ac ratespec/chanspec */
#undef D11AC_IOTYPES
#define D11AC_IOTYPES
#define WL_CHANSPEC_CHAN_MASK 0x00ff
#define WL_CHANSPEC_CHAN_SHIFT 0
#define WL_CHANSPEC_CHAN1_MASK 0x000f
#define WL_CHANSPEC_CHAN1_SHIFT 0
#define WL_CHANSPEC_CHAN2_MASK 0x00f0
#define WL_CHANSPEC_CHAN2_SHIFT 4
#define WL_CHANSPEC_CTL_SB_MASK 0x0700
#define WL_CHANSPEC_CTL_SB_SHIFT 8
#define WL_CHANSPEC_CTL_SB_LLL 0x0000
#define WL_CHANSPEC_CTL_SB_LLU 0x0100
#define WL_CHANSPEC_CTL_SB_LUL 0x0200
#define WL_CHANSPEC_CTL_SB_LUU 0x0300
#define WL_CHANSPEC_CTL_SB_ULL 0x0400
#define WL_CHANSPEC_CTL_SB_ULU 0x0500
#define WL_CHANSPEC_CTL_SB_UUL 0x0600
#define WL_CHANSPEC_CTL_SB_UUU 0x0700
#define WL_CHANSPEC_CTL_SB_LL WL_CHANSPEC_CTL_SB_LLL
#define WL_CHANSPEC_CTL_SB_LU WL_CHANSPEC_CTL_SB_LLU
#define WL_CHANSPEC_CTL_SB_UL WL_CHANSPEC_CTL_SB_LUL
#define WL_CHANSPEC_CTL_SB_UU WL_CHANSPEC_CTL_SB_LUU
#define WL_CHANSPEC_CTL_SB_L WL_CHANSPEC_CTL_SB_LLL
#define WL_CHANSPEC_CTL_SB_U WL_CHANSPEC_CTL_SB_LLU
#define WL_CHANSPEC_CTL_SB_LOWER WL_CHANSPEC_CTL_SB_LLL
#define WL_CHANSPEC_CTL_SB_UPPER WL_CHANSPEC_CTL_SB_LLU
#define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL
#define WL_CHANSPEC_BW_MASK 0x3800u
#define WL_CHANSPEC_BW_SHIFT 11u
#define WL_CHANSPEC_BW_5 0x0000u
#define WL_CHANSPEC_BW_10 0x0800u
#define WL_CHANSPEC_BW_20 0x1000u
#define WL_CHANSPEC_BW_40 0x1800u
#define WL_CHANSPEC_BW_80 0x2000u
#define WL_CHANSPEC_BW_160 0x2800u
#define WL_CHANSPEC_BW_8080 0x3000u
#define WL_CHANSPEC_BAND_MASK 0xc000u
#define WL_CHANSPEC_BAND_SHIFT 14u
#define WL_CHANSPEC_BAND_2G 0x0000u
#define WL_CHANSPEC_BAND_3G 0x4000u
#define WL_CHANSPEC_BAND_4G 0x8000u
#define WL_CHANSPEC_BAND_5G 0xc000u
#define INVCHANSPEC 255u
#define MAX_CHANSPEC 0xFFFFu
#define WL_CHANNEL_BAND(ch) (((ch) <= CH_MAX_2G_CHANNEL) ? \
WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)
/* channel defines */
#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \
((channel) - CH_10MHZ_APART) : 0)
#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \
((channel) + CH_10MHZ_APART) : 0)
/* pass a 80MHz channel number (uint8) to get respective LL, UU, LU, UL */
#define LL_20_SB(channel) (((channel) > 3 * CH_10MHZ_APART) ? ((channel) - 3 * CH_10MHZ_APART) : 0)
#define UU_20_SB(channel) (((channel) < (MAXCHANNEL - 3 * CH_10MHZ_APART)) ? \
((channel) + 3 * CH_10MHZ_APART) : 0)
#define LU_20_SB(channel) LOWER_20_SB(channel)
#define UL_20_SB(channel) UPPER_20_SB(channel)
#define LOWER_40_SB(channel) ((channel) - CH_20MHZ_APART)
#define UPPER_40_SB(channel) ((channel) + CH_20MHZ_APART)
#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX)
#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \
(((channel) <= CH_MAX_2G_CHANNEL) ? \
WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G))
#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \
((channel) + CH_20MHZ_APART) : 0)
#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \
((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \
((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \
WL_CHANSPEC_BAND_5G))
#define CH80MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \
((channel) | (ctlsb) | \
WL_CHANSPEC_BW_80 | WL_CHANSPEC_BAND_5G)
#define CH160MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \
((channel) | (ctlsb) | \
WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G)
/* simple MACROs to get different fields of chanspec */
#ifdef WL11AC_80P80
#define CHSPEC_CHANNEL(chspec) wf_chspec_channel(chspec)
#else
#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK))
#endif // endif
#define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT
#define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT
#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK)
#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK)
#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK)
#ifdef WL11N_20MHZONLY
#define CHSPEC_IS20(chspec) 1
#define CHSPEC_IS20_2G(chspec) ((((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) && \
CHSPEC_IS2G(chspec))
#ifndef CHSPEC_IS40
#define CHSPEC_IS40(chspec) 0
#endif // endif
#ifndef CHSPEC_IS80
#define CHSPEC_IS80(chspec) 0
#endif // endif
#ifndef CHSPEC_IS160
#define CHSPEC_IS160(chspec) 0
#endif // endif
#ifndef CHSPEC_IS8080
#define CHSPEC_IS8080(chspec) 0
#endif // endif
/* see FOREACH_20_SB in !WL11N_20MHZONLY section */
#define FOREACH_20_SB(chspec, channel) \
for (channel = CHSPEC_CHANNEL(chspec); channel; channel = 0)
/* see GET_ALL_SB in !WL11N_20MHZONLY section */
#define GET_ALL_SB(chspec, psb) do { \
psb[0] = CHSPEC_CHANNEL(chspec); \
} while (0)
#else /* !WL11N_20MHZONLY */
#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20)
#define CHSPEC_IS20_5G(chspec) ((((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) && \
CHSPEC_IS5G(chspec))
#ifndef CHSPEC_IS40
#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)
#endif // endif
#ifndef CHSPEC_IS80
#define CHSPEC_IS80(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80)
#endif // endif
#ifndef CHSPEC_IS160
#define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160)
#endif // endif
#ifndef CHSPEC_IS8080
#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080)
#endif // endif
/* pass a center channel and get channel offset from it by 10MHz */
#define CH_OFF_10MHZ_MULTIPLES(channel, offset) ((uint8) (((offset) < 0) ? \
(((channel) > (WL_CHANSPEC_CHAN_MASK & ((uint16)((-(offset)) * CH_10MHZ_APART)))) ?\
((channel) + (offset) * CH_10MHZ_APART) : 0) : \
(((channel) < (uint16)(MAXCHANNEL - (offset) * CH_10MHZ_APART)) ? \
((channel) + (offset) * CH_10MHZ_APART) : 0)))
#if defined(WL11AC_80P80) || defined(WL11AC_160)
/* pass a 160MHz center channel to get 20MHz subband channel numbers */
#define LLL_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, -7)
#define LLU_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, -5)
#define LUL_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, -3)
#define LUU_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, -1)
#define ULL_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, 1)
#define ULU_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, 3)
#define UUL_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, 5)
#define UUU_20_SB_160(channel) CH_OFF_10MHZ_MULTIPLES(channel, 7)
/* given an 80p80 channel, return the lower 80MHz sideband */
#define LOWER_80_SB(chspec) (wf_chspec_primary80_channel(chspec) < \
wf_chspec_secondary80_channel(chspec) ? \
wf_chspec_primary80_channel(chspec) : wf_chspec_secondary80_channel(chspec))
/* given an 80p80 channel, return the upper 80MHz sideband */
#define UPPER_80_SB(chspec) (wf_chspec_primary80_channel(chspec) > \
wf_chspec_secondary80_channel(chspec) ? \
wf_chspec_primary80_channel(chspec) : wf_chspec_secondary80_channel(chspec))
/* pass an 80P80 chanspec (not channel) to get 20MHz subnand channel numbers */
#define LLL_20_SB_8080(chspec) CH_OFF_10MHZ_MULTIPLES(LOWER_80_SB(chspec), -3)
#define LLU_20_SB_8080(chspec) CH_OFF_10MHZ_MULTIPLES(LOWER_80_SB(chspec), -1)
#define LUL_20_SB_8080(chspec) CH_OFF_10MHZ_MULTIPLES(LOWER_80_SB(chspec), 1)
#define LUU_20_SB_8080(chspec) CH_OFF_10MHZ_MULTIPLES(LOWER_80_SB(chspec), 3)
#define ULL_20_SB_8080(chspec) CH_OFF_10MHZ_MULTIPLES(UPPER_80_SB(chspec), -3)
#define ULU_20_SB_8080(chspec) CH_OFF_10MHZ_MULTIPLES(UPPER_80_SB(chspec), -1)
#define UUL_20_SB_8080(chspec) CH_OFF_10MHZ_MULTIPLES(UPPER_80_SB(chspec), 1)
#define UUU_20_SB_8080(chspec) CH_OFF_10MHZ_MULTIPLES(UPPER_80_SB(chspec), 3)
/* get lowest 20MHz sideband of a given chspec
* (works with 20, 40, 80, 160, 80p80)
*/
#define CH_FIRST_20_SB(chspec) ((uint8) (\
CHSPEC_IS160(chspec) ? LLL_20_SB_160(CHSPEC_CHANNEL(chspec)) : (\
CHSPEC_IS8080(chspec) ? LLL_20_SB_8080(chspec) : (\
CHSPEC_IS80(chspec) ? LL_20_SB(CHSPEC_CHANNEL(chspec)) : (\
CHSPEC_IS40(chspec) ? LOWER_20_SB(CHSPEC_CHANNEL(chspec)) : \
CHSPEC_CHANNEL(chspec))))))
/* get upper most 20MHz sideband of a given chspec
* (works with 20, 40, 80, 160, 80p80)
*/
#define CH_LAST_20_SB(chspec) ((uint8) (\
CHSPEC_IS160(chspec) ? UUU_20_SB_160(CHSPEC_CHANNEL(chspec)) : (\
CHSPEC_IS8080(chspec) ? UUU_20_SB_8080(chspec) : (\
CHSPEC_IS80(chspec) ? UU_20_SB(CHSPEC_CHANNEL(chspec)) : (\
CHSPEC_IS40(chspec) ? UPPER_20_SB(CHSPEC_CHANNEL(chspec)) : \
CHSPEC_CHANNEL(chspec))))))
/* call this with chspec and a valid 20MHz sideband of this channel to get the next 20MHz sideband
* (works with 80p80 only)
* resolves to 0 if called with upper most channel
*/
#define CH_NEXT_20_SB_IN_8080(chspec, channel) ((uint8) (\
((uint8) ((channel) + CH_20MHZ_APART) > CH_LAST_20_SB(chspec) ? 0 : \
((channel) == LUU_20_SB_8080(chspec) ? ULL_20_SB_8080(chspec) : \
(channel) + CH_20MHZ_APART))))
/* call this with chspec and a valid 20MHz sideband of this channel to get the next 20MHz sideband
* (works with 20, 40, 80, 160, 80p80)
* resolves to 0 if called with upper most channel
*/
#define CH_NEXT_20_SB(chspec, channel) ((uint8) (\
(CHSPEC_IS8080(chspec) ? CH_NEXT_20_SB_IN_8080((chspec), (channel)) : \
((uint8) ((channel) + CH_20MHZ_APART) > CH_LAST_20_SB(chspec) ? 0 : \
((channel) + CH_20MHZ_APART)))))
#else /* WL11AC_80P80, WL11AC_160 */
#define LLL_20_SB_160(channel) 0
#define LLU_20_SB_160(channel) 0
#define LUL_20_SB_160(channel) 0
#define LUU_20_SB_160(channel) 0
#define ULL_20_SB_160(channel) 0
#define ULU_20_SB_160(channel) 0
#define UUL_20_SB_160(channel) 0
#define UUU_20_SB_160(channel) 0
#define LOWER_80_SB(chspec) 0
#define UPPER_80_SB(chspec) 0
#define LLL_20_SB_8080(chspec) 0
#define LLU_20_SB_8080(chspec) 0
#define LUL_20_SB_8080(chspec) 0
#define LUU_20_SB_8080(chspec) 0
#define ULL_20_SB_8080(chspec) 0
#define ULU_20_SB_8080(chspec) 0
#define UUL_20_SB_8080(chspec) 0
#define UUU_20_SB_8080(chspec) 0
/* get lowest 20MHz sideband of a given chspec
* (works with 20, 40, 80)
*/
#define CH_FIRST_20_SB(chspec) ((uint8) (\
CHSPEC_IS80(chspec) ? LL_20_SB(CHSPEC_CHANNEL(chspec)) : (\
CHSPEC_IS40(chspec) ? LOWER_20_SB(CHSPEC_CHANNEL(chspec)) : \
CHSPEC_CHANNEL(chspec))))
/* get upper most 20MHz sideband of a given chspec
* (works with 20, 40, 80, 160, 80p80)
*/
#define CH_LAST_20_SB(chspec) ((uint8) (\
CHSPEC_IS80(chspec) ? UU_20_SB(CHSPEC_CHANNEL(chspec)) : (\
CHSPEC_IS40(chspec) ? UPPER_20_SB(CHSPEC_CHANNEL(chspec)) : \
CHSPEC_CHANNEL(chspec))))
/* call this with chspec and a valid 20MHz sideband of this channel to get the next 20MHz sideband
* (works with 20, 40, 80, 160, 80p80)
* resolves to 0 if called with upper most channel
*/
#define CH_NEXT_20_SB(chspec, channel) ((uint8) (\
((uint8) ((channel) + CH_20MHZ_APART) > CH_LAST_20_SB(chspec) ? 0 : \
((channel) + CH_20MHZ_APART))))
#endif /* WL11AC_80P80, WL11AC_160 */
/* Iterator for 20MHz side bands of a chanspec: (chanspec_t chspec, uint8 channel)
* 'chspec' chanspec_t of interest (used in loop, better to pass a resolved value than a macro)
* 'channel' must be a variable (not an expression).
*/
#define FOREACH_20_SB(chspec, channel) \
for (channel = CH_FIRST_20_SB(chspec); channel; \
channel = CH_NEXT_20_SB((chspec), channel))
/* Uses iterator to populate array with all side bands involved (sorted lower to upper).
* 'chspec' chanspec_t of interest
* 'psb' pointer to uint8 array of enough size to hold all side bands for the given chspec
*/
#define GET_ALL_SB(chspec, psb) do { \
uint8 channel, idx = 0; \
chanspec_t chspec_local = chspec; \
FOREACH_20_SB(chspec_local, channel) \
(psb)[idx++] = channel; \
} while (0)
/* given a chanspec of any bw, tests if primary20 SB is in lower 20, 40, 80 respectively */
#define IS_CTL_IN_L20(chspec) !((chspec) & WL_CHANSPEC_CTL_SB_U) /* CTL SB is in low 20 of any 40 */
#define IS_CTL_IN_L40(chspec) !((chspec) & WL_CHANSPEC_CTL_SB_UL) /* in low 40 of any 80 */
#define IS_CTL_IN_L80(chspec) !((chspec) & WL_CHANSPEC_CTL_SB_ULL) /* in low 80 of 80p80/160 */
#endif /* !WL11N_20MHZONLY */
/* ULB introduced macros. Remove once ULB is cleaned from phy code */
#define CHSPEC_IS2P5(chspec) 0
#define CHSPEC_IS5(chspec) 0
#define CHSPEC_IS10(chspec) 0
#define CHSPEC_ISLE20(chspec) (CHSPEC_IS20(chspec))
#define CHSPEC_BW_LE20(chspec) (CHSPEC_IS20(chspec))
#define BW_LE40(bw) ((bw) == WL_CHANSPEC_BW_20 || ((bw) == WL_CHANSPEC_BW_40))
#define BW_LE80(bw) (BW_LE40(bw) || ((bw) == WL_CHANSPEC_BW_80))
#define BW_LE160(bw) (BW_LE80(bw) || ((bw) == WL_CHANSPEC_BW_160))
#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G)
#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G)
#define CHSPEC_SB_UPPER(chspec) \
((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) && \
(((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40))
#define CHSPEC_SB_LOWER(chspec) \
((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \
(((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40))
#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G)
/**
* Number of chars needed for wf_chspec_ntoa() destination character buffer.
*/
#define CHANSPEC_STR_LEN 20
/*
* This function returns TRUE if both the chanspec can co-exist in PHY.
* Addition to primary20 channel, the function checks for side band for 2g 40 channels
*/
extern bool wf_chspec_coexist(chanspec_t chspec1, chanspec_t chspec2);
#define CHSPEC_IS_BW_160_WIDE(chspec) (CHSPEC_BW(chspec) == WL_CHANSPEC_BW_160 ||\
CHSPEC_BW(chspec) == WL_CHANSPEC_BW_8080)
/* BW inequality comparisons, LE (<=), GE (>=), LT (<), GT (>), comparisons can be made
* as simple numeric comparisons, with the exception that 160 is the same BW as 80+80,
* but have different numeric values; (WL_CHANSPEC_BW_160 < WL_CHANSPEC_BW_8080).
*
* The LT/LE/GT/GE macros check first checks whether both chspec bandwidth and bw are 160 wide.
* If both chspec bandwidth and bw is not 160 wide, then the comparison is made.
*/
#define CHSPEC_BW_GE(chspec, bw) \
((CHSPEC_IS_BW_160_WIDE(chspec) &&\
((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\
(CHSPEC_BW(chspec) >= (bw)))
#define CHSPEC_BW_LE(chspec, bw) \
((CHSPEC_IS_BW_160_WIDE(chspec) &&\
((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\
(CHSPEC_BW(chspec) <= (bw)))
#define CHSPEC_BW_GT(chspec, bw) \
(!(CHSPEC_IS_BW_160_WIDE(chspec) &&\
((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\
(CHSPEC_BW(chspec) > (bw)))
#define CHSPEC_BW_LT(chspec, bw) \
(!(CHSPEC_IS_BW_160_WIDE(chspec) &&\
((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\
(CHSPEC_BW(chspec) < (bw)))
/* Legacy Chanspec defines
* These are the defines for the previous format of the chanspec_t
*/
#define WL_LCHANSPEC_CHAN_MASK 0x00ff
#define WL_LCHANSPEC_CHAN_SHIFT 0
#define WL_LCHANSPEC_CTL_SB_MASK 0x0300
#define WL_LCHANSPEC_CTL_SB_SHIFT 8
#define WL_LCHANSPEC_CTL_SB_LOWER 0x0100
#define WL_LCHANSPEC_CTL_SB_UPPER 0x0200
#define WL_LCHANSPEC_CTL_SB_NONE 0x0300
#define WL_LCHANSPEC_BW_MASK 0x0C00
#define WL_LCHANSPEC_BW_SHIFT 10
#define WL_LCHANSPEC_BW_10 0x0400
#define WL_LCHANSPEC_BW_20 0x0800
#define WL_LCHANSPEC_BW_40 0x0C00
#define WL_LCHANSPEC_BAND_MASK 0xf000
#define WL_LCHANSPEC_BAND_SHIFT 12
#define WL_LCHANSPEC_BAND_5G 0x1000
#define WL_LCHANSPEC_BAND_2G 0x2000
#define LCHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_LCHANSPEC_CHAN_MASK))
#define LCHSPEC_BAND(chspec) ((chspec) & WL_LCHANSPEC_BAND_MASK)
#define LCHSPEC_CTL_SB(chspec) ((chspec) & WL_LCHANSPEC_CTL_SB_MASK)
#define LCHSPEC_BW(chspec) ((chspec) & WL_LCHANSPEC_BW_MASK)
#define LCHSPEC_IS10(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_10)
#define LCHSPEC_IS20(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_20)
#define LCHSPEC_IS40(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)
#define LCHSPEC_IS5G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_5G)
#define LCHSPEC_IS2G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_2G)
#define LCHSPEC_SB_UPPER(chspec) \
((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_UPPER) && \
(((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40))
#define LCHSPEC_SB_LOWER(chspec) \
((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_LOWER) && \
(((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40))
#define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band)))
#define CH20MHZ_LCHSPEC(channel) \
(chanspec_t)((chanspec_t)(channel) | WL_LCHANSPEC_BW_20 | \
WL_LCHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \
WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G))
#define GET_ALL_EXT wf_get_all_ext
/*
* WF_CHAN_FACTOR_* constants are used to calculate channel frequency
* given a channel number.
* chan_freq = chan_factor * 500Mhz + chan_number * 5
*/
/**
* Channel Factor for the starting frequence of 2.4 GHz channels.
* The value corresponds to 2407 MHz.
*/
#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */
/**
* Channel Factor for the starting frequence of 5 GHz channels.
* The value corresponds to 5000 MHz.
*/
#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */
/**
* Channel Factor for the starting frequence of 4.9 GHz channels.
* The value corresponds to 4000 MHz.
*/
#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */
#define WLC_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */
/**
* No of sub-band vlaue of the specified Mhz chanspec
*/
#define WF_NUM_SIDEBANDS_40MHZ 2
#define WF_NUM_SIDEBANDS_80MHZ 4
#define WF_NUM_SIDEBANDS_8080MHZ 4
#define WF_NUM_SIDEBANDS_160MHZ 8
/**
* Return the chanspec bandwidth in MHz
* Bandwidth of 160 MHz will be returned for 80+80MHz chanspecs.
*
* @param chspec chanspec_t
*
* @return bandwidth of chspec in MHz units
*/
extern uint wf_bw_chspec_to_mhz(chanspec_t chspec);
/**
* Convert chanspec to ascii string
*
* @param chspec chanspec format
* @param buf ascii string of chanspec
*
* @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes
* Original chanspec in case of error
*
* @see CHANSPEC_STR_LEN
*/
extern char * wf_chspec_ntoa_ex(chanspec_t chspec, char *buf);
/**
* Convert chanspec to ascii string
*
* @param chspec chanspec format
* @param buf ascii string of chanspec
*
* @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes
* NULL in case of error
*
* @see CHANSPEC_STR_LEN
*/
extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf);
/**
* Convert ascii string to chanspec
*
* @param a pointer to input string
*
* @return >= 0 if successful or 0 otherwise
*/
extern chanspec_t wf_chspec_aton(const char *a);
/**
* Verify the chanspec fields are valid.
*
* Verify the chanspec is using a legal set field values, i.e. that the chanspec
* specified a band, bw, primary_sb, and channel and that the combination could be
* legal given some set of circumstances.
*
* @param chanspec input chanspec to verify
*
* @return TRUE if the chanspec is malformed, FALSE if it looks good.
*/
extern bool wf_chspec_malformed(chanspec_t chanspec);
/**
* Verify the chanspec specifies a valid channel according to 802.11.
*
* @param chanspec input chanspec to verify
*
* @return TRUE if the chanspec is a valid 802.11 channel
*/
extern bool wf_chspec_valid(chanspec_t chanspec);
/**
* Return the primary 20MHz channel.
*
* This function returns the channel number of the primary 20MHz channel. For
* 20MHz channels this is just the channel number. For 40MHz or wider channels
* it is the primary 20MHz channel specified by the chanspec.
*
* @param chspec input chanspec
*
* @return Returns the channel number of the primary 20MHz channel
*/
extern uint8 wf_chspec_primary20_chan(chanspec_t chspec);
/* alias for old function name */
#define wf_chspec_ctlchan(c) wf_chspec_primary20_chan(c)
/**
* Return the bandwidth string.
*
* This function returns the bandwidth string for the passed chanspec.
*
* @param chspec input chanspec
*
* @return Returns the bandwidth string:
* "5", "10", "20", "40", "80", "160", "80+80"
*/
extern const char *wf_chspec_to_bw_str(chanspec_t chspec);
/**
* Create a 20MHz chanspec for the given band.
*/
chanspec_t wf_create_20MHz_chspec(uint channel, chanspec_band_t band);
/**
* Return the primary 20MHz chanspec.
*
* This function returns the chanspec of the primary 20MHz channel. For 20MHz
* channels this is just the chanspec. For 40MHz or wider channels it is the
* chanspec of the primary 20MHZ channel specified by the chanspec.
*
* @param chspec input chanspec
*
* @return Returns the chanspec of the primary 20MHz channel
*/
extern chanspec_t wf_chspec_primary20_chspec(chanspec_t chspec);
/* alias for old function name */
#define wf_chspec_ctlchspec(c) wf_chspec_primary20_chspec(c)
/**
* Return the primary 40MHz chanspec.
*
* This function returns the chanspec for the primary 40MHz of an 80MHz or wider channel.
* The primary 20MHz channel of the returned 40MHz chanspec is the same as the primary 20MHz
* channel of the input chanspec.
*/
extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec);
/*
* Return the channel number for a given frequency and base frequency.
* The returned channel number is relative to the given base frequency.
* If the given base frequency is zero, a base frequency of 5 GHz is assumed for
* frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz.
*
* Frequency is specified in MHz.
* The base frequency is specified as (start_factor * 500 kHz).
* Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for
* 2.4 GHz and 5 GHz bands.
*
* The returned channel will be in the range [1, 14] in the 2.4 GHz band
* and [0, 200] otherwise.
* -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the
* frequency is not a 2.4 GHz channel, or if the frequency is not and even
* multiple of 5 MHz from the base frequency to the base plus 1 GHz.
*
* Reference 802.11-2016, section 17.3.8.3 and section 16.3.6.3
*
* @param freq frequency in MHz
* @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz
*
* @return Returns a channel number
*
* @see WF_CHAN_FACTOR_2_4_G
* @see WF_CHAN_FACTOR_5_G
*/
extern int wf_mhz2channel(uint freq, uint start_factor);
/**
* Return the center frequency in MHz of the given channel and base frequency.
*
* Return the center frequency in MHz of the given channel and base frequency.
* The channel number is interpreted relative to the given base frequency.
*
* The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise.
* The base frequency is specified as (start_factor * 500 kHz).
* Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for
* 2.4 GHz and 5 GHz bands.
* The channel range of [1, 14] is only checked for a start_factor of
* WF_CHAN_FACTOR_2_4_G (4814).
* Odd start_factors produce channels on .5 MHz boundaries, in which case
* the answer is rounded down to an integral MHz.
* -1 is returned for an out of range channel.
*
* Reference 802.11-2016, section 17.3.8.3 and section 16.3.6.3
*
* @param channel input channel number
* @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz
*
* @return Returns a frequency in MHz
*
* @see WF_CHAN_FACTOR_2_4_G
* @see WF_CHAN_FACTOR_5_G
*/
extern int wf_channel2mhz(uint channel, uint start_factor);
/**
* Returns the chanspec 80Mhz channel corresponding to the following input
* parameters
*
* primary_channel - primary 20Mhz channel
* center_channel - center frequecny of the 80Mhz channel
*
* The center_channel can be one of {42, 58, 106, 122, 138, 155}
*
* returns INVCHANSPEC in case of error
*/
extern chanspec_t wf_chspec_80(uint8 center_channel, uint8 primary_channel);
/**
* Convert ctl chan and bw to chanspec
*
* @param ctl_ch channel
* @param bw bandwidth
*
* @return > 0 if successful or 0 otherwise
*
*/
extern uint16 wf_channel2chspec(uint ctl_ch, uint bw);
extern uint wf_channel2freq(uint channel);
extern uint wf_freq2channel(uint freq);
/*
* Returns the 80+80 MHz chanspec corresponding to the following input parameters
*
* primary_20mhz - Primary 20 MHz channel
* chan0_80MHz - center channel number of one frequency segment
* chan1_80MHz - center channel number of the other frequency segment
*
* Parameters chan0_80MHz and chan1_80MHz are channel numbers in {42, 58, 106, 122, 138, 155}.
* The primary channel must be contained in one of the 80MHz channels. This routine
* will determine which frequency segment is the primary 80 MHz segment.
*
* Returns INVCHANSPEC in case of error.
*
* Refer to 802.11-2016 section 22.3.14 "Channelization".
*/
extern chanspec_t wf_chspec_get8080_chspec(uint8 primary_20mhz,
uint8 chan0_80Mhz, uint8 chan1_80Mhz);
/**
* Returns the center channel of the primary 80 MHz sub-band of the provided chanspec
*
* @param chspec input chanspec
*
* @return center channel number of the primary 80MHz sub-band of the input.
* Will return the center channel of an input 80MHz chspec.
* Will return INVCHANNEL if the chspec is malformed or less than 80MHz bw.
*/
extern uint8 wf_chspec_primary80_channel(chanspec_t chanspec);
/**
* Returns the center channel of the secondary 80 MHz sub-band of the provided chanspec
*
* @param chspec input chanspec
*
* @return center channel number of the secondary 80MHz sub-band of the input.
* Will return INVCHANNEL if the chspec is malformed or bw is not greater than 80MHz.
*/
extern uint8 wf_chspec_secondary80_channel(chanspec_t chanspec);
/**
* Returns the chanspec for the primary 80MHz sub-band of an 160MHz or 80+80 channel
*
* @param chspec input chanspec
*
* @return An 80MHz chanspec describing the primary 80MHz sub-band of the input.
* Will return an input 80MHz chspec as is.
* Will return INVCHANSPEC if the chspec is malformed or less than 80MHz bw.
*/
extern chanspec_t wf_chspec_primary80_chspec(chanspec_t chspec);
/**
* Returns the chanspec for the secondary 80MHz sub-band of an 160MHz or 80+80 channel
* The sideband in the chanspec is always set to WL_CHANSPEC_CTL_SB_LL since this sub-band
* does not contain the primary 20MHz channel.
*
* @param chspec input chanspec
*
* @return An 80MHz chanspec describing the secondary 80MHz sub-band of the input.
* Will return INVCHANSPEC if the chspec is malformed or bw is not greater than 80MHz.
*/
extern chanspec_t wf_chspec_secondary80_chspec(chanspec_t chspec);
/*
* For 160MHz or 80P80 chanspec, set ch[0]/ch[1] to be the low/high 80 Mhz channels
*
* For 20/40/80MHz chanspec, set ch[0] to be the center freq, and chan[1]=-1
*/
extern void wf_chspec_get_80p80_channels(chanspec_t chspec, uint8 *ch);
#ifdef WL11AC_80P80
/*
* This function returns the centre chanel for the given chanspec.
* In case of 80+80 chanspec it returns the primary 80 Mhz centre channel
*/
extern uint8 wf_chspec_channel(chanspec_t chspec);
#endif // endif
extern chanspec_t wf_channel_create_chspec_frm_opclass(uint8 opclass, uint8 channel);
extern int wf_channel_create_opclass_frm_chspec(chanspec_t chspec);
/* Populates array with all 20MHz side bands of a given chanspec_t in the following order:
* primary20, ext20, two ext40s, four ext80s.
* 'chspec' is the chanspec of interest
* 'pext' must point to an uint8 array of long enough to hold all side bands of the given chspec
*
* Works with 20, 40, 80, 80p80 and 160MHz chspec
*/
extern void wf_get_all_ext(chanspec_t chspec, uint8 *chan_ptr);
/*
* Given two chanspecs, returns true if they overlap.
* (Overlap: At least one 20MHz subband is common between the two chanspecs provided)
*/
extern bool wf_chspec_overlap(chanspec_t chspec0, chanspec_t chspec1);
extern uint8 channel_bw_to_width(chanspec_t chspec);
#endif /* _bcmwifi_channels_h_ */

View File

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

View File

@@ -0,0 +1,213 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Common OS-independent driver header for rate management.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmwifi_rspec.h 736703 2017-12-18 06:55:37Z $
*/
#ifndef _bcmwifi_rspec_h_
#define _bcmwifi_rspec_h_
#include <typedefs.h>
/**
* ===================================================================================
* rate spec : holds rate and mode specific information required to generate a tx frame.
* Legacy CCK and OFDM information is held in the same manner as was done in the past.
* (in the lower byte) the upper 3 bytes primarily hold MIMO specific information
* ===================================================================================
*/
typedef uint32 ratespec_t;
/* Rate spec. definitions */
#define WL_RSPEC_RATE_MASK 0x000000FF /**< Legacy rate or MCS or MCS + NSS */
#define WL_RSPEC_TXEXP_MASK 0x00000300 /**< Tx chain expansion beyond Nsts */
#define WL_RSPEC_TXEXP_SHIFT 8
#define WL_RSPEC_HE_GI_MASK 0x00000C00 /* HE GI indices */
#define WL_RSPEC_HE_GI_SHIFT 10
#define WL_RSPEC_BW_MASK 0x00070000 /**< Band width */
#define WL_RSPEC_BW_SHIFT 16
#define WL_RSPEC_DCM 0x00080000 /**< Dual Carrier Modulation */
#define WL_RSPEC_STBC 0x00100000 /**< STBC expansion, Nsts = 2 * Nss */
#define WL_RSPEC_TXBF 0x00200000
#define WL_RSPEC_LDPC 0x00400000
#define WL_RSPEC_SGI 0x00800000
#define WL_RSPEC_SHORT_PREAMBLE 0x00800000 /**< DSSS short preable - Encoding 0 */
#define WL_RSPEC_ENCODING_MASK 0x03000000 /**< Encoding of RSPEC_RATE field */
#define WL_RSPEC_ENCODING_SHIFT 24
#define WL_RSPEC_OVERRIDE_RATE 0x40000000 /**< override rate only */
#define WL_RSPEC_OVERRIDE_MODE 0x80000000 /**< override both rate & mode */
/* ======== RSPEC_HE_GI|RSPEC_SGI fields for HE ======== */
/* GI for HE */
#define RSPEC_HE_LTF_GI(rspec) (((rspec) & WL_RSPEC_HE_GI_MASK) >> WL_RSPEC_HE_GI_SHIFT)
#define WL_RSPEC_HE_1x_LTF_GI_0_8us (0x0)
#define WL_RSPEC_HE_2x_LTF_GI_0_8us (0x1)
#define WL_RSPEC_HE_2x_LTF_GI_1_6us (0x2)
#define WL_RSPEC_HE_4x_LTF_GI_3_2us (0x3)
#define RSPEC_ISHEGI(rspec) (RSPEC_HE_LTF_GI(rspec) > WL_RSPEC_HE_1x_LTF_GI_0_8us)
#define HE_GI_TO_RSPEC(gi) (((gi) << WL_RSPEC_HE_GI_SHIFT) & WL_RSPEC_HE_GI_MASK)
/* ======== RSPEC_RATE field ======== */
/* Encoding 0 - legacy rate */
/* DSSS, CCK, and OFDM rates in [500kbps] units */
#define WL_RSPEC_LEGACY_RATE_MASK 0x0000007F
#define WLC_RATE_1M 2
#define WLC_RATE_2M 4
#define WLC_RATE_5M5 11
#define WLC_RATE_11M 22
#define WLC_RATE_6M 12
#define WLC_RATE_9M 18
#define WLC_RATE_12M 24
#define WLC_RATE_18M 36
#define WLC_RATE_24M 48
#define WLC_RATE_36M 72
#define WLC_RATE_48M 96
#define WLC_RATE_54M 108
/* Encoding 1 - HT MCS */
#define WL_RSPEC_HT_MCS_MASK 0x0000007F /**< HT MCS value mask in rspec */
/* Encoding 2 - VHT MCS + NSS */
#define WL_RSPEC_VHT_MCS_MASK 0x0000000F /**< VHT MCS value mask in rspec */
#define WL_RSPEC_VHT_NSS_MASK 0x000000F0 /**< VHT Nss value mask in rspec */
#define WL_RSPEC_VHT_NSS_SHIFT 4 /**< VHT Nss value shift in rspec */
/* Encoding 3 - HE MCS + NSS */
#define WL_RSPEC_HE_MCS_MASK 0x0000000F /**< HE MCS value mask in rspec */
#define WL_RSPEC_HE_NSS_MASK 0x000000F0 /**< HE Nss value mask in rspec */
#define WL_RSPEC_HE_NSS_SHIFT 4 /**< HE Nss value shift in rpsec */
/* ======== RSPEC_BW field ======== */
#define WL_RSPEC_BW_UNSPECIFIED 0
#define WL_RSPEC_BW_20MHZ 0x00010000
#define WL_RSPEC_BW_40MHZ 0x00020000
#define WL_RSPEC_BW_80MHZ 0x00030000
#define WL_RSPEC_BW_160MHZ 0x00040000
/* ======== RSPEC_ENCODING field ======== */
#define WL_RSPEC_ENCODE_RATE 0x00000000 /**< Legacy rate is stored in RSPEC_RATE */
#define WL_RSPEC_ENCODE_HT 0x01000000 /**< HT MCS is stored in RSPEC_RATE */
#define WL_RSPEC_ENCODE_VHT 0x02000000 /**< VHT MCS and NSS are stored in RSPEC_RATE */
#define WL_RSPEC_ENCODE_HE 0x03000000 /**< HE MCS and NSS are stored in RSPEC_RATE */
/**
* ===============================
* Handy macros to parse rate spec
* ===============================
*/
#define RSPEC_BW(rspec) ((rspec) & WL_RSPEC_BW_MASK)
#define RSPEC_IS20MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_20MHZ)
#define RSPEC_IS40MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_40MHZ)
#define RSPEC_IS80MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_80MHZ)
#define RSPEC_IS160MHZ(rspec) (RSPEC_BW(rspec) == WL_RSPEC_BW_160MHZ)
#define RSPEC_ISSGI(rspec) (((rspec) & WL_RSPEC_SGI) != 0)
#define RSPEC_ISLDPC(rspec) (((rspec) & WL_RSPEC_LDPC) != 0)
#define RSPEC_ISSTBC(rspec) (((rspec) & WL_RSPEC_STBC) != 0)
#define RSPEC_ISTXBF(rspec) (((rspec) & WL_RSPEC_TXBF) != 0)
#define RSPEC_TXEXP(rspec) (((rspec) & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT)
#define RSPEC_ENCODE(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) >> WL_RSPEC_ENCODING_SHIFT)
#define RSPEC_ISLEGACY(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_RATE)
#define RSPEC_ISCCK(rspec) (RSPEC_ISLEGACY(rspec) && \
(int8)rate_info[(rspec) & WL_RSPEC_LEGACY_RATE_MASK] > 0)
#define RSPEC_ISOFDM(rspec) (RSPEC_ISLEGACY(rspec) && \
(int8)rate_info[(rspec) & WL_RSPEC_LEGACY_RATE_MASK] < 0)
#define RSPEC_ISHT(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HT)
#ifdef WL11AC
#define RSPEC_ISVHT(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_VHT)
#else /* WL11AC */
#define RSPEC_ISVHT(rspec) 0
#endif /* WL11AC */
#ifdef WL11AX
#define RSPEC_ISHE(rspec) (((rspec) & WL_RSPEC_ENCODING_MASK) == WL_RSPEC_ENCODE_HE)
#else /* WL11AX */
#define RSPEC_ISHE(rspec) 0
#endif /* WL11AX */
/**
* ================================
* Handy macros to create rate spec
* ================================
*/
/* create ratespecs */
#define LEGACY_RSPEC(rate) (WL_RSPEC_ENCODE_RATE | WL_RSPEC_BW_20MHZ | \
((rate) & WL_RSPEC_LEGACY_RATE_MASK))
#define CCK_RSPEC(cck) LEGACY_RSPEC(cck)
#define OFDM_RSPEC(ofdm) LEGACY_RSPEC(ofdm)
#define HT_RSPEC(mcs) (WL_RSPEC_ENCODE_HT | ((mcs) & WL_RSPEC_HT_MCS_MASK))
#define VHT_RSPEC(mcs, nss) (WL_RSPEC_ENCODE_VHT | \
(((nss) << WL_RSPEC_VHT_NSS_SHIFT) & WL_RSPEC_VHT_NSS_MASK) | \
((mcs) & WL_RSPEC_VHT_MCS_MASK))
#define HE_RSPEC(mcs, nss) (WL_RSPEC_ENCODE_HE | \
(((nss) << WL_RSPEC_HE_NSS_SHIFT) & WL_RSPEC_HE_NSS_MASK) | \
((mcs) & WL_RSPEC_HE_MCS_MASK))
/**
* ==================
* Other handy macros
* ==================
*/
/* return rate in unit of Kbps */
#define RSPEC2KBPS(rspec) wf_rspec_to_rate(rspec)
/* return rate in unit of 500Kbps */
#define RSPEC2RATE(rspec) ((rspec) & WL_RSPEC_LEGACY_RATE_MASK)
/**
* =================================
* Macros to use the rate_info table
* =================================
*/
/* phy_rate table index is in [500kbps] units */
#define WLC_MAXRATE 108 /**< in 500kbps units */
extern const uint8 rate_info[];
/* phy_rate table value is encoded */
#define RATE_INFO_OFDM_MASK 0x80 /* ofdm mask */
#define RATE_INFO_RATE_MASK 0x7f /* rate signal index mask */
#define RATE_INFO_M_RATE_MASK 0x0f /* M_RATE_TABLE index mask */
#define RATE_INFO_RATE_ISCCK(r) ((r) <= WLC_MAXRATE && (int8)rate_info[r] > 0)
#define RATE_INFO_RATE_ISOFDM(r) ((r) <= WLC_MAXRATE && (int8)rate_info[r] < 0)
/**
* ===================
* function prototypes
* ===================
*/
ratespec_t wf_vht_plcp_to_rspec(uint8 *plcp);
ratespec_t wf_he_plcp_to_rspec(uint8 *plcp);
uint wf_rspec_to_rate(ratespec_t rspec);
#endif /* _bcmwifi_rspec_h_ */

View File

@@ -0,0 +1,623 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Driver O/S-independent utility routines
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmxtlv.c 788740 2018-11-13 21:45:01Z $
*/
#include <bcm_cfg.h>
#include <typedefs.h>
#include <bcmdefs.h>
#include <stdarg.h>
#ifdef BCMDRIVER
#include <osl.h>
#else /* !BCMDRIVER */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifndef ASSERT
#define ASSERT(exp)
#endif // endif
#endif /* !BCMDRIVER */
#include <bcmtlv.h>
#include <bcmendian.h>
#include <bcmutils.h>
int
bcm_xtlv_hdr_size(bcm_xtlv_opts_t opts)
{
int len = (int)OFFSETOF(bcm_xtlv_t, data); /* nominal */
if (opts & BCM_XTLV_OPTION_LENU8) --len;
if (opts & BCM_XTLV_OPTION_IDU8) --len;
return len;
}
bool
bcm_valid_xtlv(const bcm_xtlv_t *elt, int buf_len, bcm_xtlv_opts_t opts)
{
return elt != NULL &&
buf_len >= bcm_xtlv_hdr_size(opts) &&
buf_len >= bcm_xtlv_size(elt, opts);
}
int
bcm_xtlv_size_for_data(int dlen, bcm_xtlv_opts_t opts)
{
int hsz;
hsz = bcm_xtlv_hdr_size(opts);
return ((opts & BCM_XTLV_OPTION_ALIGN32) ? ALIGN_SIZE(dlen + hsz, 4)
: (dlen + hsz));
}
int
bcm_xtlv_size(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts)
{
int size; /* size including header, data, and any pad */
int len; /* length wthout padding */
len = BCM_XTLV_LEN_EX(elt, opts);
size = bcm_xtlv_size_for_data(len, opts);
return size;
}
int
bcm_xtlv_len(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts)
{
const uint8 *lenp;
int len;
lenp = (const uint8 *)&elt->len; /* nominal */
if (opts & BCM_XTLV_OPTION_IDU8) {
--lenp;
}
if (opts & BCM_XTLV_OPTION_LENU8) {
len = *lenp;
} else if (opts & BCM_XTLV_OPTION_LENBE) {
len = (uint32)hton16(elt->len);
} else {
len = ltoh16_ua(lenp);
}
return len;
}
int
bcm_xtlv_id(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts)
{
int id = 0;
if (opts & BCM_XTLV_OPTION_IDU8) {
id = *(const uint8 *)elt;
} else if (opts & BCM_XTLV_OPTION_IDBE) {
id = (uint32)hton16(elt->id);
} else {
id = ltoh16_ua((const uint8 *)elt);
}
return id;
}
bcm_xtlv_t *
bcm_next_xtlv(const bcm_xtlv_t *elt, int *buflen, bcm_xtlv_opts_t opts)
{
int sz;
/* advance to next elt */
sz = BCM_XTLV_SIZE_EX(elt, opts);
elt = (const bcm_xtlv_t*)((const uint8 *)elt + sz);
*buflen -= sz;
/* validate next elt */
if (!bcm_valid_xtlv(elt, *buflen, opts))
return NULL;
GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST();
return (bcm_xtlv_t *)(elt);
GCC_DIAGNOSTIC_POP();
}
int
bcm_xtlv_buf_init(bcm_xtlvbuf_t *tlv_buf, uint8 *buf, uint16 len, bcm_xtlv_opts_t opts)
{
if (!tlv_buf || !buf || !len)
return BCME_BADARG;
tlv_buf->opts = opts;
tlv_buf->size = len;
tlv_buf->head = buf;
tlv_buf->buf = buf;
return BCME_OK;
}
uint16
bcm_xtlv_buf_len(bcm_xtlvbuf_t *tbuf)
{
uint16 len;
if (tbuf)
len = (uint16)(tbuf->buf - tbuf->head);
else
len = 0;
return len;
}
uint16
bcm_xtlv_buf_rlen(bcm_xtlvbuf_t *tbuf)
{
uint16 rlen;
if (tbuf)
rlen = tbuf->size - bcm_xtlv_buf_len(tbuf);
else
rlen = 0;
return rlen;
}
uint8 *
bcm_xtlv_buf(bcm_xtlvbuf_t *tbuf)
{
return tbuf ? tbuf->buf : NULL;
}
uint8 *
bcm_xtlv_head(bcm_xtlvbuf_t *tbuf)
{
return tbuf ? tbuf->head : NULL;
}
void
bcm_xtlv_pack_xtlv(bcm_xtlv_t *xtlv, uint16 type, uint16 len, const uint8 *data,
bcm_xtlv_opts_t opts)
{
uint8 *data_buf;
bcm_xtlv_opts_t mask = BCM_XTLV_OPTION_IDU8 | BCM_XTLV_OPTION_LENU8;
if (!(opts & mask)) { /* default */
uint8 *idp = (uint8 *)xtlv;
uint8 *lenp = idp + sizeof(xtlv->id);
htol16_ua_store(type, idp);
htol16_ua_store(len, lenp);
data_buf = lenp + sizeof(uint16);
} else if ((opts & mask) == mask) { /* u8 id and u8 len */
uint8 *idp = (uint8 *)xtlv;
uint8 *lenp = idp + 1;
*idp = (uint8)type;
*lenp = (uint8)len;
data_buf = lenp + sizeof(uint8);
} else if (opts & BCM_XTLV_OPTION_IDU8) { /* u8 id, u16 len */
uint8 *idp = (uint8 *)xtlv;
uint8 *lenp = idp + 1;
*idp = (uint8)type;
htol16_ua_store(len, lenp);
data_buf = lenp + sizeof(uint16);
} else if (opts & BCM_XTLV_OPTION_LENU8) { /* u16 id, u8 len */
uint8 *idp = (uint8 *)xtlv;
uint8 *lenp = idp + sizeof(uint16);
htol16_ua_store(type, idp);
*lenp = (uint8)len;
data_buf = lenp + sizeof(uint8);
} else {
bool Unexpected_xtlv_option = TRUE;
BCM_REFERENCE(Unexpected_xtlv_option);
ASSERT(!Unexpected_xtlv_option);
return;
}
if (opts & BCM_XTLV_OPTION_LENU8) {
ASSERT(len <= 0x00ff);
len &= 0xff;
}
if (data != NULL)
memcpy(data_buf, data, len);
}
/* xtlv header is always packed in LE order */
void
bcm_xtlv_unpack_xtlv(const bcm_xtlv_t *xtlv, uint16 *type, uint16 *len,
const uint8 **data, bcm_xtlv_opts_t opts)
{
if (type)
*type = (uint16)bcm_xtlv_id(xtlv, opts);
if (len)
*len = (uint16)bcm_xtlv_len(xtlv, opts);
if (data)
*data = (const uint8 *)xtlv + BCM_XTLV_HDR_SIZE_EX(opts);
}
int
bcm_xtlv_put_data(bcm_xtlvbuf_t *tbuf, uint16 type, const uint8 *data, int n)
{
bcm_xtlv_t *xtlv;
int size;
if (tbuf == NULL)
return BCME_BADARG;
size = bcm_xtlv_size_for_data(n, tbuf->opts);
if (bcm_xtlv_buf_rlen(tbuf) < size)
return BCME_NOMEM;
xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf);
bcm_xtlv_pack_xtlv(xtlv, type, (uint16)n, data, tbuf->opts);
tbuf->buf += size; /* note: data may be NULL, reserves space */
return BCME_OK;
}
static int
bcm_xtlv_put_int(bcm_xtlvbuf_t *tbuf, uint16 type, const uint8 *data, int n, int int_sz)
{
bcm_xtlv_t *xtlv;
int xtlv_len;
uint8 *xtlv_data;
int err = BCME_OK;
if (tbuf == NULL) {
err = BCME_BADARG;
goto done;
}
xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf);
/* put type and length in xtlv and reserve data space */
xtlv_len = n * int_sz;
err = bcm_xtlv_put_data(tbuf, type, NULL, xtlv_len);
if (err != BCME_OK)
goto done;
xtlv_data = (uint8 *)xtlv + bcm_xtlv_hdr_size(tbuf->opts);
/* write data w/ little-endianness into buffer - single loop, aligned access */
for (; n != 0; --n, xtlv_data += int_sz, data += int_sz) {
switch (int_sz) {
case sizeof(uint8):
break;
case sizeof(uint16):
{
uint16 v = load16_ua(data);
htol16_ua_store(v, xtlv_data);
break;
}
case sizeof(uint32):
{
uint32 v = load32_ua(data);
htol32_ua_store(v, xtlv_data);
break;
}
case sizeof(uint64):
{
uint64 v = load64_ua(data);
htol64_ua_store(v, xtlv_data);
break;
}
default:
err = BCME_UNSUPPORTED;
goto done;
}
}
done:
return err;
}
int
bcm_xtlv_put16(bcm_xtlvbuf_t *tbuf, uint16 type, const uint16 *data, int n)
{
return bcm_xtlv_put_int(tbuf, type, (const uint8 *)data, n, sizeof(uint16));
}
int
bcm_xtlv_put32(bcm_xtlvbuf_t *tbuf, uint16 type, const uint32 *data, int n)
{
return bcm_xtlv_put_int(tbuf, type, (const uint8 *)data, n, sizeof(uint32));
}
int
bcm_xtlv_put64(bcm_xtlvbuf_t *tbuf, uint16 type, const uint64 *data, int n)
{
return bcm_xtlv_put_int(tbuf, type, (const uint8 *)data, n, sizeof(uint64));
}
/*
* upacks xtlv record from buf checks the type
* copies data to callers buffer
* advances tlv pointer to next record
* caller's resposible for dst space check
*/
int
bcm_unpack_xtlv_entry(const uint8 **tlv_buf, uint16 xpct_type, uint16 xpct_len,
uint8 *dst_data, bcm_xtlv_opts_t opts)
{
const bcm_xtlv_t *ptlv = (const bcm_xtlv_t *)*tlv_buf;
uint16 len;
uint16 type;
const uint8 *data;
ASSERT(ptlv);
bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts);
if (len) {
if ((type != xpct_type) || (len > xpct_len))
return BCME_BADARG;
if (dst_data && data)
memcpy(dst_data, data, len); /* copy data to dst */
}
*tlv_buf += BCM_XTLV_SIZE_EX(ptlv, opts);
return BCME_OK;
}
/*
* packs user data into tlv record and advances tlv pointer to next xtlv slot
* buflen is used for tlv_buf space check
*/
int
bcm_pack_xtlv_entry(uint8 **tlv_buf, uint16 *buflen, uint16 type, uint16 len,
const uint8 *src_data, bcm_xtlv_opts_t opts)
{
bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf;
int size;
ASSERT(ptlv);
size = bcm_xtlv_size_for_data(len, opts);
/* copy data from tlv buffer to dst provided by user */
if (size > *buflen)
return BCME_BADLEN;
bcm_xtlv_pack_xtlv(ptlv, type, len, src_data, opts);
/* advance callers pointer to tlv buff */
*tlv_buf = (uint8*)(*tlv_buf) + size;
/* decrement the len */
*buflen -= (uint16)size;
return BCME_OK;
}
/*
* unpack all xtlv records from the issue a callback
* to set function one call per found tlv record
*/
int
bcm_unpack_xtlv_buf(void *ctx, const uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts,
bcm_xtlv_unpack_cbfn_t *cbfn)
{
uint16 len;
uint16 type;
int res = BCME_OK;
int size;
const bcm_xtlv_t *ptlv;
int sbuflen = buflen;
const uint8 *data;
int hdr_size;
ASSERT(!buflen || tlv_buf);
ASSERT(!buflen || cbfn);
hdr_size = BCM_XTLV_HDR_SIZE_EX(opts);
while (sbuflen >= hdr_size) {
ptlv = (const bcm_xtlv_t *)tlv_buf;
bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts);
size = bcm_xtlv_size_for_data(len, opts);
sbuflen -= size;
if (sbuflen < 0) /* check for buffer overrun */
break;
if ((res = cbfn(ctx, data, type, len)) != BCME_OK)
break;
tlv_buf += size;
}
return res;
}
int
bcm_pack_xtlv_buf(void *ctx, uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts,
bcm_pack_xtlv_next_info_cbfn_t get_next, bcm_pack_xtlv_pack_next_cbfn_t pack_next,
int *outlen)
{
int res = BCME_OK;
uint16 tlv_id;
uint16 tlv_len;
uint8 *startp;
uint8 *endp;
uint8 *buf;
bool more;
int size;
int hdr_size;
ASSERT(get_next && pack_next);
buf = tlv_buf;
startp = buf;
endp = (uint8 *)buf + buflen;
more = TRUE;
hdr_size = BCM_XTLV_HDR_SIZE_EX(opts);
while (more && (buf < endp)) {
more = get_next(ctx, &tlv_id, &tlv_len);
size = bcm_xtlv_size_for_data(tlv_len, opts);
if ((buf + size) > endp) {
res = BCME_BUFTOOSHORT;
goto done;
}
bcm_xtlv_pack_xtlv((bcm_xtlv_t *)buf, tlv_id, tlv_len, NULL, opts);
pack_next(ctx, tlv_id, tlv_len, buf + hdr_size);
buf += size;
}
if (more)
res = BCME_BUFTOOSHORT;
done:
if (outlen) {
*outlen = (int)(buf - startp);
}
return res;
}
/*
* pack xtlv buffer from memory according to xtlv_desc_t
*/
int
bcm_pack_xtlv_buf_from_mem(uint8 **tlv_buf, uint16 *buflen, const xtlv_desc_t *items,
bcm_xtlv_opts_t opts)
{
int res = BCME_OK;
uint8 *ptlv = *tlv_buf;
while (items->type != 0) {
if (items->len && items->ptr) {
res = bcm_pack_xtlv_entry(&ptlv, buflen, items->type,
items->len, items->ptr, opts);
if (res != BCME_OK)
break;
}
items++;
}
*tlv_buf = ptlv; /* update the external pointer */
return res;
}
/*
* unpack xtlv buffer to memory according to xtlv_desc_t
*
*/
int
bcm_unpack_xtlv_buf_to_mem(uint8 *tlv_buf, int *buflen, xtlv_desc_t *items,
bcm_xtlv_opts_t opts)
{
int res = BCME_OK;
bcm_xtlv_t *elt;
elt = bcm_valid_xtlv((bcm_xtlv_t *)tlv_buf, *buflen, opts) ? (bcm_xtlv_t *)tlv_buf : NULL;
if (!elt || !items) {
res = BCME_BADARG;
return res;
}
for (; elt != NULL && res == BCME_OK; elt = bcm_next_xtlv(elt, buflen, opts)) {
/* find matches in desc_t items */
xtlv_desc_t *dst_desc = items;
uint16 len, type;
const uint8 *data;
bcm_xtlv_unpack_xtlv(elt, &type, &len, &data, opts);
while (dst_desc->type != 0) {
if (type == dst_desc->type) {
if (len != dst_desc->len) {
res = BCME_BADLEN;
} else {
memcpy(dst_desc->ptr, data, len);
}
break;
}
dst_desc++;
}
}
if (res == BCME_OK && *buflen != 0)
res = BCME_BUFTOOSHORT;
return res;
}
/*
* return data pointer of a given ID from xtlv buffer.
* If the specified xTLV ID is found, on return *datalen will contain
* the the data length of the xTLV ID.
*/
const uint8*
bcm_get_data_from_xtlv_buf(const uint8 *tlv_buf, uint16 buflen, uint16 id,
uint16 *datalen, bcm_xtlv_opts_t opts)
{
const uint8 *retptr = NULL;
uint16 type, len;
int size;
const bcm_xtlv_t *ptlv;
int sbuflen = buflen;
const uint8 *data;
int hdr_size;
hdr_size = BCM_XTLV_HDR_SIZE_EX(opts);
/* Init the datalength */
if (datalen) {
*datalen = 0;
}
while (sbuflen >= hdr_size) {
ptlv = (const bcm_xtlv_t *)tlv_buf;
bcm_xtlv_unpack_xtlv(ptlv, &type, &len, &data, opts);
size = bcm_xtlv_size_for_data(len, opts);
sbuflen -= size;
if (sbuflen < 0) /* buffer overrun? */
break;
if (id == type) {
retptr = data;
if (datalen)
*datalen = len;
break;
}
tlv_buf += size;
}
return retptr;
}
bcm_xtlv_t*
bcm_xtlv_bcopy(const bcm_xtlv_t *src, bcm_xtlv_t *dst,
int src_buf_len, int dst_buf_len, bcm_xtlv_opts_t opts)
{
bcm_xtlv_t *dst_next = NULL;
src = (src && bcm_valid_xtlv(src, src_buf_len, opts)) ? src : NULL;
if (src && dst) {
uint16 type;
uint16 len;
const uint8 *data;
int size;
bcm_xtlv_unpack_xtlv(src, &type, &len, &data, opts);
size = bcm_xtlv_size_for_data(len, opts);
if (size <= dst_buf_len) {
bcm_xtlv_pack_xtlv(dst, type, len, data, opts);
dst_next = (bcm_xtlv_t *)((uint8 *)dst + size);
}
}
return dst_next;
}

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,352 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Header file describing the internal (inter-module) DHD interfaces.
*
* Provides type definitions and function prototypes used to link the
* DHD OS, bus, and protocol modules.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_bus.h 814378 2019-04-11 02:21:31Z $
*/
#ifndef _dhd_bus_h_
#define _dhd_bus_h_
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)
*/
/* global variable for the bus */
extern struct dhd_bus *g_dhd_bus;
/* Indicate (dis)interest in finding dongles. */
extern int dhd_bus_register(void);
extern void dhd_bus_unregister(void);
/* Download firmware image and nvram image */
extern int dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
char *fw_path, char *nv_path, char *clm_path, char *conf_path);
#if defined(BT_OVER_SDIO)
extern int dhd_bus_download_btfw(struct dhd_bus *bus, osl_t *osh, char *btfw_path);
#endif /* defined (BT_OVER_SDIO) */
/* Stop bus module: clear pending frames, disable data flow */
extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex);
/* Initialize bus module: prepare for communication w/dongle */
extern int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex);
/* Get the Bus Idle Time */
extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int *idletime);
/* Set the Bus Idle Time */
extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time);
/* Send a data frame to the dongle. Callee disposes of txp. */
#ifdef BCMPCIE
extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx);
#else
extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp);
#endif // endif
#ifdef BCMPCIE
extern void dhdpcie_cto_recovery_handler(dhd_pub_t *dhd);
#endif /* BCMPCIE */
/* Send/receive a control message to/from the dongle.
* Expects caller to enforce a single outstanding transaction.
*/
extern int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen);
extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen);
/* Watchdog timer function */
extern bool dhd_bus_watchdog(dhd_pub_t *dhd);
extern int dhd_bus_oob_intr_register(dhd_pub_t *dhdp);
extern void dhd_bus_oob_intr_unregister(dhd_pub_t *dhdp);
extern void dhd_bus_oob_intr_set(dhd_pub_t *dhdp, bool enable);
extern void dhd_bus_dev_pm_stay_awake(dhd_pub_t *dhdpub);
extern void dhd_bus_dev_pm_relax(dhd_pub_t *dhdpub);
extern bool dhd_bus_dev_pm_enabled(dhd_pub_t *dhdpub);
/* Device console input function */
extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen);
#ifdef CONSOLE_DPC
extern int dhd_bus_txcons(dhd_pub_t *dhd, uchar *msg, uint msglen);
#endif
/* Deferred processing for the bus, return TRUE requests reschedule */
extern bool dhd_bus_dpc(struct dhd_bus *bus);
extern void dhd_bus_isr(bool * InterruptRecognized, bool * QueueMiniportHandleInterrupt, void *arg);
/* Check for and handle local prot-specific iovar commands */
extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
void *params, int plen, void *arg, int len, bool set);
/* Add bus dump output to a buffer */
extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
/* Clear any bus counters */
extern void dhd_bus_clearcounts(dhd_pub_t *dhdp);
/* return the dongle chipid */
extern uint dhd_bus_chip(struct dhd_bus *bus);
/* return the dongle chiprev */
extern uint dhd_bus_chiprev(struct dhd_bus *bus);
/* Set user-specified nvram parameters. */
extern void dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params);
extern void *dhd_bus_pub(struct dhd_bus *bus);
extern void *dhd_bus_txq(struct dhd_bus *bus);
extern void *dhd_bus_sih(struct dhd_bus *bus);
extern uint dhd_bus_hdrlen(struct dhd_bus *bus);
#ifdef BCMSDIO
extern void dhd_bus_set_dotxinrx(struct dhd_bus *bus, bool val);
/* return sdio io status */
extern uint8 dhd_bus_is_ioready(struct dhd_bus *bus);
#else
#define dhd_bus_set_dotxinrx(a, b) do {} while (0)
#endif // endif
#define DHD_SET_BUS_STATE_DOWN(_bus) do { \
(_bus)->dhd->busstate = DHD_BUS_DOWN; \
} while (0)
/* Register a dummy SDIO client driver in order to be notified of new SDIO device */
extern int dhd_bus_reg_sdio_notify(void* semaphore);
extern void dhd_bus_unreg_sdio_notify(void);
extern void dhd_txglom_enable(dhd_pub_t *dhdp, bool enable);
extern int dhd_bus_get_ids(struct dhd_bus *bus, uint32 *bus_type, uint32 *bus_num,
uint32 *slot_num);
#if defined(DHD_FW_COREDUMP) && (defined(BCMPCIE) || defined(BCMSDIO))
extern int dhd_bus_mem_dump(dhd_pub_t *dhd);
extern int dhd_bus_get_mem_dump(dhd_pub_t *dhdp);
#else
#define dhd_bus_mem_dump(x)
#define dhd_bus_get_mem_dump(x)
#endif /* DHD_FW_COREDUMP && (BCMPCIE || BCMSDIO) */
#ifdef BCMPCIE
enum {
/* Scratch buffer confiuguration update */
D2H_DMA_SCRATCH_BUF,
D2H_DMA_SCRATCH_BUF_LEN,
/* DMA Indices array buffers for: H2D WR and RD, and D2H WR and RD */
H2D_DMA_INDX_WR_BUF, /* update H2D WR dma indices buf base addr to dongle */
H2D_DMA_INDX_RD_BUF, /* update H2D RD dma indices buf base addr to dongle */
D2H_DMA_INDX_WR_BUF, /* update D2H WR dma indices buf base addr to dongle */
D2H_DMA_INDX_RD_BUF, /* update D2H RD dma indices buf base addr to dongle */
/* DHD sets/gets WR or RD index, in host's H2D and D2H DMA indices buffer */
H2D_DMA_INDX_WR_UPD, /* update H2D WR index in H2D WR dma indices buf */
H2D_DMA_INDX_RD_UPD, /* update H2D RD index in H2D RD dma indices buf */
D2H_DMA_INDX_WR_UPD, /* update D2H WR index in D2H WR dma indices buf */
D2H_DMA_INDX_RD_UPD, /* update D2H RD index in D2H RD dma indices buf */
/* DHD Indices array buffers and update for: H2D flow ring WR */
H2D_IFRM_INDX_WR_BUF, /* update H2D WR dma indices buf base addr to dongle */
H2D_IFRM_INDX_WR_UPD, /* update H2D WR dma indices buf base addr to dongle */
/* H2D and D2H Mailbox data update */
H2D_MB_DATA,
D2H_MB_DATA,
/* (Common) MsgBuf Ring configuration update */
RING_BUF_ADDR, /* update ring base address to dongle */
RING_ITEM_LEN, /* update ring item size to dongle */
RING_MAX_ITEMS, /* update ring max items to dongle */
/* Update of WR or RD index, for a MsgBuf Ring */
RING_RD_UPD, /* update ring read index from/to dongle */
RING_WR_UPD, /* update ring write index from/to dongle */
TOTAL_LFRAG_PACKET_CNT,
MAX_HOST_RXBUFS,
HOST_API_VERSION,
DNGL_TO_HOST_TRAP_ADDR,
HOST_SCB_ADDR, /* update host scb base address to dongle */
};
typedef void (*dhd_mb_ring_t) (struct dhd_bus *, uint32);
typedef void (*dhd_mb_ring_2_t) (struct dhd_bus *, uint32, bool);
extern void dhd_bus_cmn_writeshared(struct dhd_bus *bus, void * data, uint32 len, uint8 type,
uint16 ringid);
extern void dhd_bus_ringbell(struct dhd_bus *bus, uint32 value);
extern void dhd_bus_ringbell_2(struct dhd_bus *bus, uint32 value, bool devwake);
extern void dhd_bus_cmn_readshared(struct dhd_bus *bus, void* data, uint8 type, uint16 ringid);
extern uint32 dhd_bus_get_sharedflags(struct dhd_bus *bus);
extern void dhd_bus_rx_frame(struct dhd_bus *bus, void* pkt, int ifidx, uint pkt_count);
extern void dhd_bus_start_queue(struct dhd_bus *bus);
extern void dhd_bus_stop_queue(struct dhd_bus *bus);
extern dhd_mb_ring_t dhd_bus_get_mbintr_fn(struct dhd_bus *bus);
extern dhd_mb_ring_2_t dhd_bus_get_mbintr_2_fn(struct dhd_bus *bus);
extern void dhd_bus_write_flow_ring_states(struct dhd_bus *bus,
void * data, uint16 flowid);
extern void dhd_bus_read_flow_ring_states(struct dhd_bus *bus,
void * data, uint8 flowid);
extern int dhd_bus_flow_ring_create_request(struct dhd_bus *bus, void *flow_ring_node);
extern void dhd_bus_clean_flow_ring(struct dhd_bus *bus, void *flow_ring_node);
extern void dhd_bus_flow_ring_create_response(struct dhd_bus *bus, uint16 flow_id, int32 status);
extern int dhd_bus_flow_ring_delete_request(struct dhd_bus *bus, void *flow_ring_node);
extern void dhd_bus_flow_ring_delete_response(struct dhd_bus *bus, uint16 flowid, uint32 status);
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);
#ifdef IDLE_TX_FLOW_MGMT
extern void dhd_bus_flow_ring_resume_response(struct dhd_bus *bus, uint16 flowid, int32 status);
#endif /* IDLE_TX_FLOW_MGMT */
extern int dhdpcie_bus_clock_start(struct dhd_bus *bus);
extern int dhdpcie_bus_clock_stop(struct dhd_bus *bus);
extern int dhdpcie_bus_enable_device(struct dhd_bus *bus);
extern int dhdpcie_bus_disable_device(struct dhd_bus *bus);
extern int dhdpcie_bus_alloc_resource(struct dhd_bus *bus);
extern void dhdpcie_bus_free_resource(struct dhd_bus *bus);
extern bool dhdpcie_bus_dongle_attach(struct dhd_bus *bus);
extern int dhd_bus_release_dongle(struct dhd_bus *bus);
extern int dhd_bus_request_irq(struct dhd_bus *bus);
extern int dhdpcie_get_pcieirq(struct dhd_bus *bus, unsigned int *irq);
extern void dhd_bus_aer_config(struct dhd_bus *bus);
extern struct device * dhd_bus_to_dev(struct dhd_bus *bus);
extern int dhdpcie_cto_init(struct dhd_bus *bus, bool enable);
extern int dhdpcie_cto_cfg_init(struct dhd_bus *bus, bool enable);
extern void dhdpcie_ssreset_dis_enum_rst(struct dhd_bus *bus);
#ifdef DHD_FW_COREDUMP
extern int dhd_dongle_mem_dump(void);
#endif /* DHD_FW_COREDUMP */
#ifdef IDLE_TX_FLOW_MGMT
extern void dhd_bus_idle_tx_ring_suspend(dhd_pub_t *dhd, uint16 flow_ring_id);
#endif /* IDLE_TX_FLOW_MGMT */
extern void dhd_bus_handle_mb_data(struct dhd_bus *bus, uint32 d2h_mb_data);
#endif /* BCMPCIE */
/* dump the device trap informtation */
extern void dhd_bus_dump_trap_info(struct dhd_bus *bus, struct bcmstrbuf *b);
extern void dhd_bus_copy_trap_sig(struct dhd_bus *bus, trap_t *tr);
/* Function to set default min res mask */
extern bool dhd_bus_set_default_min_res_mask(struct dhd_bus *bus);
/* Function to reset PMU registers */
extern void dhd_bus_pmu_reg_reset(dhd_pub_t *dhdp);
extern void dhd_bus_ucode_download(struct dhd_bus *bus);
#ifdef DHD_ULP
extern void dhd_bus_ulp_disable_console(dhd_pub_t *dhdp);
#endif /* DHD_ULP */
extern int dhd_bus_readwrite_bp_addr(dhd_pub_t *dhdp, uint addr, uint size, uint* data, bool read);
extern int dhd_get_idletime(dhd_pub_t *dhd);
#ifdef BCMPCIE
extern void dhd_bus_dump_console_buffer(struct dhd_bus *bus);
extern void dhd_bus_intr_count_dump(dhd_pub_t *dhdp);
extern void dhd_bus_set_dpc_sched_time(dhd_pub_t *dhdp);
extern bool dhd_bus_query_dpc_sched_errors(dhd_pub_t *dhdp);
extern int dhd_bus_dmaxfer_lpbk(dhd_pub_t *dhdp, uint32 type);
extern bool dhd_bus_check_driver_up(void);
extern int dhd_bus_get_cto(dhd_pub_t *dhdp);
extern void dhd_bus_set_linkdown(dhd_pub_t *dhdp, bool val);
extern int dhd_bus_get_linkdown(dhd_pub_t *dhdp);
#else
#define dhd_bus_dump_console_buffer(x)
static INLINE void dhd_bus_intr_count_dump(dhd_pub_t *dhdp) { UNUSED_PARAMETER(dhdp); }
static INLINE void dhd_bus_set_dpc_sched_time(dhd_pub_t *dhdp) { }
static INLINE bool dhd_bus_query_dpc_sched_errors(dhd_pub_t *dhdp) { return 0; }
static INLINE int dhd_bus_dmaxfer_lpbk(dhd_pub_t *dhdp, uint32 type) { return 0; }
static INLINE bool dhd_bus_check_driver_up(void) { return FALSE; }
extern INLINE void dhd_bus_set_linkdown(dhd_pub_t *dhdp, bool val) { }
extern INLINE int dhd_bus_get_linkdown(dhd_pub_t *dhdp) { return 0; }
static INLINE int dhd_bus_get_cto(dhd_pub_t *dhdp) { return 0; }
#endif /* BCMPCIE */
#if defined(BCMPCIE) && defined(EWP_ETD_PRSRV_LOGS)
void dhdpcie_get_etd_preserve_logs(dhd_pub_t *dhd, uint8 *ext_trap_data,
void *event_decode_data);
#endif // endif
extern uint16 dhd_get_chipid(dhd_pub_t *dhd);
#ifdef DHD_WAKE_STATUS
extern wake_counts_t* dhd_bus_get_wakecount(dhd_pub_t *dhd);
extern int dhd_bus_get_bus_wake(dhd_pub_t * dhd);
#endif /* DHD_WAKE_STATUS */
#ifdef BT_OVER_SDIO
/*
* SDIO layer clock control functions exposed to be called from other layers.
* This is required especially in the case where the BUS is shared between
* BT and SDIO and we have to control the clock. The callers of this function
* are expected to hold the sdlock
*/
int __dhdsdio_clk_enable(struct dhd_bus *bus, bus_owner_t owner, int can_wait);
int __dhdsdio_clk_disable(struct dhd_bus *bus, bus_owner_t owner, int can_wait);
void dhdsdio_reset_bt_use_count(struct dhd_bus *bus);
#endif /* BT_OVER_SDIO */
int dhd_bus_perform_flr(struct dhd_bus *bus, bool force_fail);
extern bool dhd_bus_get_flr_force_fail(struct dhd_bus *bus);
extern bool dhd_bus_aspm_enable_rc_ep(struct dhd_bus *bus, bool enable);
extern void dhd_bus_l1ss_enable_rc_ep(struct dhd_bus *bus, bool enable);
bool dhd_bus_is_multibp_capable(struct dhd_bus *bus);
#ifdef BCMPCIE
extern void dhdpcie_advertise_bus_cleanup(dhd_pub_t *dhdp);
extern void dhd_msgbuf_iovar_timeout_dump(dhd_pub_t *dhd);
#endif /* BCMPCIE */
extern bool dhd_bus_force_bt_quiesce_enabled(struct dhd_bus *bus);
#ifdef DHD_SSSR_DUMP
extern int dhd_bus_fis_trigger(dhd_pub_t *dhd);
extern int dhd_bus_fis_dump(dhd_pub_t *dhd);
#endif /* DHD_SSSR_DUMP */
#ifdef PCIE_FULL_DONGLE
extern int dhdpcie_set_dma_ring_indices(dhd_pub_t *dhd, int32 int_val);
#endif /* PCIE_FULL_DONGLE */
#ifdef DHD_USE_BP_RESET
extern int dhd_bus_perform_bp_reset(struct dhd_bus *bus);
#endif /* DHD_USE_BP_RESET */
extern void dhd_bwm_bt_quiesce(struct dhd_bus *bus);
extern void dhd_bwm_bt_resume(struct dhd_bus *bus);
#endif /* _dhd_bus_h_ */

View File

@@ -0,0 +1,38 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _DHD_BUZZZ_H_INCLUDED_
#define _DHD_BUZZZ_H_INCLUDED_
/*
* Broadcom logging system - Empty implementaiton
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id$
*/
#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_H_INCLUDED_ */

View File

@@ -0,0 +1,981 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* DHD Protocol Module for CDC and BDC.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_cdc.c 752794 2018-03-19 04:00:31Z $
*
* BDC is like CDC, except it includes a header for data packets to convey
* packet priority over the bus, and flags (e.g. to indicate checksum status
* for dongle offload.)
*/
#include <typedefs.h>
#include <osl.h>
#include <bcmutils.h>
#include <bcmcdc.h>
#include <bcmendian.h>
#include <dngl_stats.h>
#include <dhd.h>
#include <dhd_proto.h>
#include <dhd_bus.h>
#include <dhd_dbg.h>
#ifdef PROP_TXSTATUS
#include <wlfc_proto.h>
#include <dhd_wlfc.h>
#endif // endif
#ifdef BCMDBUS
#include <dhd_config.h>
#endif /* BCMDBUS */
#ifdef DHD_ULP
#include <dhd_ulp.h>
#endif /* DHD_ULP */
#define RETRIES 2 /* # of retries to retrieve matching ioctl response */
#define BUS_HEADER_LEN (24+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE
* defined in dhd_sdio.c (amount of header tha might be added)
* plus any space that might be needed for alignment padding.
*/
#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for
* round off at the end of buffer
*/
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];
} dhd_prot_t;
uint16
dhd_prot_get_ioctl_trans_id(dhd_pub_t *dhdp)
{
/* SDIO does not have ioctl_trans_id yet, so return -1 */
return -1;
}
static int
dhdcdc_msg(dhd_pub_t *dhd)
{
#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);
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
DHD_OS_WAKE_LOCK(dhd);
/* NOTE : cdc->msg.len holds the desired length of the buffer to be
* returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
* is actually sent to the dongle
*/
if (len > CDC_MAX_MSG_SIZE)
len = CDC_MAX_MSG_SIZE;
/* Send request */
#ifdef BCMDBUS
DHD_OS_IOCTL_RESP_LOCK(dhd);
prot->ctl_completed = FALSE;
err = dbus_send_ctl(dhd->bus, (void *)&prot->msg, len);
if (err) {
DHD_ERROR(("dbus_send_ctl error=%d\n", err));
DHD_OS_IOCTL_RESP_UNLOCK(dhd);
DHD_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;
}
DHD_OS_IOCTL_RESP_UNLOCK(dhd);
#endif /* BCMDBUS */
#if defined(BCMDBUS) && defined(INTR_EP_ENABLE)
/* If the ctl write is successfully completed, wait for an acknowledgement
* that indicates that it is now ok to do ctl read from the dongle
*/
if (err != -1) {
DHD_OS_IOCTL_RESP_LOCK(dhd);
prot->ctl_completed = FALSE;
if (dbus_poll_intr(dhd->dbus)) {
DHD_ERROR(("dbus_poll_intr not submitted\n"));
} 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"));
}
}
DHD_OS_IOCTL_RESP_UNLOCK(dhd);
}
#endif /* defined(BCMDBUS) && defined(INTR_EP_ENABLE) */
DHD_OS_WAKE_UNLOCK(dhd);
return err;
}
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__));
do {
#ifdef BCMDBUS
DHD_OS_IOCTL_RESP_LOCK(dhd);
prot->ctl_completed = FALSE;
ret = dbus_recv_ctl(dhd->bus, (uchar*)&prot->msg, cdc_len);
if (ret) {
DHD_ERROR(("dbus_recv_ctl error=0x%x(%d)\n", ret, ret));
DHD_OS_IOCTL_RESP_UNLOCK(dhd);
goto done;
}
timeout = dhd_os_ioctl_resp_wait(dhd, &prot->ctl_completed);
if ((!timeout) || (!prot->ctl_completed)) {
DHD_ERROR(("Rxctl timeout %d ctl_completed %d\n",
timeout, prot->ctl_completed));
ret = -1;
DHD_OS_IOCTL_RESP_UNLOCK(dhd);
goto done;
}
DHD_OS_IOCTL_RESP_UNLOCK(dhd);
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);
#ifdef BCMDBUS
done:
#endif /* BCMDBUS */
return ret;
}
static int
dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action)
{
dhd_prot_t *prot = dhd->prot;
cdc_ioctl_t *msg = &prot->msg;
int ret = 0, retries = 0;
uint32 id, flags = 0;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
/* Respond "bcmerror" and "bcmerrorstr" with local cache */
if (cmd == WLC_GET_VAR && buf)
{
if (!strcmp((char *)buf, "bcmerrorstr"))
{
strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN);
goto done;
}
else if (!strcmp((char *)buf, "bcmerror"))
{
*(int *)buf = dhd->dongle_error;
goto done;
}
}
memset(msg, 0, sizeof(cdc_ioctl_t));
#ifdef BCMSPI
/* 11bit gSPI bus allows 2048bytes of max-data. We restrict 'len'
* value which is 8Kbytes for various 'get' commands to 2000. 48 bytes are
* left for sw headers and misc.
*/
if (len > 2000) {
DHD_ERROR(("dhdcdc_query_ioctl: len is truncated to 2000 bytes\n"));
len = 2000;
}
#endif /* BCMSPI */
msg->cmd = htol32(cmd);
msg->len = htol32(len);
msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT);
CDC_SET_IF_IDX(msg, ifidx);
/* add additional action bits */
action &= WL_IOCTL_ACTION_MASK;
msg->flags |= (action << CDCF_IOC_ACTION_SHIFT);
msg->flags = htol32(msg->flags);
if (buf)
memcpy(prot->buf, buf, len);
if ((ret = dhdcdc_msg(dhd)) < 0) {
if (!dhd->hang_was_sent)
DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret));
goto done;
}
retry:
/* wait for interrupt and get first fragment */
if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0)
goto done;
flags = ltoh32(msg->flags);
id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
if ((id < prot->reqid) && (++retries < RETRIES))
goto retry;
if (id != prot->reqid) {
DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid));
ret = -EINVAL;
goto done;
}
/* Copy info buffer */
if (buf)
{
if (ret < (int)len)
len = ret;
memcpy(buf, (void*) prot->buf, len);
}
/* Check the ERROR flag */
if (flags & CDCF_IOC_ERROR)
{
ret = ltoh32(msg->status);
/* Cache error from dongle */
dhd->dongle_error = ret;
}
done:
return ret;
}
#ifdef DHD_PM_CONTROL_FROM_FILE
extern bool g_pm_control;
#endif /* DHD_PM_CONTROL_FROM_FILE */
static int
dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action)
{
dhd_prot_t *prot = dhd->prot;
cdc_ioctl_t *msg = &prot->msg;
int ret = 0;
uint32 flags, id;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
if (dhd->busstate == DHD_BUS_DOWN) {
DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
return -EIO;
}
/* don't talk to the dongle if fw is about to be reloaded */
if (dhd->hang_was_sent) {
DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n",
__FUNCTION__));
return -EIO;
}
if (cmd == WLC_SET_PM) {
#ifdef DHD_PM_CONTROL_FROM_FILE
if (g_pm_control == TRUE) {
DHD_ERROR(("%s: SET PM ignored!(Requested:%d)\n",
__FUNCTION__, buf ? *(char *)buf : 0));
goto done;
}
#endif /* DHD_PM_CONTROL_FROM_FILE */
DHD_TRACE_HW4(("%s: SET PM to %d\n", __FUNCTION__, buf ? *(char *)buf : 0));
}
memset(msg, 0, sizeof(cdc_ioctl_t));
msg->cmd = htol32(cmd);
msg->len = htol32(len);
msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT);
CDC_SET_IF_IDX(msg, ifidx);
/* add additional action bits */
action &= WL_IOCTL_ACTION_MASK;
msg->flags |= (action << CDCF_IOC_ACTION_SHIFT) | CDCF_IOC_SET;
msg->flags = htol32(msg->flags);
if (buf)
memcpy(prot->buf, buf, len);
#ifdef DHD_ULP
if (buf && (!strncmp(buf, "ulp", sizeof("ulp")))) {
/* force all the writes after this point to NOT to use cached sbwad value */
dhd_ulp_disable_cached_sbwad(dhd);
}
#endif /* DHD_ULP */
if ((ret = dhdcdc_msg(dhd)) < 0) {
DHD_ERROR(("%s: dhdcdc_msg failed w/status %d\n", __FUNCTION__, ret));
goto done;
}
if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0)
goto done;
flags = ltoh32(msg->flags);
id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
if (id != prot->reqid) {
DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid));
ret = -EINVAL;
goto done;
}
#ifdef DHD_ULP
/* For ulp prototyping temporary */
if ((ret = dhd_ulp_check_ulp_request(dhd, buf)) < 0)
goto done;
#endif /* DHD_ULP */
/* Check the ERROR flag */
if (flags & CDCF_IOC_ERROR)
{
ret = ltoh32(msg->status);
/* Cache error from dongle */
dhd->dongle_error = ret;
}
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);
DHD_OS_IOCTL_RESP_LOCK(dhd);
prot->ctl_completed = TRUE;
dhd_os_ioctl_resp_wake(dhd);
DHD_OS_IOCTL_RESP_UNLOCK(dhd);
return 0;
}
#endif /* BCMDBUS */
int
dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len)
{
dhd_prot_t *prot = dhd->prot;
int ret = -1;
uint8 action;
static int error_cnt = 0;
if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) {
DHD_ERROR(("%s : bus is down. we have nothing to do - bs: %d, has: %d\n",
__FUNCTION__, dhd->busstate, dhd->hang_was_sent));
goto done;
}
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
ASSERT(len <= WLC_IOCTL_MAXLEN);
if (len > WLC_IOCTL_MAXLEN)
goto done;
if (prot->pending == TRUE) {
DHD_ERROR(("CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n",
ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd,
(unsigned long)prot->lastcmd));
if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) {
DHD_TRACE(("iovar cmd=%s\n", buf ? (char*)buf : "\0"));
}
goto done;
}
prot->pending = TRUE;
prot->lastcmd = ioc->cmd;
action = ioc->set;
if (action & WL_IOCTL_ACTION_SET)
ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action);
else {
ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action);
if (ret > 0)
ioc->used = ret - sizeof(cdc_ioctl_t);
}
// terence 20130805: send hang event to wpa_supplicant
if (ret == -EIO) {
error_cnt++;
if (error_cnt > 2)
ret = -ETIMEDOUT;
} else
error_cnt = 0;
/* Too many programs assume ioctl() returns 0 on success */
if (ret >= 0)
ret = 0;
else {
cdc_ioctl_t *msg = &prot->msg;
ioc->needed = ltoh32(msg->len); /* len == needed when set/query fails from dongle */
}
/* Intercept the wme_dp ioctl here */
if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) {
int slen, val = 0;
slen = strlen("wme_dp") + 1;
if (len >= (int)(slen + sizeof(int)))
bcopy(((char *)buf + slen), &val, sizeof(int));
dhd->wme_dp = (uint8) ltoh32(val);
}
prot->pending = FALSE;
done:
return ret;
}
int
dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name,
void *params, int plen, void *arg, int len, bool set)
{
return BCME_UNSUPPORTED;
}
void
dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
{
if (!dhdp || !dhdp->prot) {
return;
}
bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid);
#ifdef PROP_TXSTATUS
dhd_wlfc_dump(dhdp, strbuf);
#endif // endif
}
/* The FreeBSD PKTPUSH could change the packet buf pinter
so we need to make it changable
*/
#define PKTBUF pktbuf
void
dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *PKTBUF)
{
#ifdef BDC
struct bdc_header *h;
#endif /* BDC */
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
#ifdef BDC
/* Push BDC header used to convey priority for buses that don't */
PKTPUSH(dhd->osh, PKTBUF, BDC_HEADER_LEN);
h = (struct bdc_header *)PKTDATA(dhd->osh, PKTBUF);
h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT);
if (PKTSUMNEEDED(PKTBUF))
h->flags |= BDC_FLAG_SUM_NEEDED;
h->priority = (PKTPRIO(PKTBUF) & BDC_PRIORITY_MASK);
h->flags2 = 0;
h->dataOffset = 0;
#endif /* BDC */
BDC_SET_IF_IDX(h, ifidx);
}
#undef PKTBUF /* Only defined in the above routine */
uint
dhd_prot_hdrlen(dhd_pub_t *dhd, void *PKTBUF)
{
uint hdrlen = 0;
#ifdef BDC
/* Length of BDC(+WLFC) headers pushed */
hdrlen = BDC_HEADER_LEN + (((struct bdc_header *)PKTBUF)->dataOffset * 4);
#endif // endif
return hdrlen;
}
int
dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_info,
uint *reorder_info_len)
{
#ifdef BDC
struct bdc_header *h;
#endif // endif
uint8 data_offset = 0;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
#ifdef BDC
if (reorder_info_len)
*reorder_info_len = 0;
/* Pop BDC header used to convey priority for buses that don't */
if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) {
DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__,
PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN));
return BCME_ERROR;
}
h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf);
if (!ifidx) {
/* for tx packet, skip the analysis */
data_offset = h->dataOffset;
PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN);
goto exit;
}
*ifidx = BDC_GET_IF_IDX(h);
if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) {
DHD_ERROR(("%s: non-BDC packet received, flags = 0x%x\n",
dhd_ifname(dhd, *ifidx), h->flags));
if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) == BDC_PROTO_VER_1)
h->dataOffset = 0;
else
return BCME_ERROR;
}
if (h->flags & BDC_FLAG_SUM_GOOD) {
DHD_INFO(("%s: BDC packet received with good rx-csum, flags 0x%x\n",
dhd_ifname(dhd, *ifidx), h->flags));
PKTSETSUMGOOD(pktbuf, TRUE);
}
PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK));
data_offset = h->dataOffset;
PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN);
#endif /* BDC */
#ifdef PROP_TXSTATUS
if (!DHD_PKTTAG_PKTDIR(PKTTAG(pktbuf))) {
/*
- parse txstatus only for packets that came from the firmware
*/
dhd_wlfc_parse_header_info(dhd, pktbuf, (data_offset << 2),
reorder_buf_info, reorder_info_len);
#ifdef BCMDBUS
#ifndef DHD_WLFC_THREAD
dhd_wlfc_commit_packets(dhd,
(f_commitpkt_t)dhd_bus_txdata, dhd->bus, NULL, FALSE);
#endif /* DHD_WLFC_THREAD */
#endif /* BCMDBUS */
}
#endif /* PROP_TXSTATUS */
exit:
PKTPULL(dhd->osh, pktbuf, (data_offset << 2));
return 0;
}
int
dhd_prot_attach(dhd_pub_t *dhd)
{
dhd_prot_t *cdc;
if (!(cdc = (dhd_prot_t *)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_PROT, sizeof(dhd_prot_t)))) {
DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
goto fail;
}
memset(cdc, 0, sizeof(dhd_prot_t));
/* ensure that the msg buf directly follows the cdc msg struct */
if ((uintptr)(&cdc->msg + 1) != (uintptr)cdc->buf) {
DHD_ERROR(("dhd_prot_t is not correctly defined\n"));
goto fail;
}
dhd->prot = cdc;
#ifdef BDC
dhd->hdrlen += BDC_HEADER_LEN;
#endif // endif
dhd->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN;
return 0;
fail:
if (cdc != NULL)
DHD_OS_PREFREE(dhd, cdc, sizeof(dhd_prot_t));
return BCME_NOMEM;
}
/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */
void
dhd_prot_detach(dhd_pub_t *dhd)
{
#ifdef PROP_TXSTATUS
dhd_wlfc_deinit(dhd);
#endif // endif
DHD_OS_PREFREE(dhd, dhd->prot, sizeof(dhd_prot_t));
dhd->prot = NULL;
}
void
dhd_prot_dstats(dhd_pub_t *dhd)
{
/* copy bus stats */
dhd->dstats.tx_packets = dhd->tx_packets;
dhd->dstats.tx_errors = dhd->tx_errors;
dhd->dstats.rx_packets = dhd->rx_packets;
dhd->dstats.rx_errors = dhd->rx_errors;
dhd->dstats.rx_dropped = dhd->rx_dropped;
dhd->dstats.multicast = dhd->rx_multicast;
return;
}
int
dhd_sync_with_dongle(dhd_pub_t *dhd)
{
int ret = 0;
wlc_rev_info_t revinfo;
DHD_TRACE(("%s: Enter\n", __FUNCTION__));
#ifdef DHD_FW_COREDUMP
/* Check the memdump capability */
dhd_get_memdump_info(dhd);
#endif /* DHD_FW_COREDUMP */
#ifdef BCMASSERT_LOG
dhd_get_assert_info(dhd);
#endif /* BCMASSERT_LOG */
/* Get the device rev info */
memset(&revinfo, 0, sizeof(revinfo));
ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0);
if (ret < 0)
goto done;
#if defined(BCMDBUS)
if (dhd_download_fw_on_driverload) {
dhd_conf_reset(dhd);
dhd_conf_set_chiprev(dhd, revinfo.chipnum, revinfo.chiprev);
dhd_conf_preinit(dhd);
dhd_conf_read_config(dhd, dhd->conf_path);
}
#endif /* BCMDBUS */
DHD_SSSR_DUMP_INIT(dhd);
dhd_process_cid_mac(dhd, TRUE);
ret = dhd_preinit_ioctls(dhd);
dhd_process_cid_mac(dhd, FALSE);
/* Always assumes wl for now */
dhd->iswl = TRUE;
done:
return ret;
}
int dhd_prot_init(dhd_pub_t *dhd)
{
return BCME_OK;
}
void
dhd_prot_stop(dhd_pub_t *dhd)
{
/* Nothing to do for CDC */
}
static void
dhd_get_hostreorder_pkts(void *osh, struct reorder_info *ptr, void **pkt,
uint32 *pkt_count, void **pplast, uint8 start, uint8 end)
{
void *plast = NULL, *p;
uint32 pkt_cnt = 0;
if (ptr->pend_pkts == 0) {
DHD_REORDER(("%s: no packets in reorder queue \n", __FUNCTION__));
*pplast = NULL;
*pkt_count = 0;
*pkt = NULL;
return;
}
do {
p = (void *)(ptr->p[start]);
ptr->p[start] = NULL;
if (p != NULL) {
if (plast == NULL)
*pkt = p;
else
PKTSETNEXT(osh, plast, p);
plast = p;
pkt_cnt++;
}
start++;
if (start > ptr->max_idx)
start = 0;
} while (start != end);
*pplast = plast;
*pkt_count = pkt_cnt;
ptr->pend_pkts -= (uint8)pkt_cnt;
}
int
dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len,
void **pkt, uint32 *pkt_count)
{
uint8 flow_id, max_idx, cur_idx, exp_idx;
struct reorder_info *ptr;
uint8 flags;
void *cur_pkt, *plast = NULL;
uint32 cnt = 0;
if (pkt == NULL) {
if (pkt_count != NULL)
*pkt_count = 0;
return 0;
}
flow_id = reorder_info_buf[WLHOST_REORDERDATA_FLOWID_OFFSET];
flags = reorder_info_buf[WLHOST_REORDERDATA_FLAGS_OFFSET];
DHD_REORDER(("flow_id %d, flags 0x%02x, idx(%d, %d, %d)\n", flow_id, flags,
reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET],
reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET],
reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]));
/* validate flags and flow id */
if (flags == 0xFF) {
DHD_ERROR(("%s: invalid flags...so ignore this packet\n", __FUNCTION__));
*pkt_count = 1;
return 0;
}
cur_pkt = *pkt;
*pkt = NULL;
ptr = dhd->reorder_bufs[flow_id];
if (flags & WLHOST_REORDERDATA_DEL_FLOW) {
uint32 buf_size = sizeof(struct reorder_info);
DHD_REORDER(("%s: Flags indicating to delete a flow id %d\n",
__FUNCTION__, flow_id));
if (ptr == NULL) {
DHD_REORDER(("%s: received flags to cleanup, but no flow (%d) yet\n",
__FUNCTION__, flow_id));
*pkt_count = 1;
*pkt = cur_pkt;
return 0;
}
dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast,
ptr->exp_idx, ptr->exp_idx);
/* set it to the last packet */
if (plast) {
PKTSETNEXT(dhd->osh, plast, cur_pkt);
cnt++;
}
else {
if (cnt != 0) {
DHD_ERROR(("%s: del flow: something fishy, pending packets %d\n",
__FUNCTION__, cnt));
}
*pkt = cur_pkt;
cnt = 1;
}
buf_size += ((ptr->max_idx + 1) * sizeof(void *));
MFREE(dhd->osh, ptr, buf_size);
dhd->reorder_bufs[flow_id] = NULL;
*pkt_count = cnt;
return 0;
}
/* all the other cases depend on the existance of the reorder struct for that flow id */
if (ptr == NULL) {
uint32 buf_size_alloc = sizeof(reorder_info_t);
max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET];
buf_size_alloc += ((max_idx + 1) * sizeof(void*));
/* allocate space to hold the buffers, index etc */
DHD_REORDER(("%s: alloc buffer of size %d size, reorder info id %d, maxidx %d\n",
__FUNCTION__, buf_size_alloc, flow_id, max_idx));
ptr = (struct reorder_info *)MALLOC(dhd->osh, buf_size_alloc);
if (ptr == NULL) {
DHD_ERROR(("%s: Malloc failed to alloc buffer\n", __FUNCTION__));
*pkt_count = 1;
return 0;
}
bzero(ptr, buf_size_alloc);
dhd->reorder_bufs[flow_id] = ptr;
ptr->p = (void *)(ptr+1);
ptr->max_idx = max_idx;
}
if (flags & WLHOST_REORDERDATA_NEW_HOLE) {
DHD_REORDER(("%s: new hole, so cleanup pending buffers\n", __FUNCTION__));
if (ptr->pend_pkts) {
dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast,
ptr->exp_idx, ptr->exp_idx);
ptr->pend_pkts = 0;
}
ptr->cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET];
ptr->exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET];
ptr->max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET];
ptr->p[ptr->cur_idx] = cur_pkt;
ptr->pend_pkts++;
*pkt_count = cnt;
}
else if (flags & WLHOST_REORDERDATA_CURIDX_VALID) {
cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET];
exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET];
if ((exp_idx == ptr->exp_idx) && (cur_idx != ptr->exp_idx)) {
/* still in the current hole */
/* enqueue the current on the buffer chain */
if (ptr->p[cur_idx] != NULL) {
DHD_REORDER(("%s: HOLE: ERROR buffer pending..free it\n",
__FUNCTION__));
PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE);
ptr->p[cur_idx] = NULL;
}
ptr->p[cur_idx] = cur_pkt;
ptr->pend_pkts++;
ptr->cur_idx = cur_idx;
DHD_REORDER(("%s: fill up a hole..pending packets is %d\n",
__FUNCTION__, ptr->pend_pkts));
*pkt_count = 0;
*pkt = NULL;
}
else if (ptr->exp_idx == cur_idx) {
/* got the right one ..flush from cur to exp and update exp */
DHD_REORDER(("%s: got the right one now, cur_idx is %d\n",
__FUNCTION__, cur_idx));
if (ptr->p[cur_idx] != NULL) {
DHD_REORDER(("%s: Error buffer pending..free it\n",
__FUNCTION__));
PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE);
ptr->p[cur_idx] = NULL;
}
ptr->p[cur_idx] = cur_pkt;
ptr->pend_pkts++;
ptr->cur_idx = cur_idx;
ptr->exp_idx = exp_idx;
dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast,
cur_idx, exp_idx);
*pkt_count = cnt;
DHD_REORDER(("%s: freeing up buffers %d, still pending %d\n",
__FUNCTION__, cnt, ptr->pend_pkts));
}
else {
uint8 end_idx;
bool flush_current = FALSE;
/* both cur and exp are moved now .. */
DHD_REORDER(("%s:, flow %d, both moved, cur %d(%d), exp %d(%d)\n",
__FUNCTION__, flow_id, ptr->cur_idx, cur_idx,
ptr->exp_idx, exp_idx));
if (flags & WLHOST_REORDERDATA_FLUSH_ALL)
end_idx = ptr->exp_idx;
else
end_idx = exp_idx;
/* flush pkts first */
dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast,
ptr->exp_idx, end_idx);
if (cur_idx == ptr->max_idx) {
if (exp_idx == 0)
flush_current = TRUE;
} else {
if (exp_idx == cur_idx + 1)
flush_current = TRUE;
}
if (flush_current) {
if (plast)
PKTSETNEXT(dhd->osh, plast, cur_pkt);
else
*pkt = cur_pkt;
cnt++;
}
else {
ptr->p[cur_idx] = cur_pkt;
ptr->pend_pkts++;
}
ptr->exp_idx = exp_idx;
ptr->cur_idx = cur_idx;
*pkt_count = cnt;
}
}
else {
uint8 end_idx;
/* no real packet but update to exp_seq...that means explicit window move */
exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET];
DHD_REORDER(("%s: move the window, cur_idx is %d, exp is %d, new exp is %d\n",
__FUNCTION__, ptr->cur_idx, ptr->exp_idx, exp_idx));
if (flags & WLHOST_REORDERDATA_FLUSH_ALL)
end_idx = ptr->exp_idx;
else
end_idx = exp_idx;
dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ptr->exp_idx, end_idx);
if (plast)
PKTSETNEXT(dhd->osh, plast, cur_pkt);
else
*pkt = cur_pkt;
cnt++;
*pkt_count = cnt;
/* set the new expected idx */
ptr->exp_idx = exp_idx;
}
return 0;
}

View File

@@ -0,0 +1,305 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Linux cfg80211 driver - Dongle Host Driver (DHD) related
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_cfg80211.c 807961 2019-03-05 05:47:47Z $
*/
#include <linux/vmalloc.h>
#include <net/rtnetlink.h>
#include <bcmutils.h>
#include <wldev_common.h>
#include <wl_cfg80211.h>
#include <dhd_cfg80211.h>
#ifdef PKT_FILTER_SUPPORT
#include <dngl_stats.h>
#include <dhd.h>
#endif // endif
#ifdef PKT_FILTER_SUPPORT
extern uint dhd_pkt_filter_enable;
extern uint dhd_master_mode;
extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
#endif // endif
static int dhd_dongle_up = FALSE;
#include <dngl_stats.h>
#include <dhd.h>
#include <dhdioctl.h>
#include <wlioctl.h>
#include <brcm_nl80211.h>
#include <dhd_cfg80211.h>
static s32 wl_dongle_up(struct net_device *ndev);
static s32 wl_dongle_down(struct net_device *ndev);
/**
* Function implementations
*/
s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg)
{
dhd_dongle_up = FALSE;
return 0;
}
s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg)
{
dhd_dongle_up = FALSE;
return 0;
}
s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg)
{
struct net_device *ndev;
s32 err = 0;
dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
WL_TRACE(("In\n"));
if ((!dhd_dongle_up) || (!dhd->up)) {
WL_INFORM_MEM(("Dongle is already down\n"));
err = 0;
goto done;
}
ndev = bcmcfg_to_prmry_ndev(cfg);
wl_dongle_down(ndev);
done:
dhd_dongle_up = FALSE;
return err;
}
s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val)
{
dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
dhd->op_mode |= val;
WL_ERR(("Set : op_mode=0x%04x\n", dhd->op_mode));
#ifdef ARP_OFFLOAD_SUPPORT
if (dhd->arp_version == 1) {
/* IF P2P is enabled, disable arpoe */
dhd_arp_offload_set(dhd, 0);
dhd_arp_offload_enable(dhd, false);
}
#endif /* ARP_OFFLOAD_SUPPORT */
return 0;
}
s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg)
{
dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub);
dhd->op_mode &= ~(DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE);
WL_ERR(("Clean : op_mode=0x%04x\n", dhd->op_mode));
#ifdef ARP_OFFLOAD_SUPPORT
if (dhd->arp_version == 1) {
/* IF P2P is disabled, enable arpoe back for STA mode. */
dhd_arp_offload_set(dhd, dhd_arp_mode);
dhd_arp_offload_enable(dhd, true);
}
#endif /* ARP_OFFLOAD_SUPPORT */
return 0;
}
#ifdef WL_STATIC_IF
int32
wl_cfg80211_update_iflist_info(struct bcm_cfg80211 *cfg, struct net_device *ndev,
int ifidx, uint8 *addr, int bssidx, char *name, int if_state)
{
return dhd_update_iflist_info(cfg->pub, ndev, ifidx, addr, bssidx, name, if_state);
}
#endif /* WL_STATIC_IF */
struct net_device* wl_cfg80211_allocate_if(struct bcm_cfg80211 *cfg, int ifidx, const char *name,
uint8 *mac, uint8 bssidx, const char *dngl_name)
{
return dhd_allocate_if(cfg->pub, ifidx, name, mac, bssidx, FALSE, dngl_name);
}
int wl_cfg80211_register_if(struct bcm_cfg80211 *cfg,
int ifidx, struct net_device* ndev, bool rtnl_lock_reqd)
{
return dhd_register_if(cfg->pub, ifidx, rtnl_lock_reqd);
}
int wl_cfg80211_remove_if(struct bcm_cfg80211 *cfg,
int ifidx, struct net_device* ndev, bool rtnl_lock_reqd)
{
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);
BCM_REFERENCE(cfg);
dhd_cleanup_if(net);
}
struct net_device * dhd_cfg80211_netdev_free(struct net_device *ndev)
{
struct bcm_cfg80211 *cfg;
if (ndev) {
cfg = wl_get_cfg(ndev);
if (ndev->ieee80211_ptr) {
MFREE(cfg->osh, ndev->ieee80211_ptr, sizeof(struct wireless_dev));
ndev->ieee80211_ptr = NULL;
}
free_netdev(ndev);
return NULL;
}
return ndev;
}
void dhd_netdev_free(struct net_device *ndev)
{
#ifdef WL_CFG80211
ndev = dhd_cfg80211_netdev_free(ndev);
#endif // endif
if (ndev)
free_netdev(ndev);
}
static s32
wl_dongle_up(struct net_device *ndev)
{
s32 err = 0;
u32 local_up = 0;
err = wldev_ioctl_set(ndev, WLC_UP, &local_up, sizeof(local_up));
if (unlikely(err)) {
WL_ERR(("WLC_UP error (%d)\n", err));
}
return err;
}
static s32
wl_dongle_down(struct net_device *ndev)
{
s32 err = 0;
u32 local_down = 0;
err = wldev_ioctl_set(ndev, WLC_DOWN, &local_down, sizeof(local_down));
if (unlikely(err)) {
WL_ERR(("WLC_DOWN error (%d)\n", err));
}
return err;
}
s32
wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
{
s32 err = 0;
/* Setup timeout if Beacons are lost and roam is off to report link down */
if (roamvar) {
err = wldev_iovar_setint(ndev, "bcn_timeout", bcn_timeout);
if (unlikely(err)) {
WL_ERR(("bcn_timeout error (%d)\n", err));
goto dongle_rom_out;
}
}
/* Enable/Disable built-in roaming to allow supplicant to take care of roaming */
err = wldev_iovar_setint(ndev, "roam_off", roamvar);
if (unlikely(err)) {
WL_ERR(("roam_off error (%d)\n", err));
goto dongle_rom_out;
}
dongle_rom_out:
return err;
}
s32 dhd_config_dongle(struct bcm_cfg80211 *cfg)
{
#ifndef DHD_SDALIGN
#define DHD_SDALIGN 32
#endif // endif
struct net_device *ndev;
s32 err = 0;
WL_TRACE(("In\n"));
if (dhd_dongle_up) {
WL_ERR(("Dongle is already up\n"));
return err;
}
ndev = bcmcfg_to_prmry_ndev(cfg);
err = wl_dongle_up(ndev);
if (unlikely(err)) {
WL_ERR(("wl_dongle_up failed\n"));
goto default_conf_out;
}
dhd_dongle_up = true;
default_conf_out:
return err;
}
int dhd_cfgvendor_priv_string_handler(struct bcm_cfg80211 *cfg, struct wireless_dev *wdev,
const struct bcm_nlmsg_hdr *nlioc, void *buf)
{
struct net_device *ndev = NULL;
dhd_pub_t *dhd;
dhd_ioctl_t ioc = { 0, NULL, 0, 0, 0, 0, 0};
int ret = 0;
int8 index;
WL_TRACE(("entry: cmd = %d\n", nlioc->cmd));
dhd = cfg->pub;
DHD_OS_WAKE_LOCK(dhd);
ndev = wdev_to_wlc_ndev(wdev, cfg);
index = dhd_net2idx(dhd->info, ndev);
if (index == DHD_BAD_IF) {
WL_ERR(("Bad ifidx from wdev:%p\n", wdev));
ret = BCME_ERROR;
goto done;
}
ioc.cmd = nlioc->cmd;
ioc.len = nlioc->len;
ioc.set = nlioc->set;
ioc.driver = nlioc->magic;
ioc.buf = buf;
ret = dhd_ioctl_process(dhd, index, &ioc, buf);
if (ret) {
WL_TRACE(("dhd_ioctl_process return err %d\n", ret));
ret = OSL_ERROR(ret);
goto done;
}
done:
DHD_OS_WAKE_UNLOCK(dhd);
return ret;
}

View File

@@ -0,0 +1,55 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Linux cfg80211 driver - Dongle Host Driver (DHD) related
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_cfg80211.h 763539 2018-05-19 06:39:21Z $
*/
#ifndef __DHD_CFG80211__
#define __DHD_CFG80211__
#include <wl_cfg80211.h>
#include <wl_cfgp2p.h>
#include <brcm_nl80211.h>
#ifndef WL_ERR
#define WL_ERR CFG80211_ERR
#endif // endif
#ifndef WL_TRACE
#define WL_TRACE CFG80211_TRACE
#endif // endif
s32 dhd_cfg80211_init(struct bcm_cfg80211 *cfg);
s32 dhd_cfg80211_deinit(struct bcm_cfg80211 *cfg);
s32 dhd_cfg80211_down(struct bcm_cfg80211 *cfg);
s32 dhd_cfg80211_set_p2p_info(struct bcm_cfg80211 *cfg, int val);
s32 dhd_cfg80211_clean_p2p_info(struct bcm_cfg80211 *cfg);
s32 dhd_config_dongle(struct bcm_cfg80211 *cfg);
int dhd_cfgvendor_priv_string_handler(struct bcm_cfg80211 *cfg,
struct wireless_dev *wdev, const struct bcm_nlmsg_hdr *nlioc, void *data);
s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout);
#endif /* __DHD_CFG80211__ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,327 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _dhd_config_
#define _dhd_config_
#include <bcmdevs.h>
#include <siutils.h>
#include <dngl_stats.h>
#include <dhd.h>
#include <wlioctl.h>
#include <802.11.h>
#define FW_TYPE_STA 0
#define FW_TYPE_APSTA 1
#define FW_TYPE_P2P 2
#define FW_TYPE_MESH 3
#define FW_TYPE_ES 4
#define FW_TYPE_MFG 5
#define FW_TYPE_G 0
#define FW_TYPE_AG 1
#define FW_PATH_AUTO_SELECT 1
//#define CONFIG_PATH_AUTO_SELECT
extern char firmware_path[MOD_PARAM_PATHLEN];
#if defined(BCMSDIO) || defined(BCMPCIE)
extern uint dhd_rxbound;
extern uint dhd_txbound;
#endif
#ifdef BCMSDIO
#define TXGLOM_RECV_OFFSET 8
extern uint dhd_doflow;
extern uint dhd_slpauto;
#endif
typedef struct wl_mac_range {
uint32 oui;
uint32 nic_start;
uint32 nic_end;
} wl_mac_range_t;
typedef struct wl_mac_list {
int count;
wl_mac_range_t *mac;
char name[MOD_PARAM_PATHLEN];
} wl_mac_list_t;
typedef struct wl_mac_list_ctrl {
int count;
struct wl_mac_list *m_mac_list_head;
} wl_mac_list_ctrl_t;
typedef struct wl_chip_nv_path {
uint chip;
uint chiprev;
char name[MOD_PARAM_PATHLEN];
} wl_chip_nv_path_t;
typedef struct wl_chip_nv_path_list_ctrl {
int count;
struct wl_chip_nv_path *m_chip_nv_path_head;
} wl_chip_nv_path_list_ctrl_t;
typedef struct wl_channel_list {
uint32 count;
uint32 channel[WL_NUMCHANNELS];
} wl_channel_list_t;
typedef struct wmes_param {
int aifsn[AC_COUNT];
int ecwmin[AC_COUNT];
int ecwmax[AC_COUNT];
int txop[AC_COUNT];
} wme_param_t;
#ifdef PKT_FILTER_SUPPORT
#define DHD_CONF_FILTER_MAX 8
#define PKT_FILTER_LEN 300
#define MAGIC_PKT_FILTER_LEN 450
typedef struct conf_pkt_filter_add {
uint32 count;
char filter[DHD_CONF_FILTER_MAX][PKT_FILTER_LEN];
} conf_pkt_filter_add_t;
typedef struct conf_pkt_filter_del {
uint32 count;
uint32 id[DHD_CONF_FILTER_MAX];
} conf_pkt_filter_del_t;
#endif
#define CONFIG_COUNTRY_LIST_SIZE 500
typedef struct country_list {
struct country_list *next;
wl_country_t cspec;
} country_list_t;
/* mchan_params */
#define MCHAN_MAX_NUM 4
#define MIRACAST_SOURCE 1
#define MIRACAST_SINK 2
typedef struct mchan_params {
struct mchan_params *next;
int bw;
int p2p_mode;
int miracast_mode;
} mchan_params_t;
enum in4way_flags {
NO_SCAN_IN4WAY = (1 << (0)),
NO_BTC_IN4WAY = (1 << (1)),
DONT_DELETE_GC_AFTER_WPS = (1 << (2)),
WAIT_DISCONNECTED = (1 << (3)),
};
enum in_suspend_flags {
NO_EVENT_IN_SUSPEND = (1 << (0)),
NO_TXDATA_IN_SUSPEND = (1 << (1)),
NO_TXCTL_IN_SUSPEND = (1 << (2)),
AP_DOWN_IN_SUSPEND = (1 << (3)),
ROAM_OFFLOAD_IN_SUSPEND = (1 << (4)),
AP_FILTER_IN_SUSPEND = (1 << (5)),
WOWL_IN_SUSPEND = (1 << (6)),
ALL_IN_SUSPEND = 0xFFFFFFFF,
};
enum in_suspend_mode {
EARLY_SUSPEND = 0,
PM_NOTIFIER = 1
};
enum eapol_status {
EAPOL_STATUS_NONE = 0,
EAPOL_STATUS_REQID = 1,
EAPOL_STATUS_RSPID = 2,
EAPOL_STATUS_WSC_START = 3,
EAPOL_STATUS_WPS_M1 = 4,
EAPOL_STATUS_WPS_M2 = 5,
EAPOL_STATUS_WPS_M3 = 6,
EAPOL_STATUS_WPS_M4 = 7,
EAPOL_STATUS_WPS_M5 = 8,
EAPOL_STATUS_WPS_M6 = 9,
EAPOL_STATUS_WPS_M7 = 10,
EAPOL_STATUS_WPS_M8 = 11,
EAPOL_STATUS_WSC_DONE = 12,
EAPOL_STATUS_4WAY_START = 13,
EAPOL_STATUS_4WAY_M1 = 14,
EAPOL_STATUS_4WAY_M2 = 15,
EAPOL_STATUS_4WAY_M3 = 16,
EAPOL_STATUS_4WAY_M4 = 17,
EAPOL_STATUS_GROUPKEY_M1 = 18,
EAPOL_STATUS_GROUPKEY_M2 = 19,
EAPOL_STATUS_4WAY_DONE = 20
};
typedef struct dhd_conf {
uint chip;
uint chiprev;
#ifdef GET_OTP_MODULE_NAME
char module_name[16];
#endif
struct ether_addr otp_mac;
int fw_type;
#ifdef BCMSDIO
wl_mac_list_ctrl_t fw_by_mac;
wl_mac_list_ctrl_t nv_by_mac;
#endif
wl_chip_nv_path_list_ctrl_t nv_by_chip;
country_list_t *country_head;
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];
int roam_scan_period[2];
int roam_delta[2];
int fullroamperiod;
uint keep_alive_period;
#ifdef ARP_OFFLOAD_SUPPORT
bool garp;
#endif
int force_wme_ac;
wme_param_t wme_sta;
wme_param_t wme_ap;
#ifdef PKT_FILTER_SUPPORT
conf_pkt_filter_add_t pkt_filter_add;
conf_pkt_filter_del_t pkt_filter_del;
char *magic_pkt_filter_add;
#endif
int srl;
int lrl;
uint bcn_timeout;
int disable_proptx;
int dhd_poll;
#ifdef BCMSDIO
int use_rxchain;
bool bus_rxglom;
bool txglom_ext; /* Only for 43362/4330/43340/43341/43241 */
/* terence 20161011:
1) conf->tx_max_offset = 1 to fix credict issue in adaptivity testing
2) conf->tx_max_offset = 1 will cause to UDP Tx not work in rxglom supported,
but not happened in sw txglom
*/
int tx_max_offset;
uint txglomsize;
int txctl_tmo_fix;
bool txglom_mode;
uint deferred_tx_len;
/*txglom_bucket_size:
* 43362/4330: 1680
* 43340/43341/43241: 1684
*/
int txglom_bucket_size;
int txinrx_thres;
int dhd_txminmax; // -1=DATABUFCNT(bus)
bool oob_enabled_later;
#if defined(SDIO_ISR_THREAD)
bool intr_extn;
#endif
#ifdef BCMSDIO_RXLIM_POST
bool rxlim_en;
#endif
#endif
#ifdef BCMPCIE
int bus_deepsleep_disable;
#endif
int dpc_cpucore;
int rxf_cpucore;
int frameburst;
bool deepsleep;
int pm;
int pm_in_suspend;
int suspend_mode;
int suspend_bcn_li_dtim;
#ifdef DHDTCPACK_SUPPRESS
uint8 tcpack_sup_mode;
#endif
int pktprio8021x;
uint insuspend;
bool suspended;
#ifdef SUSPEND_EVENT
char resume_eventmask[WL_EVENTING_MASK_LEN];
struct ether_addr bssid_insuspend;
bool wlfc;
#endif
#ifdef IDHCP
int dhcpc_enable;
int dhcpd_enable;
struct ipv4_addr dhcpd_ip_addr;
struct ipv4_addr dhcpd_ip_mask;
struct ipv4_addr dhcpd_ip_start;
struct ipv4_addr dhcpd_ip_end;
#endif
#ifdef ISAM_PREINIT
char isam_init[50];
char isam_config[300];
char isam_enable[50];
#endif
int ctrl_resched;
mchan_params_t *mchan;
char *wl_preinit;
char *wl_suspend;
char *wl_resume;
int tsq;
int orphan_move;
uint eapol_status;
uint in4way;
#ifdef WL_EXT_WOWL
uint wowl;
#endif
#ifdef GET_CUSTOM_MAC_FROM_CONFIG
char hw_ether[62];
#endif
wait_queue_head_t event_complete;
} dhd_conf_t;
#ifdef BCMSDIO
void dhd_conf_get_otp(dhd_pub_t *dhd, bcmsdh_info_t *sdh, si_t *sih);
#if defined(HW_OOB) || defined(FORCE_WOWLAN)
void dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, struct si_pub *sih);
#endif
void dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable);
int dhd_conf_set_blksize(bcmsdh_info_t *sdh);
#endif
void dhd_conf_set_path_params(dhd_pub_t *dhd, char *fw_path, char *nv_path);
int dhd_conf_set_intiovar(dhd_pub_t *dhd, uint cmd, char *name, int val,
int def, bool down);
int dhd_conf_get_band(dhd_pub_t *dhd);
int dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec);
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);
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);
bool dhd_conf_del_pkt_filter(dhd_pub_t *dhd, uint32 id);
void dhd_conf_discard_pkt_filter(dhd_pub_t *dhd);
int dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path);
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_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,
int hostsleep_set, int hostsleep_val, int ret);
int dhd_conf_mkeep_alive(dhd_pub_t *dhd, int ifidx, int id, int period,
char *packet, bool bcast);
#ifdef ARP_OFFLOAD_SUPPORT
void dhd_conf_set_garp(dhd_pub_t *dhd, int ifidx, uint32 ipa, bool enable);
#endif
#ifdef PROP_TXSTATUS
int dhd_conf_get_disable_proptx(dhd_pub_t *dhd);
#endif
uint dhd_conf_get_insuspend(dhd_pub_t *dhd, uint mask);
int dhd_conf_set_suspend_resume(dhd_pub_t *dhd, int suspend);
void dhd_conf_postinit_ioctls(dhd_pub_t *dhd);
int dhd_conf_preinit(dhd_pub_t *dhd);
int dhd_conf_reset(dhd_pub_t *dhd);
int dhd_conf_attach(dhd_pub_t *dhd);
void dhd_conf_detach(dhd_pub_t *dhd);
void *dhd_get_pub(struct net_device *dev);
int wl_pattern_atoh(char *src, char *dst);
#ifdef BCMSDIO
extern int dhd_bus_sleep(dhd_pub_t *dhdp, bool sleep, uint32 *intstatus);
#endif
#endif /* _dhd_config_ */

View File

@@ -0,0 +1,279 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Customer code to add GPIO control during WLAN start/stop
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_custom_gpio.c 717227 2017-08-23 13:51:13Z $
*/
#include <typedefs.h>
#include <linuxver.h>
#include <osl.h>
#include <bcmutils.h>
#include <dngl_stats.h>
#include <dhd.h>
#include <dhd_linux.h>
#include <wlioctl.h>
#if defined(WL_WIRELESS_EXT)
#include <wl_iw.h>
#endif // endif
#define WL_ERROR(x) printf x
#define WL_TRACE(x)
#if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
#if defined(BCMLXSDMMC)
extern int sdioh_mmc_irq(int irq);
#endif /* (BCMLXSDMMC) */
/* Customer specific Host GPIO defintion */
static int dhd_oob_gpio_num = -1;
module_param(dhd_oob_gpio_num, int, 0644);
MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number");
/* This function will return:
* 1) return : Host gpio interrupt number per customer platform
* 2) irq_flags_ptr : Type of Host interrupt as Level or Edge
*
* NOTE :
* Customer should check his platform definitions
* and his Host Interrupt spec
* to figure out the proper setting for his platform.
* Broadcom provides just reference settings as example.
*
*/
int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr)
{
int host_oob_irq = 0;
host_oob_irq = wifi_platform_get_irq_number(adapter, irq_flags_ptr);
return (host_oob_irq);
}
#endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
/* Customer function to control hw specific wlan gpios */
int
dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff)
{
int err = 0;
return err;
}
#if 0
/* Function to get custom MAC address */
int
dhd_custom_get_mac_address(void *adapter, unsigned char *buf)
{
int ret = 0;
WL_TRACE(("%s Enter\n", __FUNCTION__));
if (!buf)
return -EINVAL;
/* Customer access to MAC address stored outside of DHD driver */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
ret = wifi_platform_get_mac_addr(adapter, buf);
#endif // endif
#ifdef EXAMPLE_GET_MAC
/* EXAMPLE code */
{
struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}};
bcopy((char *)&ea_example, buf, sizeof(struct ether_addr));
}
#endif /* EXAMPLE_GET_MAC */
return ret;
}
#endif /* GET_CUSTOM_MAC_ENABLE */
/* Customized Locale table : OPTIONAL feature */
const struct cntry_locales_custom translate_custom_table[] = {
/* Table should be filled out based on custom platform regulatory requirement */
#ifdef EXAMPLE_TABLE
{"", "XY", 4}, /* Universal if Country code is unknown or empty */
{"US", "US", 69}, /* input ISO "US" to : US regrev 69 */
{"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */
{"EU", "EU", 5}, /* European union countries to : EU regrev 05 */
{"AT", "EU", 5},
{"BE", "EU", 5},
{"BG", "EU", 5},
{"CY", "EU", 5},
{"CZ", "EU", 5},
{"DK", "EU", 5},
{"EE", "EU", 5},
{"FI", "EU", 5},
{"FR", "EU", 5},
{"DE", "EU", 5},
{"GR", "EU", 5},
{"HU", "EU", 5},
{"IE", "EU", 5},
{"IT", "EU", 5},
{"LV", "EU", 5},
{"LI", "EU", 5},
{"LT", "EU", 5},
{"LU", "EU", 5},
{"MT", "EU", 5},
{"NL", "EU", 5},
{"PL", "EU", 5},
{"PT", "EU", 5},
{"RO", "EU", 5},
{"SK", "EU", 5},
{"SI", "EU", 5},
{"ES", "EU", 5},
{"SE", "EU", 5},
{"GB", "EU", 5},
{"KR", "XY", 3},
{"AU", "XY", 3},
{"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */
{"TW", "XY", 3},
{"AR", "XY", 3},
{"MX", "XY", 3},
{"IL", "IL", 0},
{"CH", "CH", 0},
{"TR", "TR", 0},
{"NO", "NO", 0},
#endif /* EXMAPLE_TABLE */
#if defined(BCM4335_CHIP)
{"", "XZ", 11}, /* Universal if Country code is unknown or empty */
#endif // endif
{"AE", "AE", 1},
{"AR", "AR", 1},
{"AT", "AT", 1},
{"AU", "AU", 2},
{"BE", "BE", 1},
{"BG", "BG", 1},
{"BN", "BN", 1},
{"CA", "CA", 2},
{"CH", "CH", 1},
{"CY", "CY", 1},
{"CZ", "CZ", 1},
{"DE", "DE", 3},
{"DK", "DK", 1},
{"EE", "EE", 1},
{"ES", "ES", 1},
{"FI", "FI", 1},
{"FR", "FR", 1},
{"GB", "GB", 1},
{"GR", "GR", 1},
{"HR", "HR", 1},
{"HU", "HU", 1},
{"IE", "IE", 1},
{"IS", "IS", 1},
{"IT", "IT", 1},
{"ID", "ID", 1},
{"JP", "JP", 8},
{"KR", "KR", 24},
{"KW", "KW", 1},
{"LI", "LI", 1},
{"LT", "LT", 1},
{"LU", "LU", 1},
{"LV", "LV", 1},
{"MA", "MA", 1},
{"MT", "MT", 1},
{"MX", "MX", 1},
{"NL", "NL", 1},
{"NO", "NO", 1},
{"PL", "PL", 1},
{"PT", "PT", 1},
{"PY", "PY", 1},
{"RO", "RO", 1},
{"SE", "SE", 1},
{"SI", "SI", 1},
{"SK", "SK", 1},
{"TR", "TR", 7},
{"TW", "TW", 1},
{"IR", "XZ", 11}, /* Universal if Country code is IRAN, (ISLAMIC REPUBLIC OF) */
{"SD", "XZ", 11}, /* Universal if Country code is SUDAN */
{"SY", "XZ", 11}, /* Universal if Country code is SYRIAN ARAB REPUBLIC */
{"GL", "XZ", 11}, /* Universal if Country code is GREENLAND */
{"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 */
};
/* Customized Locale convertor
* input : ISO 3166-1 country abbreviation
* output: customized cspec
*/
void
#ifdef CUSTOM_COUNTRY_CODE
get_customized_country_code(void *adapter, char *country_iso_code,
wl_country_t *cspec, u32 flags)
#else
get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec)
#endif /* CUSTOM_COUNTRY_CODE */
{
#if (defined(CUSTOMER_HW) || defined(CUSTOMER_HW2)) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
struct cntry_locales_custom *cloc_ptr;
if (!cspec)
return;
#ifdef CUSTOM_COUNTRY_CODE
cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code, flags);
#else
cloc_ptr = wifi_platform_get_country_code(adapter, country_iso_code);
#endif /* CUSTOM_COUNTRY_CODE */
if (cloc_ptr) {
strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ);
cspec->rev = cloc_ptr->custom_locale_rev;
}
return;
#else
int size, i;
size = ARRAYSIZE(translate_custom_table);
if (cspec == 0)
return;
if (size == 0)
return;
for (i = 0; i < size; i++) {
if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) {
memcpy(cspec->ccode,
translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ);
cspec->rev = translate_custom_table[i].custom_locale_rev;
return;
}
}
#ifdef EXAMPLE_TABLE
/* if no country code matched return first universal code from translate_custom_table */
memcpy(cspec->ccode, translate_custom_table[0].custom_locale, WLC_CNTRY_BUF_SZ);
cspec->rev = translate_custom_table[0].custom_locale_rev;
#endif /* EXMAPLE_TABLE */
return;
#endif /* (defined(CUSTOMER_HW2) || defined(BOARD_HIKEY)) &&
* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36))
*/
}

View File

@@ -0,0 +1,294 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Platform Dependent file for Hikey
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* <<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/wlan_plat.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/of_gpio.h>
#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
extern int dhd_init_wlan_mem(void);
extern void *dhd_wlan_mem_prealloc(int section, unsigned long size);
#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
#define WIFI_TURNON_DELAY 200
#define WLAN_REG_ON_GPIO 491
#define WLAN_HOST_WAKE_GPIO 493
static int wlan_reg_on = -1;
#define DHD_DT_COMPAT_ENTRY "android,bcmdhd_wlan"
#define WIFI_WL_REG_ON_PROPNAME "wl_reg_on"
static int wlan_host_wake_up = -1;
static int wlan_host_wake_irq = 0;
#define WIFI_WLAN_HOST_WAKE_PROPNAME "wl_host_wake"
int
dhd_wifi_init_gpio(void)
{
int gpio_reg_on_val;
/* ========== WLAN_PWR_EN ============ */
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) {
wlan_reg_on = of_get_named_gpio(root_node, WIFI_WL_REG_ON_PROPNAME, 0);
wlan_host_wake_up = of_get_named_gpio(root_node, WIFI_WLAN_HOST_WAKE_PROPNAME, 0);
} else {
printk(KERN_ERR "failed to get device node of BRCM WLAN, use default GPIOs\n");
wlan_reg_on = WLAN_REG_ON_GPIO;
wlan_host_wake_up = WLAN_HOST_WAKE_GPIO;
}
/* ========== WLAN_PWR_EN ============ */
printk(KERN_INFO "%s: gpio_wlan_power : %d\n", __FUNCTION__, wlan_reg_on);
/*
* For reg_on, gpio_request will fail if the gpio is configured to output-high
* in the dts using gpio-hog, so do not return error for failure.
*/
if (gpio_request_one(wlan_reg_on, GPIOF_OUT_INIT_HIGH, "WL_REG_ON")) {
printk(KERN_ERR "%s: Failed to request gpio %d for WL_REG_ON, "
"might have configured in the dts\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);
}
gpio_reg_on_val = gpio_get_value(wlan_reg_on);
printk(KERN_INFO "%s: Initial WL_REG_ON: [%d]\n",
__FUNCTION__, gpio_get_value(wlan_reg_on));
if (gpio_reg_on_val == 0) {
printk(KERN_INFO "%s: WL_REG_ON is LOW, drive it HIGH\n", __FUNCTION__);
if (gpio_direction_output(wlan_reg_on, 1)) {
printk(KERN_ERR "%s: WL_REG_ON is failed to pull up\n", __FUNCTION__);
return -EIO;
}
}
printk(KERN_ERR "%s: WL_REG_ON is pulled up\n", __FUNCTION__);
/* Wait for WIFI_TURNON_DELAY due to power stability */
msleep(WIFI_TURNON_DELAY);
/* ========== WLAN_HOST_WAKE ============ */
printk(KERN_INFO "%s: gpio_wlan_host_wake : %d\n", __FUNCTION__, wlan_host_wake_up);
if (gpio_request_one(wlan_host_wake_up, GPIOF_IN, "WLAN_HOST_WAKE")) {
printk(KERN_ERR "%s: Failed to request gpio %d for WLAN_HOST_WAKE\n",
__FUNCTION__, wlan_host_wake_up);
return -ENODEV;
} else {
printk(KERN_ERR "%s: gpio_request WLAN_HOST_WAKE done"
" - WLAN_HOST_WAKE: GPIO %d\n",
__FUNCTION__, wlan_host_wake_up);
}
if (gpio_direction_input(wlan_host_wake_up)) {
printk(KERN_ERR "%s: Failed to set WL_HOST_WAKE gpio direction\n", __FUNCTION__);
}
wlan_host_wake_irq = gpio_to_irq(wlan_host_wake_up);
return 0;
}
extern void kirin_pcie_power_on_atu_fixup(void) __attribute__ ((weak));
extern int kirin_pcie_lp_ctrl(u32 enable) __attribute__ ((weak));
#ifndef BOARD_HIKEY_MODULAR
int
dhd_wlan_power(int onoff)
{
printk(KERN_INFO"------------------------------------------------");
printk(KERN_INFO"------------------------------------------------\n");
printk(KERN_INFO"%s Enter: power %s\n", __func__, onoff ? "on" : "off");
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__);
}
}
/* 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 {
printk(KERN_ERR "[%s] kirin_pcie_power_on_atu_fixup is NULL. "
"REG_ON may not work\n", __func__);
}
/* Enable ASPM after powering ON */
if (kirin_pcie_lp_ctrl) {
kirin_pcie_lp_ctrl(onoff);
} else {
printk(KERN_ERR "[%s] kirin_pcie_lp_ctrl is NULL. "
"ASPM may not work\n", __func__);
}
} else {
/* Disable ASPM before powering off */
if (kirin_pcie_lp_ctrl) {
kirin_pcie_lp_ctrl(onoff);
} else {
printk(KERN_ERR "[%s] kirin_pcie_lp_ctrl is NULL. "
"ASPM may not work\n", __func__);
}
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);
#endif /* BOARD_HIKEY_MODULAR */
static int
dhd_wlan_reset(int onoff)
{
return 0;
}
static int
dhd_wlan_set_carddetect(int val)
{
return 0;
}
#ifdef BCMSDIO
static int dhd_wlan_get_wake_irq(void)
{
return gpio_to_irq(wlan_host_wake_up);
}
#endif /* BCMSDIO */
#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 |
IORESOURCE_IRQ_HIGHEDGE,
};
EXPORT_SYMBOL(dhd_wlan_resources);
struct wifi_platform_data dhd_wlan_control = {
#ifndef BOARD_HIKEY_MODULAR
.set_power = dhd_wlan_power,
#endif /* BOARD_HIKEY_MODULAR */
.set_reset = dhd_wlan_reset,
.set_carddetect = dhd_wlan_set_carddetect,
#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
.mem_prealloc = dhd_wlan_mem_prealloc,
#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
#ifdef BCMSDIO
.get_wake_irq = dhd_wlan_get_wake_irq,
#endif // endif
};
EXPORT_SYMBOL(dhd_wlan_control);
int
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;
}
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) {
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)
{
gpio_free(wlan_host_wake_up);
gpio_free(wlan_reg_on);
return 0;
}
#ifndef BOARD_HIKEY_MODULAR
/* Required only for Built-in DHD */
device_initcall(dhd_wlan_init);
#endif /* BOARD_HIKEY_MODULAR */

View File

@@ -0,0 +1,562 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Platform Dependent file for usage of Preallocted Memory
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_custom_memprealloc.c 805764 2019-02-20 08:46:57Z $
*/
#include <linux/device.h>
#include <linux/slab.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>
#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM
#define WLAN_STATIC_SCAN_BUF0 5
#define WLAN_STATIC_SCAN_BUF1 6
#define WLAN_STATIC_DHD_INFO_BUF 7
#define WLAN_STATIC_DHD_WLFC_BUF 8
#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_LOG_DUMP_BUF 15
#define WLAN_STATIC_DHD_LOG_DUMP_BUF_EX 16
#define WLAN_STATIC_DHD_PKTLOG_DUMP_BUF 17
#define WLAN_SCAN_BUF_SIZE (64 * 1024)
#if defined(CONFIG_64BIT)
#define WLAN_DHD_INFO_BUF_SIZE (32 * 1024)
#define WLAN_DHD_WLFC_BUF_SIZE (64 * 1024)
#define WLAN_DHD_IF_FLOW_LKUP_SIZE (64 * 1024)
#else
#define WLAN_DHD_INFO_BUF_SIZE (32 * 1024)
#define WLAN_DHD_WLFC_BUF_SIZE (16 * 1024)
#define WLAN_DHD_IF_FLOW_LKUP_SIZE (20 * 1024)
#endif /* CONFIG_64BIT */
/* Have 2MB ramsize to accomodate future chips */
#define WLAN_DHD_MEMDUMP_SIZE (2048 * 1024)
#define PREALLOC_WLAN_SEC_NUM 4
#define PREALLOC_WLAN_BUF_NUM 160
#define PREALLOC_WLAN_SECTION_HEADER 24
#ifdef CONFIG_BCMDHD_PCIE
#define DHD_SKB_1PAGE_BUFSIZE (PAGE_SIZE*1)
#define DHD_SKB_2PAGE_BUFSIZE (PAGE_SIZE*2)
#define DHD_SKB_4PAGE_BUFSIZE (PAGE_SIZE*4)
#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_BUF_NUM * 128)
#define WLAN_SECTION_SIZE_1 0
#define WLAN_SECTION_SIZE_2 0
#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_BUF_NUM * 1024)
#define DHD_SKB_1PAGE_BUF_NUM 0
#define DHD_SKB_2PAGE_BUF_NUM 128
#define DHD_SKB_4PAGE_BUF_NUM 0
#else
#define DHD_SKB_HDRSIZE 336
#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE)
#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE)
#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE)
#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_BUF_NUM * 128)
#define WLAN_SECTION_SIZE_1 (PREALLOC_WLAN_BUF_NUM * 128)
#define WLAN_SECTION_SIZE_2 (PREALLOC_WLAN_BUF_NUM * 512)
#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_BUF_NUM * 1024)
#define DHD_SKB_1PAGE_BUF_NUM 8
#define DHD_SKB_2PAGE_BUF_NUM 8
#define DHD_SKB_4PAGE_BUF_NUM 1
#endif /* CONFIG_BCMDHD_PCIE */
#define WLAN_SKB_1_2PAGE_BUF_NUM ((DHD_SKB_1PAGE_BUF_NUM) + \
(DHD_SKB_2PAGE_BUF_NUM))
#define WLAN_SKB_BUF_NUM ((WLAN_SKB_1_2PAGE_BUF_NUM) + \
(DHD_SKB_4PAGE_BUF_NUM))
#define WLAN_MAX_PKTID_ITEMS (8192)
#define WLAN_DHD_PKTID_MAP_HDR_SIZE (20 + 4*(WLAN_MAX_PKTID_ITEMS + 1))
#define WLAN_DHD_PKTID_MAP_ITEM_SIZE (32)
#define WLAN_DHD_PKTID_MAP_SIZE ((WLAN_DHD_PKTID_MAP_HDR_SIZE) + \
((WLAN_MAX_PKTID_ITEMS+1) * WLAN_DHD_PKTID_MAP_ITEM_SIZE))
#define WLAN_MAX_PKTID_IOCTL_ITEMS (32)
#define WLAN_DHD_PKTID_IOCTL_MAP_HDR_SIZE (20 + 4*(WLAN_MAX_PKTID_IOCTL_ITEMS + 1))
#define WLAN_DHD_PKTID_IOCTL_MAP_ITEM_SIZE (32)
#define WLAN_DHD_PKTID_IOCTL_MAP_SIZE ((WLAN_DHD_PKTID_IOCTL_MAP_HDR_SIZE) + \
((WLAN_MAX_PKTID_IOCTL_ITEMS+1) * WLAN_DHD_PKTID_IOCTL_MAP_ITEM_SIZE))
#define DHD_LOG_DUMP_BUF_SIZE (1024 * 1024 * 4)
#define DHD_LOG_DUMP_BUF_EX_SIZE (1024 * 1024 * 4)
#define DHD_PKTLOG_DUMP_BUF_SIZE (64 * 1024)
#define WLAN_DHD_WLFC_HANGER_MAXITEMS 3072
#define WLAN_DHD_WLFC_HANGER_ITEM_SIZE 32
#define WLAN_DHD_WLFC_HANGER_SIZE ((WLAN_DHD_WLFC_HANGER_ITEM_SIZE) + \
((WLAN_DHD_WLFC_HANGER_MAXITEMS) * (WLAN_DHD_WLFC_HANGER_ITEM_SIZE)))
static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM];
struct wlan_mem_prealloc {
void *mem_ptr;
unsigned long size;
};
static struct wlan_mem_prealloc wlan_mem_array[PREALLOC_WLAN_SEC_NUM] = {
{NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER)},
{NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER)},
{NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER)},
{NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER)}
};
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;
static void *wlan_static_if_flow_lkup = NULL;
static void *wlan_static_dhd_memdump_ram = 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;
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_wlan_mem_prealloc(int section, unsigned long size)
{
if (section == PREALLOC_WLAN_SEC_NUM) {
return wlan_static_skb;
}
if (section == WLAN_STATIC_SCAN_BUF0) {
return wlan_static_scan_buf0;
}
if (section == WLAN_STATIC_SCAN_BUF1) {
return wlan_static_scan_buf1;
}
if (section == WLAN_STATIC_DHD_INFO_BUF) {
if (size > WLAN_DHD_INFO_BUF_SIZE) {
pr_err("request DHD_INFO size(%lu) is bigger than"
" static size(%d).\n", size,
WLAN_DHD_INFO_BUF_SIZE);
return NULL;
}
return wlan_static_dhd_info_buf;
}
if (section == WLAN_STATIC_DHD_WLFC_BUF) {
if (size > WLAN_DHD_WLFC_BUF_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_dhd_wlfc_buf;
}
if (section == WLAN_STATIC_DHD_WLFC_HANGER) {
if (size > WLAN_DHD_WLFC_HANGER_SIZE) {
pr_err("request DHD_WLFC_HANGER size(%lu) is bigger than"
" static size(%d).\n",
size, WLAN_DHD_WLFC_HANGER_SIZE);
return NULL;
}
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;
}
if (section == WLAN_STATIC_DHD_MEMDUMP_RAM) {
if (size > WLAN_DHD_MEMDUMP_SIZE) {
pr_err("request DHD_MEMDUMP_RAM size(%lu) is bigger"
" than static size(%d).\n",
size, WLAN_DHD_MEMDUMP_SIZE);
return NULL;
}
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;
}
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"
" static size(%d).\n",
size, DHD_LOG_DUMP_BUF_SIZE);
return NULL;
}
return wlan_static_dhd_log_dump_buf;
}
if (section == WLAN_STATIC_DHD_LOG_DUMP_BUF_EX) {
if (size > DHD_LOG_DUMP_BUF_EX_SIZE) {
pr_err("request DHD_LOG_DUMP_BUF_EX size(%lu) is bigger then"
" static size(%d).\n",
size, DHD_LOG_DUMP_BUF_EX_SIZE);
return NULL;
}
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;
}
if (wlan_mem_array[section].size < size) {
return NULL;
}
return wlan_mem_array[section].mem_ptr;
}
EXPORT_SYMBOL(dhd_wlan_mem_prealloc);
int
dhd_init_wlan_mem(void)
{
int i;
int j;
#if !defined(CONFIG_BCMDHD_PCIE)
for (i = 0; i < DHD_SKB_1PAGE_BUF_NUM; i++) {
wlan_static_skb[i] = __dev_alloc_skb(DHD_SKB_1PAGE_BUFSIZE, GFP_KERNEL);
if (!wlan_static_skb[i]) {
goto err_skb_alloc;
}
}
#endif /* !CONFIG_BCMDHD_PCIE */
for (i = DHD_SKB_1PAGE_BUF_NUM; i < WLAN_SKB_1_2PAGE_BUF_NUM; i++) {
wlan_static_skb[i] = __dev_alloc_skb(DHD_SKB_2PAGE_BUFSIZE, GFP_KERNEL);
if (!wlan_static_skb[i]) {
goto err_skb_alloc;
}
}
#if !defined(CONFIG_BCMDHD_PCIE)
wlan_static_skb[i] = __dev_alloc_skb(DHD_SKB_4PAGE_BUFSIZE, GFP_KERNEL);
if (!wlan_static_skb[i]) {
goto err_skb_alloc;
}
#endif /* !CONFIG_BCMDHD_PCIE */
for (i = 0; i < PREALLOC_WLAN_SEC_NUM; i++) {
if (wlan_mem_array[i].size > 0) {
wlan_mem_array[i].mem_ptr =
kmalloc(wlan_mem_array[i].size, GFP_KERNEL);
if (!wlan_mem_array[i].mem_ptr) {
goto err_mem_alloc;
}
}
}
wlan_static_scan_buf0 = kmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL);
if (!wlan_static_scan_buf0) {
pr_err("Failed to alloc wlan_static_scan_buf0\n");
goto err_mem_alloc;
}
wlan_static_scan_buf1 = kmalloc(WLAN_SCAN_BUF_SIZE, GFP_KERNEL);
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);
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);
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;
}
wlan_static_dhd_info_buf = kmalloc(WLAN_DHD_INFO_BUF_SIZE, GFP_KERNEL);
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,
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);
if (!wlan_static_dhd_wlfc_buf) {
pr_err("Failed to alloc wlan_static_dhd_wlfc_buf\n");
goto err_mem_alloc;
}
wlan_static_dhd_wlfc_hanger = kmalloc(WLAN_DHD_WLFC_HANGER_SIZE,
GFP_KERNEL);
if (!wlan_static_dhd_wlfc_hanger) {
pr_err("Failed to alloc wlan_static_dhd_wlfc_hanger\n");
goto err_mem_alloc;
}
#endif /* CONFIG_BCMDHD_PCIE */
#ifdef CONFIG_BCMDHD_PREALLOC_MEMDUMP
wlan_static_dhd_memdump_ram = kmalloc(WLAN_DHD_MEMDUMP_SIZE, GFP_KERNEL);
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;
err_mem_alloc:
#ifdef CONFIG_BCMDHD_PREALLOC_MEMDUMP
if (wlan_static_dhd_memdump_ram) {
kfree(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);
}
#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);
}
if (wlan_static_dhd_wlfc_hanger) {
kfree(wlan_static_dhd_wlfc_hanger);
}
#endif /* CONFIG_BCMDHD_PCIE */
if (wlan_static_dhd_info_buf) {
kfree(wlan_static_dhd_info_buf);
}
if (wlan_static_dhd_log_dump_buf) {
kfree(wlan_static_dhd_log_dump_buf);
}
if (wlan_static_dhd_log_dump_buf_ex) {
kfree(wlan_static_dhd_log_dump_buf_ex);
}
if (wlan_static_scan_buf1) {
kfree(wlan_static_scan_buf1);
}
if (wlan_static_scan_buf0) {
kfree(wlan_static_scan_buf0);
}
if (wlan_static_dhd_pktlog_dump_buf) {
kfree(wlan_static_dhd_pktlog_dump_buf);
}
pr_err("Failed to mem_alloc for WLAN\n");
for (j = 0; j < i; j++) {
kfree(wlan_mem_array[j].mem_ptr);
}
i = WLAN_SKB_BUF_NUM;
err_skb_alloc:
pr_err("Failed to skb_alloc for WLAN\n");
for (j = 0; j < i; j++) {
dev_kfree_skb(wlan_static_skb[j]);
}
return -ENOMEM;
}
EXPORT_SYMBOL(dhd_init_wlan_mem);
void
dhd_exit_wlan_mem(void)
{
int i = 0;
#ifdef CONFIG_BCMDHD_PREALLOC_MEMDUMP
if (wlan_static_dhd_memdump_ram) {
kfree(wlan_static_dhd_memdump_ram);
}
#endif /* CONFIG_BCMDHD_PREALLOC_MEMDUMP */
#ifdef CONFIG_BCMDHD_PCIE
if (wlan_static_if_flow_lkup) {
kfree(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);
}
if (wlan_static_dhd_wlfc_hanger) {
kfree(wlan_static_dhd_wlfc_hanger);
}
#endif /* CONFIG_BCMDHD_PCIE */
if (wlan_static_dhd_info_buf) {
kfree(wlan_static_dhd_info_buf);
}
if (wlan_static_dhd_log_dump_buf) {
kfree(wlan_static_dhd_log_dump_buf);
}
if (wlan_static_dhd_log_dump_buf_ex) {
kfree(wlan_static_dhd_log_dump_buf_ex);
}
if (wlan_static_scan_buf1) {
kfree(wlan_static_scan_buf1);
}
if (wlan_static_scan_buf0) {
kfree(wlan_static_scan_buf0);
}
if (wlan_static_dhd_pktlog_dump_buf) {
kfree(wlan_static_dhd_pktlog_dump_buf);
}
pr_err("Failed to mem_alloc for WLAN\n");
for (i = 0; i < PREALLOC_WLAN_SEC_NUM; i++) {
if (wlan_mem_array[i].mem_ptr) {
kfree(wlan_mem_array[i].mem_ptr);
}
}
pr_err("Failed to skb_alloc for WLAN\n");
for (i = 0; i < WLAN_SKB_BUF_NUM; i++) {
dev_kfree_skb(wlan_static_skb[i]);
}
return;
}
EXPORT_SYMBOL(dhd_exit_wlan_mem);
#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */

View File

@@ -0,0 +1,367 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Debug/trace/assert driver definitions for Dongle Host Driver.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_dbg.h 798329 2019-01-08 05:40:39Z $
*/
#ifndef _dhd_dbg_
#define _dhd_dbg_
#ifdef DHD_LOG_DUMP
extern char *dhd_log_dump_get_timestamp(void);
extern void dhd_log_dump_write(int type, char *binary_data,
int binary_len, const char *fmt, ...);
#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_WRITE(fmt, ...) \
dhd_log_dump_write(DLD_BUF_TYPE_GENERAL, NULL, 0, fmt, ##__VA_ARGS__)
#define DHD_LOG_DUMP_WRITE_EX(fmt, ...) \
dhd_log_dump_write(DLD_BUF_TYPE_SPECIAL, NULL, 0, fmt, ##__VA_ARGS__)
#define DHD_LOG_DUMP_WRITE_PRSRV(fmt, ...) \
dhd_log_dump_write(DLD_BUF_TYPE_PRESERVE, NULL, 0, fmt, ##__VA_ARGS__)
#endif /* !_DHD_LOG_DUMP_DEFINITIONS_ */
#define CONCISE_DUMP_BUFLEN 16 * 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 COOKIE_LOG_HDR "\n-------------------- Cookie List ----------------------------\n"
#endif /* DHD_LOG_DUMP */
#if defined(DHD_DEBUG)
/* NON-NDIS cases */
#ifdef DHD_LOG_DUMP
/* Common case for EFI and non EFI */
#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)
/* !defined(DHD_EFI) and defined(DHD_LOG_DUMP) */
#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0)
#else /* DHD_LOG_DUMP */
/* !defined(DHD_LOG_DUMP cases) */
#define DHD_ERROR(args) do {if (dhd_msg_level & DHD_ERROR_VAL) printf args;} while (0)
#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0)
#endif /* DHD_LOG_DUMP */
#define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) printf args;} while (0)
#ifdef DHD_LOG_DUMP
/* LOG_DUMP defines common to EFI and NON-EFI */
#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)
/* NON-EFI builds with LOG DUMP enabled */
#define DHD_EVENT(args) \
do { \
if (dhd_msg_level & DHD_EVENT_VAL) { \
printf args; \
DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#define DHD_PRSRV_MEM(args) \
do { \
if (dhd_msg_level & DHD_EVENT_VAL) { \
if (dhd_msg_level & DHD_PRSRV_MEM_VAL) \
printf args; \
DHD_LOG_DUMP_WRITE_PRSRV("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE_PRSRV args; \
} \
} while (0)
/* Re-using 'DHD_MSGTRACE_VAL' for controlling printing of ecounter binary event
* logs to console and debug dump -- need to cleanup in the future to use separate
* 'DHD_ECNTR_VAL' bitmap flag. 'DHD_MSGTRACE_VAL' will be defined only
* for non-android builds.
*/
#define DHD_ECNTR_LOG(args) \
do { \
if (dhd_msg_level & DHD_EVENT_VAL) { \
if (dhd_msg_level & DHD_MSGTRACE_VAL) { \
printf args; \
DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE args; \
} \
} \
} while (0)
#define DHD_ERROR_EX(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
printf args; \
DHD_LOG_DUMP_WRITE_EX("[%s]: ", dhd_log_dump_get_timestamp()); \
DHD_LOG_DUMP_WRITE_EX args; \
} \
} while (0)
#define DHD_MSGTRACE_LOG(args) \
do { \
if (dhd_msg_level & DHD_MSGTRACE_VAL) { \
printf args; \
} \
DHD_LOG_DUMP_WRITE("[%s]: ", dhd_log_dump_get_timestamp()); \
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)
#define DHD_ERROR_MEM(args) DHD_ERROR(args)
#define DHD_IOVAR_MEM(args) DHD_ERROR(args)
#define DHD_LOG_MEM(args) DHD_ERROR(args)
#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0)
#define DHD_ECNTR_LOG(args) DHD_EVENT(args)
#define DHD_PRSRV_MEM(args) DHD_EVENT(args)
#define DHD_ERROR_EX(args) DHD_ERROR(args)
#endif /* DHD_LOG_DUMP */
#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0)
#define DHD_CTL(args) do {if (dhd_msg_level & DHD_CTL_VAL) printf args;} while (0)
#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_PKT_MON(args) do {if (dhd_msg_level & DHD_PKT_MON_VAL) printf args;} while (0)
#if defined(DHD_LOG_DUMP)
#if defined(DHD_LOG_PRINT_RATE_LIMIT)
#define DHD_FWLOG(args) \
do { \
if (dhd_msg_level & DHD_FWLOG_VAL) { \
if (!log_print_threshold) \
printf args; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#else
#define DHD_FWLOG(args) \
do { \
if (dhd_msg_level & DHD_FWLOG_VAL) { \
printf args; \
DHD_LOG_DUMP_WRITE args; \
} \
} while (0)
#endif // endif
#else /* DHD_LOG_DUMP */
#define DHD_FWLOG(args) do {if (dhd_msg_level & DHD_FWLOG_VAL) printf args;} while (0)
#endif /* DHD_LOG_DUMP */
#define DHD_DBGIF(args) do {if (dhd_msg_level & DHD_DBGIF_VAL) printf args;} while (0)
#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 */
#define DHD_TRACE_HW4 DHD_TRACE
#define DHD_INFO_HW4 DHD_INFO
#define DHD_ERROR_NO_HW4 DHD_ERROR
#define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL)
#define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL)
#define DHD_INFO_ON() (dhd_msg_level & DHD_INFO_VAL)
#define DHD_DATA_ON() (dhd_msg_level & DHD_DATA_VAL)
#define DHD_CTL_ON() (dhd_msg_level & DHD_CTL_VAL)
#define DHD_TIMER_ON() (dhd_msg_level & DHD_TIMER_VAL)
#define DHD_HDRS_ON() (dhd_msg_level & DHD_HDRS_VAL)
#define DHD_BYTES_ON() (dhd_msg_level & DHD_BYTES_VAL)
#define DHD_INTR_ON() (dhd_msg_level & DHD_INTR_VAL)
#define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL)
#define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL)
#define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL)
#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL)
#define DHD_ARPOE_ON() (dhd_msg_level & DHD_ARPOE_VAL)
#define DHD_REORDER_ON() (dhd_msg_level & DHD_REORDER_VAL)
#define DHD_NOCHECKDIED_ON() (dhd_msg_level & DHD_NOCHECKDIED_VAL)
#define DHD_PNO_ON() (dhd_msg_level & DHD_PNO_VAL)
#define DHD_RTT_ON() (dhd_msg_level & DHD_RTT_VAL)
#define DHD_MSGTRACE_ON() (dhd_msg_level & DHD_MSGTRACE_VAL)
#define DHD_FWLOG_ON() (dhd_msg_level & DHD_FWLOG_VAL)
#define DHD_DBGIF_ON() (dhd_msg_level & DHD_DBGIF_VAL)
#define DHD_PKT_MON_ON() (dhd_msg_level & DHD_PKT_MON_VAL)
#define DHD_PKT_MON_DUMP_ON() (dhd_msg_level & DHD_PKT_MON_DUMP_VAL)
#ifdef DHD_PCIE_NATIVE_RUNTIMEPM
#define DHD_RPM_ON() (dhd_msg_level & DHD_RPM_VAL)
#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
#else /* defined(BCMDBG) || defined(DHD_DEBUG) */
#define DHD_ERROR(args) do {if (dhd_msg_level & DHD_ERROR_VAL) \
printf args;} while (0)
#define DHD_TRACE(args)
#define DHD_INFO(args)
#define DHD_DATA(args)
#define DHD_CTL(args)
#define DHD_TIMER(args)
#define DHD_HDRS(args)
#define DHD_BYTES(args)
#define DHD_INTR(args)
#define DHD_GLOM(args)
#define DHD_EVENT(args)
#define DHD_ECNTR_LOG(args) DHD_EVENT(args)
#define DHD_PRSRV_MEM(args) DHD_EVENT(args)
#define DHD_BTA(args)
#define DHD_ISCAN(args)
#define DHD_ARPOE(args)
#define DHD_REORDER(args)
#define DHD_PNO(args)
#define DHD_RTT(args)
#define DHD_PKT_MON(args)
#define DHD_MSGTRACE_LOG(args)
#define DHD_FWLOG(args)
#define DHD_DBGIF(args)
#define DHD_ERROR_MEM(args) DHD_ERROR(args)
#define DHD_IOVAR_MEM(args) DHD_ERROR(args)
#define DHD_LOG_MEM(args) DHD_ERROR(args)
#define DHD_ERROR_EX(args) DHD_ERROR(args)
#define DHD_TRACE_HW4 DHD_TRACE
#define DHD_INFO_HW4 DHD_INFO
#define DHD_ERROR_NO_HW4 DHD_ERROR
#define DHD_ERROR_ON() 0
#define DHD_TRACE_ON() 0
#define DHD_INFO_ON() 0
#define DHD_DATA_ON() 0
#define DHD_CTL_ON() 0
#define DHD_TIMER_ON() 0
#define DHD_HDRS_ON() 0
#define DHD_BYTES_ON() 0
#define DHD_INTR_ON() 0
#define DHD_GLOM_ON() 0
#define DHD_EVENT_ON() 0
#define DHD_BTA_ON() 0
#define DHD_ISCAN_ON() 0
#define DHD_ARPOE_ON() 0
#define DHD_REORDER_ON() 0
#define DHD_NOCHECKDIED_ON() 0
#define DHD_PNO_ON() 0
#define DHD_RTT_ON() 0
#define DHD_PKT_MON_ON() 0
#define DHD_PKT_MON_DUMP_ON() 0
#define DHD_MSGTRACE_ON() 0
#define DHD_FWLOG_ON() 0
#define DHD_DBGIF_ON() 0
#ifdef DHD_PCIE_NATIVE_RUNTIMEPM
#define DHD_RPM_ON() 0
#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
#endif // endif
#define PRINT_RATE_LIMIT_PERIOD 5000000u /* 5s in units of us */
#define DHD_ERROR_RLMT(args) \
do { \
if (dhd_msg_level & DHD_ERROR_VAL) { \
static uint64 __err_ts = 0; \
static uint32 __err_cnt = 0; \
uint64 __cur_ts = 0; \
__cur_ts = OSL_SYSUPTIME_US(); \
if (__err_ts == 0 || (__cur_ts > __err_ts && \
(__cur_ts - __err_ts > PRINT_RATE_LIMIT_PERIOD))) { \
__err_ts = __cur_ts; \
DHD_ERROR(args); \
DHD_ERROR(("[Repeats %u times]\n", __err_cnt)); \
__err_cnt = 0; \
} else { \
++__err_cnt; \
} \
} \
} while (0)
/* even in non-BCMDBG builds, logging of dongle iovars should be available */
#define DHD_DNGL_IOVAR_SET(args) \
do {if (dhd_msg_level & DHD_DNGL_IOVAR_SET_VAL) printf args;} while (0)
#define DHD_LOG(args)
#define DHD_BLOG(cp, size)
#define DHD_NONE(args)
extern int dhd_msg_level;
#ifdef DHD_LOG_PRINT_RATE_LIMIT
extern int log_print_threshold;
#endif /* DHD_LOG_PRINT_RATE_LIMIT */
#define DHD_RTT_MEM(args) DHD_LOG_MEM(args)
#define DHD_RTT_ERR(args) DHD_ERROR(args)
/* Defines msg bits */
#include <dhdioctl.h>
#endif /* _dhd_dbg_ */

View File

@@ -0,0 +1,426 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* DHD debug ring API and structures
*
* <<Broadcom-WL-IPTag/Open:>>
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: dhd_dbg_ring.c 792099 2018-12-03 15:45:56Z $
*/
#include <typedefs.h>
#include <osl.h>
#include <bcmutils.h>
#include <bcmendian.h>
#include <dngl_stats.h>
#include <dhd.h>
#include <dhd_dbg.h>
#include <dhd_dbg_ring.h>
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 *buf;
unsigned long flags = 0;
if (allocd_buf == NULL) {
return BCME_NOMEM;
} else {
buf = allocd_buf;
}
ring->lock = DHD_DBG_RING_LOCK_INIT(dhdp->osh);
if (!ring->lock)
return BCME_NOMEM;
DHD_DBG_RING_LOCK(ring->lock, flags);
ring->id = id;
strncpy(ring->name, name, DBGRING_NAME_MAX);
ring->name[DBGRING_NAME_MAX - 1] = 0;
ring->ring_size = ring_sz;
ring->wp = ring->rp = 0;
ring->ring_buf = buf;
ring->threshold = DBGRING_FLUSH_THRESHOLD(ring);
ring->state = RING_SUSPEND;
ring->rem_len = 0;
ring->sched_pull = TRUE;
ring->pull_inactive = pull_inactive;
DHD_DBG_RING_UNLOCK(ring->lock, flags);
return BCME_OK;
}
void
dhd_dbg_ring_deinit(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring)
{
unsigned long flags = 0;
DHD_DBG_RING_LOCK(ring->lock, flags);
ring->id = 0;
ring->name[0] = 0;
ring->wp = ring->rp = 0;
memset(&ring->stat, 0, sizeof(ring->stat));
ring->threshold = 0;
ring->state = RING_STOP;
DHD_DBG_RING_UNLOCK(ring->lock, flags);
DHD_DBG_RING_LOCK_DEINIT(dhdp->osh, ring->lock);
}
void
dhd_dbg_ring_sched_pull(dhd_dbg_ring_t *ring, uint32 pending_len,
os_pullreq_t pull_fn, void *os_pvt, const int id)
{
unsigned long flags = 0;
DHD_DBG_RING_LOCK(ring->lock, flags);
/* if the current pending size is bigger than threshold and
* threshold is set
*/
if (ring->threshold > 0 &&
(pending_len >= ring->threshold) && ring->sched_pull) {
/*
* Update the state and release the lock before calling
* the pull_fn. Do not transfer control to other layers
* with locks held. If the call back again calls into
* the same layer fro this context, can lead to deadlock.
*/
ring->sched_pull = FALSE;
DHD_DBG_RING_UNLOCK(ring->lock, flags);
pull_fn(os_pvt, id);
} else {
DHD_DBG_RING_UNLOCK(ring->lock, flags);
}
}
uint32
dhd_dbg_ring_get_pending_len(dhd_dbg_ring_t *ring)
{
uint32 pending_len = 0;
unsigned long flags = 0;
DHD_DBG_RING_LOCK(ring->lock, flags);
if (ring->stat.written_bytes > ring->stat.read_bytes) {
pending_len = ring->stat.written_bytes - ring->stat.read_bytes;
} else if (ring->stat.written_bytes < ring->stat.read_bytes) {
pending_len = PENDING_LEN_MAX - ring->stat.read_bytes + ring->stat.written_bytes;
} else {
pending_len = 0;
}
DHD_DBG_RING_UNLOCK(ring->lock, flags);
return pending_len;
}
int
dhd_dbg_ring_push(dhd_dbg_ring_t *ring, dhd_dbg_ring_entry_t *hdr, void *data)
{
unsigned long flags;
uint32 w_len;
uint32 avail_size;
dhd_dbg_ring_entry_t *w_entry, *r_entry;
if (!ring || !hdr || !data) {
return BCME_BADARG;
}
DHD_DBG_RING_LOCK(ring->lock, flags);
if (ring->state != RING_ACTIVE) {
DHD_DBG_RING_UNLOCK(ring->lock, flags);
return BCME_OK;
}
w_len = ENTRY_LENGTH(hdr);
DHD_DBGIF(("%s: RING%d[%s] hdr->len=%u, w_len=%u, wp=%d, rp=%d, ring_start=0x%p;"
" ring_size=%u\n",
__FUNCTION__, ring->id, ring->name, hdr->len, w_len, ring->wp, ring->rp,
ring->ring_buf, ring->ring_size));
if (w_len > ring->ring_size) {
DHD_DBG_RING_UNLOCK(ring->lock, flags);
DHD_ERROR(("%s: RING%d[%s] w_len=%u, ring_size=%u,"
" write size exceeds ring size !\n",
__FUNCTION__, ring->id, ring->name, w_len, ring->ring_size));
return BCME_BUFTOOLONG;
}
/* Claim the space */
do {
avail_size = DBG_RING_CHECK_WRITE_SPACE(ring->rp, ring->wp, ring->ring_size);
if (avail_size <= w_len) {
/* Prepare the space */
if (ring->rp <= ring->wp) {
ring->tail_padded = TRUE;
ring->rem_len = ring->ring_size - ring->wp;
DHD_DBGIF(("%s: RING%d[%s] Insuffient tail space,"
" rp=%d, wp=%d, rem_len=%d, ring_size=%d,"
" avail_size=%d, w_len=%d\n", __FUNCTION__,
ring->id, ring->name, ring->rp, ring->wp,
ring->rem_len, ring->ring_size, avail_size,
w_len));
/* 0 pad insufficient tail space */
memset((uint8 *)ring->ring_buf + ring->wp, 0, ring->rem_len);
/* If read pointer is still at the beginning, make some room */
if (ring->rp == 0) {
r_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf +
ring->rp);
ring->rp += ENTRY_LENGTH(r_entry);
ring->stat.read_bytes += ENTRY_LENGTH(r_entry);
DHD_DBGIF(("%s: rp at 0, move by one entry length"
" (%u bytes)\n",
__FUNCTION__, (uint32)ENTRY_LENGTH(r_entry)));
}
if (ring->rp == ring->wp) {
ring->rp = 0;
}
ring->wp = 0;
DHD_DBGIF(("%s: new rp=%u, wp=%u\n",
__FUNCTION__, ring->rp, ring->wp));
} else {
/* Not enough space for new entry, free some up */
r_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf +
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, "
"ring->wp=%u, ring->rp=%u, ring->ring_size=%d\n",
__FUNCTION__, ring->id, ring->name, ring->wp,
ring->rp, ring->ring_size));
ASSERT(0);
DHD_DBG_RING_UNLOCK(ring->lock, flags);
return BCME_BUFTOOSHORT;
}
ring->rp += ENTRY_LENGTH(r_entry);
/* skip padding if there is one */
if (ring->tail_padded &&
((ring->rp + ring->rem_len) == ring->ring_size)) {
DHD_DBGIF(("%s: RING%d[%s] Found padding,"
" avail_size=%d, w_len=%d, set rp=0\n",
__FUNCTION__, ring->id, ring->name,
avail_size, w_len));
ring->rp = 0;
ring->tail_padded = FALSE;
ring->rem_len = 0;
}
ring->stat.read_bytes += ENTRY_LENGTH(r_entry);
DHD_DBGIF(("%s: RING%d[%s] read_bytes=%d, wp=%d, rp=%d\n",
__FUNCTION__, ring->id, ring->name, ring->stat.read_bytes,
ring->wp, ring->rp));
}
} else {
break;
}
} while (TRUE);
/* 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, "
"wp=%d, ring_size=%d, w_len=%u\n", __FUNCTION__, ring->id,
ring->name, ring->wp, ring->ring_size, w_len));
ASSERT(0);
DHD_DBG_RING_UNLOCK(ring->lock, flags);
return BCME_BUFTOOLONG;
}
w_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf + ring->wp);
/* header */
memcpy(w_entry, hdr, DBG_RING_ENTRY_SIZE);
w_entry->len = hdr->len;
/* payload */
memcpy((char *)w_entry + DBG_RING_ENTRY_SIZE, data, w_entry->len);
/* update write pointer */
ring->wp += w_len;
/* 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;
}
/*
* This function folds ring->lock, so callers of this function
* should not hold ring->lock.
*/
int
dhd_dbg_ring_pull_single(dhd_dbg_ring_t *ring, void *data, uint32 buf_len, bool strip_header)
{
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
* pulled to dump it to a file. For other rings if ring is
* not in active state return without processing (as before)
*/
if (!ring->pull_inactive && (ring->state != RING_ACTIVE)) {
goto exit;
}
if (ring->rp == ring->wp) {
goto exit;
}
DHD_DBGIF(("%s: RING%d[%s] buf_len=%u, wp=%d, rp=%d, ring_start=0x%p; ring_size=%u\n",
__FUNCTION__, ring->id, ring->name, buf_len, ring->wp, ring->rp,
ring->ring_buf, ring->ring_size));
r_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf + ring->rp);
/* 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,"
" current ring %d[%s] - rp=%d\n", __FUNCTION__, rlen,
ring->ring_size, ring->id, ring->name, ring->rp));
rlen = 0;
goto exit;
}
if (strip_header) {
rlen = r_entry->len;
buf = (char *)r_entry + DBG_RING_ENTRY_SIZE;
} else {
rlen = ENTRY_LENGTH(r_entry);
buf = (char *)r_entry;
}
if (rlen > buf_len) {
DHD_ERROR(("%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",
__FUNCTION__, ring->id, ring->name, ring->ring_size,
ring->wp, ring->rp));
ASSERT(0);
rlen = 0;
goto exit;
}
memcpy(data, buf, rlen);
/* update ring context */
ring->rp += ENTRY_LENGTH(r_entry);
/* don't pass wp but skip padding if there is one */
if (ring->rp != ring->wp &&
ring->tail_padded && ((ring->rp + ring->rem_len) >= ring->ring_size)) {
DHD_DBGIF(("%s: RING%d[%s] Found padding, rp=%d, wp=%d\n",
__FUNCTION__, ring->id, ring->name, ring->rp, ring->wp));
ring->rp = 0;
ring->tail_padded = FALSE;
ring->rem_len = 0;
}
if (ring->rp >= ring->ring_size) {
DHD_ERROR(("%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);
rlen = 0;
goto exit;
}
ring->stat.read_bytes += ENTRY_LENGTH(r_entry);
DHD_DBGIF(("%s RING%d[%s]read_bytes %d, wp=%d, rp=%d\n", __FUNCTION__,
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)
{
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);
if (r_len == 0)
break;
data = (uint8 *)data + r_len;
buf_len -= r_len;
total_r_len += r_len;
}
return total_r_len;
}
int
dhd_dbg_ring_config(dhd_dbg_ring_t *ring, int log_level, uint32 threshold)
{
unsigned long flags = 0;
if (!ring)
return BCME_BADADDR;
if (ring->state == RING_STOP)
return BCME_UNSUPPORTED;
DHD_DBG_RING_LOCK(ring->lock, flags);
if (log_level == 0)
ring->state = RING_SUSPEND;
else
ring->state = RING_ACTIVE;
ring->log_level = log_level;
ring->threshold = MIN(threshold, DBGRING_FLUSH_THRESHOLD(ring));
DHD_DBG_RING_UNLOCK(ring->lock, flags);
return BCME_OK;
}
void
dhd_dbg_ring_start(dhd_dbg_ring_t *ring)
{
if (!ring)
return;
/* Initialize the information for the ring */
ring->state = RING_SUSPEND;
ring->log_level = 0;
ring->rp = ring->wp = 0;
ring->threshold = 0;
memset(&ring->stat, 0, sizeof(struct ring_statistics));
memset(ring->ring_buf, 0, ring->ring_size);
}

View File

@@ -0,0 +1,141 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* DHD debug ring header file
*
* <<Broadcom-WL-IPTag/Open:>>
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: dhd_dbg_ring.h 795094 2018-12-17 08:56:58Z $
*/
#ifndef __DHD_DBG_RING_H__
#define __DHD_DBG_RING_H__
#include <bcmutils.h>
#define PACKED_STRUCT __attribute__ ((packed))
#define DBGRING_NAME_MAX 32
enum dbg_ring_state {
RING_STOP = 0, /* ring is not initialized */
RING_ACTIVE, /* ring is live and logging */
RING_SUSPEND /* ring is initialized but not logging */
};
/* each entry in dbg ring has below header, to handle
* variable length records in ring
*/
typedef struct dhd_dbg_ring_entry {
uint16 len; /* payload length excluding the header */
uint8 flags;
uint8 type; /* Per ring specific */
uint64 timestamp; /* present if has_timestamp bit is set. */
} PACKED_STRUCT dhd_dbg_ring_entry_t;
struct ring_statistics {
/* number of bytes that was written to the buffer by driver */
uint32 written_bytes;
/* number of bytes that was read from the buffer by user land */
uint32 read_bytes;
/* number of records that was written to the buffer by driver */
uint32 written_records;
};
typedef struct dhd_dbg_ring_status {
uint8 name[DBGRING_NAME_MAX];
uint32 flags;
int ring_id; /* unique integer representing the ring */
/* total memory size allocated for the buffer */
uint32 ring_buffer_byte_size;
uint32 verbose_level;
/* number of bytes that was written to the buffer by driver */
uint32 written_bytes;
/* number of bytes that was read from the buffer by user land */
uint32 read_bytes;
/* number of records that was read from the buffer by user land */
uint32 written_records;
} dhd_dbg_ring_status_t;
typedef struct dhd_dbg_ring {
int id; /* ring id */
uint8 name[DBGRING_NAME_MAX]; /* name string */
uint32 ring_size; /* numbers of item in ring */
uint32 wp; /* write pointer */
uint32 rp; /* read pointer */
uint32 rp_tmp; /* tmp read pointer */
uint32 log_level; /* log_level */
uint32 threshold; /* threshold bytes */
void * ring_buf; /* pointer of actually ring buffer */
void * lock; /* lock for ring access */
struct ring_statistics stat; /* statistics */
enum dbg_ring_state state; /* ring state enum */
bool tail_padded; /* writer does not have enough space */
uint32 rem_len; /* number of bytes from wp_pad to end */
bool sched_pull; /* schedule reader immediately */
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 RING_STAT_TO_STATUS(ring, status) \
do { \
strncpy(status.name, ring->name, \
sizeof(status.name) - 1); \
status.ring_id = ring->id; \
status.ring_buffer_byte_size = ring->ring_size; \
status.written_bytes = ring->stat.written_bytes; \
status.written_records = ring->stat.written_records; \
status.read_bytes = ring->stat.read_bytes; \
status.verbose_level = ring->log_level; \
} while (0)
#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 PENDING_LEN_MAX 0xFFFFFFFF
#define DBG_RING_STATUS_SIZE (sizeof(dhd_dbg_ring_status_t))
#define TXACTIVESZ(r, w, d) (((r) <= (w)) ? ((w) - (r)) : ((d) - (r) + (w)))
#define DBG_RING_READ_AVAIL_SPACE(w, r, d) (((w) >= (r)) ? ((w) - (r)) : ((d) - (r)))
#define DBG_RING_WRITE_SPACE_AVAIL_CONT(r, w, d) (((w) >= (r)) ? ((d) - (w)) : ((r) - (w)))
#define DBG_RING_WRITE_SPACE_AVAIL(r, w, d) (d - (TXACTIVESZ(r, w, d)))
#define DBG_RING_CHECK_WRITE_SPACE(r, w, d) \
MIN(DBG_RING_WRITE_SPACE_AVAIL(r, w, d), DBG_RING_WRITE_SPACE_AVAIL_CONT(r, w, d))
typedef void (*os_pullreq_t)(void *os_priv, const int ring_id);
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_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);
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);
void dhd_dbg_ring_sched_pull(dhd_dbg_ring_t *ring, uint32 pending_len,
os_pullreq_t pull_fn, void *os_pvt, const int id);
int dhd_dbg_ring_config(dhd_dbg_ring_t *ring, int log_level, uint32 threshold);
void dhd_dbg_ring_start(dhd_dbg_ring_t *ring);
#endif /* __DHD_DBG_RING_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,853 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* DHD debugability header file
*
* <<Broadcom-WL-IPTag/Open:>>
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: dhd_debug.h 783721 2018-10-08 13:05:26Z $
*/
#ifndef _dhd_debug_h_
#define _dhd_debug_h_
#include <event_log.h>
#include <bcmutils.h>
#include <dhd_dbg_ring.h>
enum {
DEBUG_RING_ID_INVALID = 0,
FW_VERBOSE_RING_ID,
DHD_EVENT_RING_ID,
/* add new id here */
DEBUG_RING_ID_MAX
};
enum {
/* Feature set */
DBG_MEMORY_DUMP_SUPPORTED = (1 << (0)), /* Memory dump of FW */
DBG_PER_PACKET_TX_RX_STATUS_SUPPORTED = (1 << (1)), /* PKT Status */
DBG_CONNECT_EVENT_SUPPORTED = (1 << (2)), /* Connectivity Event */
DBG_POWER_EVENT_SUPOORTED = (1 << (3)), /* POWER of Driver */
DBG_WAKE_LOCK_SUPPORTED = (1 << (4)), /* WAKE LOCK of Driver */
DBG_VERBOSE_LOG_SUPPORTED = (1 << (5)), /* verbose log of FW */
DBG_HEALTH_CHECK_SUPPORTED = (1 << (6)), /* monitor the health of FW */
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 */
};
enum {
/* set for binary entries */
DBG_RING_ENTRY_FLAGS_HAS_BINARY = (1 << (0)),
/* set if 64 bits timestamp is present */
DBG_RING_ENTRY_FLAGS_HAS_TIMESTAMP = (1 << (1))
};
/* firmware verbose ring, ring id 1 */
#define FW_VERBOSE_RING_NAME "fw_verbose"
#define FW_VERBOSE_RING_SIZE (256 * 1024)
/* firmware event ring, ring id 2 */
#define FW_EVENT_RING_NAME "fw_event"
#define FW_EVENT_RING_SIZE (64 * 1024)
/* DHD connection event ring, ring id 3 */
#define DHD_EVENT_RING_NAME "dhd_event"
#define DHD_EVENT_RING_SIZE (64 * 1024)
/* NAN event ring, ring id 4 */
#define NAN_EVENT_RING_NAME "nan_event"
#define NAN_EVENT_RING_SIZE (64 * 1024)
#define TLV_LOG_SIZE(tlv) ((tlv) ? (sizeof(tlv_log) + (tlv)->len) : 0)
#define TLV_LOG_NEXT(tlv) \
((tlv) ? ((tlv_log *)((uint8 *)tlv + TLV_LOG_SIZE(tlv))) : 0)
#define VALID_RING(id) \
((id > DEBUG_RING_ID_INVALID) && (id < DEBUG_RING_ID_MAX))
#ifdef DEBUGABILITY
#define DBG_RING_ACTIVE(dhdp, ring_id) \
((dhdp)->dbg->dbg_rings[(ring_id)].state == RING_ACTIVE)
#else
#define DBG_RING_ACTIVE(dhdp, ring_id) 0
#endif /* DEBUGABILITY */
enum {
/* driver receive association command from kernel */
WIFI_EVENT_ASSOCIATION_REQUESTED = 0,
WIFI_EVENT_AUTH_COMPLETE,
WIFI_EVENT_ASSOC_COMPLETE,
/* received firmware event indicating auth frames are sent */
WIFI_EVENT_FW_AUTH_STARTED,
/* received firmware event indicating assoc frames are sent */
WIFI_EVENT_FW_ASSOC_STARTED,
/* received firmware event indicating reassoc frames are sent */
WIFI_EVENT_FW_RE_ASSOC_STARTED,
WIFI_EVENT_DRIVER_SCAN_REQUESTED,
WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND,
WIFI_EVENT_DRIVER_SCAN_COMPLETE,
WIFI_EVENT_G_SCAN_STARTED,
WIFI_EVENT_G_SCAN_COMPLETE,
WIFI_EVENT_DISASSOCIATION_REQUESTED,
WIFI_EVENT_RE_ASSOCIATION_REQUESTED,
WIFI_EVENT_ROAM_REQUESTED,
/* received beacon from AP (event enabled only in verbose mode) */
WIFI_EVENT_BEACON_RECEIVED,
/* firmware has triggered a roam scan (not g-scan) */
WIFI_EVENT_ROAM_SCAN_STARTED,
/* firmware has completed a roam scan (not g-scan) */
WIFI_EVENT_ROAM_SCAN_COMPLETE,
/* firmware has started searching for roam candidates (with reason =xx) */
WIFI_EVENT_ROAM_SEARCH_STARTED,
/* firmware has stopped searching for roam candidates (with reason =xx) */
WIFI_EVENT_ROAM_SEARCH_STOPPED,
WIFI_EVENT_UNUSED_0,
/* received channel switch anouncement from AP */
WIFI_EVENT_CHANNEL_SWITCH_ANOUNCEMENT,
/* fw start transmit eapol frame, with EAPOL index 1-4 */
WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_START,
/* fw gives up eapol frame, with rate, success/failure and number retries */
WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_STOP,
/* kernel queue EAPOL for transmission in driver with EAPOL index 1-4 */
WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED,
/* with rate, regardless of the fact that EAPOL frame is accepted or
* rejected by firmware
*/
WIFI_EVENT_FW_EAPOL_FRAME_RECEIVED,
WIFI_EVENT_UNUSED_1,
/* with rate, and eapol index, driver has received */
/* EAPOL frame and will queue it up to wpa_supplicant */
WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED,
/* with success/failure, parameters */
WIFI_EVENT_BLOCK_ACK_NEGOTIATION_COMPLETE,
WIFI_EVENT_BT_COEX_BT_SCO_START,
WIFI_EVENT_BT_COEX_BT_SCO_STOP,
/* for paging/scan etc..., when BT starts transmiting twice per BT slot */
WIFI_EVENT_BT_COEX_BT_SCAN_START,
WIFI_EVENT_BT_COEX_BT_SCAN_STOP,
WIFI_EVENT_BT_COEX_BT_HID_START,
WIFI_EVENT_BT_COEX_BT_HID_STOP,
/* firmware sends auth frame in roaming to next candidate */
WIFI_EVENT_ROAM_AUTH_STARTED,
/* firmware receive auth confirm from ap */
WIFI_EVENT_ROAM_AUTH_COMPLETE,
/* firmware sends assoc/reassoc frame in */
WIFI_EVENT_ROAM_ASSOC_STARTED,
/* firmware receive assoc/reassoc confirm from ap */
WIFI_EVENT_ROAM_ASSOC_COMPLETE,
/* firmware sends stop G_SCAN */
WIFI_EVENT_G_SCAN_STOP,
/* firmware indicates G_SCAN scan cycle started */
WIFI_EVENT_G_SCAN_CYCLE_STARTED,
/* firmware indicates G_SCAN scan cycle completed */
WIFI_EVENT_G_SCAN_CYCLE_COMPLETED,
/* firmware indicates G_SCAN scan start for a particular bucket */
WIFI_EVENT_G_SCAN_BUCKET_STARTED,
/* firmware indicates G_SCAN scan completed for particular bucket */
WIFI_EVENT_G_SCAN_BUCKET_COMPLETED,
/* Event received from firmware about G_SCAN scan results being available */
WIFI_EVENT_G_SCAN_RESULTS_AVAILABLE,
/* Event received from firmware with G_SCAN capabilities */
WIFI_EVENT_G_SCAN_CAPABILITIES,
/* Event received from firmware when eligible candidate is found */
WIFI_EVENT_ROAM_CANDIDATE_FOUND,
/* Event received from firmware when roam scan configuration gets enabled or disabled */
WIFI_EVENT_ROAM_SCAN_CONFIG,
/* firmware/driver timed out authentication */
WIFI_EVENT_AUTH_TIMEOUT,
/* firmware/driver timed out association */
WIFI_EVENT_ASSOC_TIMEOUT,
/* firmware/driver encountered allocation failure */
WIFI_EVENT_MEM_ALLOC_FAILURE,
/* driver added a PNO network in firmware */
WIFI_EVENT_DRIVER_PNO_ADD,
/* driver removed a PNO network in firmware */
WIFI_EVENT_DRIVER_PNO_REMOVE,
/* driver received PNO networks found indication from firmware */
WIFI_EVENT_DRIVER_PNO_NETWORK_FOUND,
/* driver triggered a scan for PNO networks */
WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED,
/* driver received scan results of PNO networks */
WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND,
/* driver updated scan results from PNO candidates to cfg */
WIFI_EVENT_DRIVER_PNO_SCAN_COMPLETE
};
enum {
WIFI_TAG_VENDOR_SPECIFIC = 0, /* take a byte stream as parameter */
WIFI_TAG_BSSID, /* takes a 6 bytes MAC address as parameter */
WIFI_TAG_ADDR, /* takes a 6 bytes MAC address as parameter */
WIFI_TAG_SSID, /* takes a 32 bytes SSID address as parameter */
WIFI_TAG_STATUS, /* takes an integer as parameter */
WIFI_TAG_CHANNEL_SPEC, /* takes one or more wifi_channel_spec as parameter */
WIFI_TAG_WAKE_LOCK_EVENT, /* takes a wake_lock_event struct as parameter */
WIFI_TAG_ADDR1, /* takes a 6 bytes MAC address as parameter */
WIFI_TAG_ADDR2, /* takes a 6 bytes MAC address as parameter */
WIFI_TAG_ADDR3, /* takes a 6 bytes MAC address as parameter */
WIFI_TAG_ADDR4, /* takes a 6 bytes MAC address as parameter */
WIFI_TAG_TSF, /* take a 64 bits TSF value as parameter */
WIFI_TAG_IE,
/* take one or more specific 802.11 IEs parameter, IEs are in turn
* indicated in TLV format as per 802.11 spec
*/
WIFI_TAG_INTERFACE, /* take interface name as parameter */
WIFI_TAG_REASON_CODE, /* take a reason code as per 802.11 as parameter */
WIFI_TAG_RATE_MBPS, /* take a wifi rate in 0.5 mbps */
WIFI_TAG_REQUEST_ID, /* take an integer as parameter */
WIFI_TAG_BUCKET_ID, /* take an integer as parameter */
WIFI_TAG_GSCAN_PARAMS, /* takes a wifi_scan_cmd_params struct as parameter */
WIFI_TAG_GSCAN_CAPABILITIES, /* takes a wifi_gscan_capabilities struct as parameter */
WIFI_TAG_SCAN_ID, /* take an integer as parameter */
WIFI_TAG_RSSI, /* takes s16 as parameter */
WIFI_TAG_CHANNEL, /* takes u16 as parameter */
WIFI_TAG_LINK_ID, /* take an integer as parameter */
WIFI_TAG_LINK_ROLE, /* take an integer as parameter */
WIFI_TAG_LINK_STATE, /* take an integer as parameter */
WIFI_TAG_LINK_TYPE, /* take an integer as parameter */
WIFI_TAG_TSCO, /* take an integer as parameter */
WIFI_TAG_RSCO, /* take an integer as parameter */
WIFI_TAG_EAPOL_MESSAGE_TYPE /* take an integer as parameter */
};
/* NAN events */
typedef enum {
NAN_EVENT_INVALID = 0,
NAN_EVENT_CLUSTER_STARTED = 1,
NAN_EVENT_CLUSTER_JOINED = 2,
NAN_EVENT_CLUSTER_MERGED = 3,
NAN_EVENT_ROLE_CHANGED = 4,
NAN_EVENT_SCAN_COMPLETE = 5,
NAN_EVENT_STATUS_CHNG = 6,
/* ADD new events before this line */
NAN_EVENT_MAX
} nan_event_id_t;
typedef struct {
uint16 tag;
uint16 len; /* length of value */
uint8 value[0];
} tlv_log;
typedef struct per_packet_status_entry {
uint8 flags;
uint8 tid; /* transmit or received tid */
uint16 MCS; /* modulation and bandwidth */
/*
* TX: RSSI of ACK for that packet
* RX: RSSI of packet
*/
uint8 rssi;
uint8 num_retries; /* number of attempted retries */
uint16 last_transmit_rate; /* last transmit rate in .5 mbps */
/* transmit/reeive sequence for that MPDU packet */
uint16 link_layer_transmit_sequence;
/*
* TX: firmware timestamp (us) when packet is queued within firmware buffer
* for SDIO/HSIC or into PCIe buffer
* RX : firmware receive timestamp
*/
uint64 firmware_entry_timestamp;
/*
* firmware timestamp (us) when packet start contending for the
* medium for the first time, at head of its AC queue,
* or as part of an MPDU or A-MPDU. This timestamp is not updated
* for each retry, only the first transmit attempt.
*/
uint64 start_contention_timestamp;
/*
* fimrware timestamp (us) when packet is successfully transmitted
* or aborted because it has exhausted its maximum number of retries
*/
uint64 transmit_success_timestamp;
/*
* packet data. The length of packet data is determined by the entry_size field of
* the wifi_ring_buffer_entry structure. It is expected that first bytes of the
* packet, or packet headers only (up to TCP or RTP/UDP headers) will be copied into the ring
*/
uint8 *data;
} per_packet_status_entry_t;
#define PACKED_STRUCT __attribute__ ((packed))
typedef struct log_conn_event {
uint16 event;
tlv_log *tlvs;
/*
* separate parameter structure per event to be provided and optional data
* the event_data is expected to include an official android part, with some
* parameter as transmit rate, num retries, num scan result found etc...
* as well, event_data can include a vendor proprietary part which is
* understood by the developer only.
*/
} PACKED_STRUCT log_conn_event_t;
/*
* Ring buffer name for power events ring. note that power event are extremely frequents
* and thus should be stored in their own ring/file so as not to clobber connectivity events
*/
typedef struct wake_lock_event {
uint32 status; /* 0 taken, 1 released */
uint32 reason; /* reason why this wake lock is taken */
char *name; /* null terminated */
} wake_lock_event_t;
typedef struct wifi_power_event {
uint16 event;
tlv_log *tlvs;
} wifi_power_event_t;
#define NAN_EVENT_VERSION 1
typedef struct log_nan_event {
uint8 version;
uint8 pad;
uint16 event;
tlv_log *tlvs;
} log_nan_event_t;
/* entry type */
enum {
DBG_RING_ENTRY_EVENT_TYPE = 1,
DBG_RING_ENTRY_PKT_TYPE,
DBG_RING_ENTRY_WAKE_LOCK_EVENT_TYPE,
DBG_RING_ENTRY_POWER_EVENT_TYPE,
DBG_RING_ENTRY_DATA_TYPE,
DBG_RING_ENTRY_NAN_EVENT_TYPE
};
struct log_level_table {
int log_level;
uint16 tag;
char *desc;
};
/*
* Assuming that the Ring lock is mutex, bailing out if the
* callers are from atomic context. On a long term, one has to
* schedule a job to execute in sleepable context so that
* contents are pushed to the ring.
*/
#define DBG_EVENT_LOG(dhdp, connect_state) \
{ \
do { \
uint16 state = connect_state; \
if (CAN_SLEEP() && DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) \
dhd_os_push_push_ring_data(dhdp, DHD_EVENT_RING_ID, \
&state, sizeof(state)); \
} while (0); \
}
#define MD5_PREFIX_LEN 4
#define MAX_FATE_LOG_LEN 32
#define MAX_FRAME_LEN_ETHERNET 1518
#define MAX_FRAME_LEN_80211_MGMT 2352 /* 802.11-2012 Fig. 8-34 */
typedef enum {
/* Sent over air and ACKed. */
TX_PKT_FATE_ACKED,
/* Sent over air but not ACKed. (Normal for broadcast/multicast.) */
TX_PKT_FATE_SENT,
/* Queued within firmware, but not yet sent over air. */
TX_PKT_FATE_FW_QUEUED,
/*
* Dropped by firmware as invalid. E.g. bad source address,
* bad checksum, or invalid for current state.
*/
TX_PKT_FATE_FW_DROP_INVALID,
/* Dropped by firmware due to lifetime expiration. */
TX_PKT_FATE_FW_DROP_EXPTIME,
/*
* Dropped by firmware for any other reason. Includes
* frames that were sent by driver to firmware, but
* unaccounted for by firmware.
*/
TX_PKT_FATE_FW_DROP_OTHER,
/* Queued within driver, not yet sent to firmware. */
TX_PKT_FATE_DRV_QUEUED,
/*
* Dropped by driver as invalid. E.g. bad source address,
* or invalid for current state.
*/
TX_PKT_FATE_DRV_DROP_INVALID,
/* Dropped by driver due to lack of buffer space. */
TX_PKT_FATE_DRV_DROP_NOBUFS,
/* Dropped by driver for any other reason. */
TX_PKT_FATE_DRV_DROP_OTHER,
/* Packet free by firmware. */
TX_PKT_FATE_FW_PKT_FREE,
} wifi_tx_packet_fate;
typedef enum {
/* Valid and delivered to network stack (e.g., netif_rx()). */
RX_PKT_FATE_SUCCESS,
/* Queued within firmware, but not yet sent to driver. */
RX_PKT_FATE_FW_QUEUED,
/* Dropped by firmware due to host-programmable filters. */
RX_PKT_FATE_FW_DROP_FILTER,
/*
* Dropped by firmware as invalid. E.g. bad checksum,
* decrypt failed, or invalid for current state.
*/
RX_PKT_FATE_FW_DROP_INVALID,
/* Dropped by firmware due to lack of buffer space. */
RX_PKT_FATE_FW_DROP_NOBUFS,
/* Dropped by firmware for any other reason. */
RX_PKT_FATE_FW_DROP_OTHER,
/* Queued within driver, not yet delivered to network stack. */
RX_PKT_FATE_DRV_QUEUED,
/* Dropped by driver due to filter rules. */
RX_PKT_FATE_DRV_DROP_FILTER,
/* Dropped by driver as invalid. E.g. not permitted in current state. */
RX_PKT_FATE_DRV_DROP_INVALID,
/* Dropped by driver due to lack of buffer space. */
RX_PKT_FATE_DRV_DROP_NOBUFS,
/* Dropped by driver for any other reason. */
RX_PKT_FATE_DRV_DROP_OTHER,
} wifi_rx_packet_fate;
typedef enum {
FRAME_TYPE_UNKNOWN,
FRAME_TYPE_ETHERNET_II,
FRAME_TYPE_80211_MGMT,
} frame_type;
typedef struct wifi_frame_info {
/*
* The type of MAC-layer frame that this frame_info holds.
* - For data frames, use FRAME_TYPE_ETHERNET_II.
* - For management frames, use FRAME_TYPE_80211_MGMT.
* - If the type of the frame is unknown, use FRAME_TYPE_UNKNOWN.
*/
frame_type payload_type;
/*
* The number of bytes included in |frame_content|. If the frame
* contents are missing (e.g. RX frame dropped in firmware),
* |frame_len| should be set to 0.
*/
size_t frame_len;
/*
* Host clock when this frame was received by the driver (either
* outbound from the host network stack, or inbound from the
* firmware).
* - The timestamp should be taken from a clock which includes time
* the host spent suspended (e.g. ktime_get_boottime()).
* - If no host timestamp is available (e.g. RX frame was dropped in
* firmware), this field should be set to 0.
*/
uint32 driver_timestamp_usec;
/*
* Firmware clock when this frame was received by the firmware
* (either outbound from the host, or inbound from a remote
* station).
* - The timestamp should be taken from a clock which includes time
* firmware spent suspended (if applicable).
* - If no firmware timestamp is available (e.g. TX frame was
* dropped by driver), this field should be set to 0.
* - Consumers of |frame_info| should _not_ assume any
* synchronization between driver and firmware clocks.
*/
uint32 firmware_timestamp_usec;
/*
* Actual frame content.
* - Should be provided for TX frames originated by the host.
* - Should be provided for RX frames received by the driver.
* - Optionally provided for TX frames originated by firmware. (At
* discretion of HAL implementation.)
* - Optionally provided for RX frames dropped in firmware. (At
* discretion of HAL implementation.)
* - If frame content is not provided, |frame_len| should be set
* to 0.
*/
union {
char ethernet_ii[MAX_FRAME_LEN_ETHERNET];
char ieee_80211_mgmt[MAX_FRAME_LEN_80211_MGMT];
} frame_content;
} wifi_frame_info_t;
typedef struct wifi_tx_report {
/*
* Prefix of MD5 hash of |frame_inf.frame_content|. If frame
* content is not provided, prefix of MD5 hash over the same data
* that would be in frame_content, if frame content were provided.
*/
char md5_prefix[MD5_PREFIX_LEN];
wifi_tx_packet_fate fate;
wifi_frame_info_t frame_inf;
} wifi_tx_report_t;
typedef struct wifi_rx_report {
/*
* Prefix of MD5 hash of |frame_inf.frame_content|. If frame
* content is not provided, prefix of MD5 hash over the same data
* that would be in frame_content, if frame content were provided.
*/
char md5_prefix[MD5_PREFIX_LEN];
wifi_rx_packet_fate fate;
wifi_frame_info_t frame_inf;
} wifi_rx_report_t;
typedef struct compat_wifi_frame_info {
frame_type payload_type;
uint32 frame_len;
uint32 driver_timestamp_usec;
uint32 firmware_timestamp_usec;
union {
char ethernet_ii[MAX_FRAME_LEN_ETHERNET];
char ieee_80211_mgmt[MAX_FRAME_LEN_80211_MGMT];
} frame_content;
} compat_wifi_frame_info_t;
typedef struct compat_wifi_tx_report {
char md5_prefix[MD5_PREFIX_LEN];
wifi_tx_packet_fate fate;
compat_wifi_frame_info_t frame_inf;
} compat_wifi_tx_report_t;
typedef struct compat_wifi_rx_report {
char md5_prefix[MD5_PREFIX_LEN];
wifi_rx_packet_fate fate;
compat_wifi_frame_info_t frame_inf;
} compat_wifi_rx_report_t;
/*
* Packet logging - internal data
*/
typedef enum dhd_dbg_pkt_mon_state {
PKT_MON_INVALID = 0,
PKT_MON_ATTACHED,
PKT_MON_STARTING,
PKT_MON_STARTED,
PKT_MON_STOPPING,
PKT_MON_STOPPED,
PKT_MON_DETACHED,
} dhd_dbg_pkt_mon_state_t;
typedef struct dhd_dbg_pkt_info {
frame_type payload_type;
size_t pkt_len;
uint32 driver_ts;
uint32 firmware_ts;
uint32 pkt_hash;
void *pkt;
} dhd_dbg_pkt_info_t;
typedef struct compat_dhd_dbg_pkt_info {
frame_type payload_type;
uint32 pkt_len;
uint32 driver_ts;
uint32 firmware_ts;
uint32 pkt_hash;
void *pkt;
} compat_dhd_dbg_pkt_info_t;
typedef struct dhd_dbg_tx_info
{
wifi_tx_packet_fate fate;
dhd_dbg_pkt_info_t info;
} dhd_dbg_tx_info_t;
typedef struct dhd_dbg_rx_info
{
wifi_rx_packet_fate fate;
dhd_dbg_pkt_info_t info;
} dhd_dbg_rx_info_t;
typedef struct dhd_dbg_tx_report
{
dhd_dbg_tx_info_t *tx_pkts;
uint16 pkt_pos;
uint16 status_pos;
} dhd_dbg_tx_report_t;
typedef struct dhd_dbg_rx_report
{
dhd_dbg_rx_info_t *rx_pkts;
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_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 struct dhd_dbg_pkt_mon
{
dhd_dbg_tx_report_t *tx_report;
dhd_dbg_rx_report_t *rx_report;
dhd_dbg_pkt_mon_state_t tx_pkt_state;
dhd_dbg_pkt_mon_state_t tx_status_state;
dhd_dbg_pkt_mon_state_t rx_pkt_state;
/* call backs */
dbg_mon_tx_pkts_t tx_pkt_mon;
dbg_mon_tx_status_t tx_status_mon;
dbg_mon_rx_pkts_t rx_pkt_mon;
} dhd_dbg_pkt_mon_t;
typedef struct dhd_dbg {
dhd_dbg_ring_t dbg_rings[DEBUG_RING_ID_MAX];
void *private; /* os private_data */
dhd_dbg_pkt_mon_t pkt_mon;
void *pkt_mon_lock; /* spin lock for packet monitoring */
dbg_pullreq_t pullreq;
dbg_urgent_noti_t urgent_notifier;
} dhd_dbg_t;
#define PKT_MON_ATTACHED(state) \
(((state) > PKT_MON_INVALID) && ((state) < PKT_MON_DETACHED))
#define PKT_MON_DETACHED(state) \
(((state) == PKT_MON_INVALID) || ((state) == PKT_MON_DETACHED))
#define PKT_MON_STARTED(state) ((state) == PKT_MON_STARTED)
#define PKT_MON_STOPPED(state) ((state) == PKT_MON_STOPPED)
#define PKT_MON_NOT_OPERATIONAL(state) \
(((state) != PKT_MON_STARTED) && ((state) != PKT_MON_STOPPED))
#define PKT_MON_SAFE_TO_FREE(state) \
(((state) == PKT_MON_STARTING) || ((state) == PKT_MON_STOPPED))
#define PKT_MON_PKT_FULL(pkt_count) ((pkt_count) >= MAX_FATE_LOG_LEN)
#define PKT_MON_STATUS_FULL(pkt_count, status_count) \
(((status_count) >= (pkt_count)) || ((status_count) >= MAX_FATE_LOG_LEN))
#ifdef DBG_PKT_MON
#define DHD_DBG_PKT_MON_TX(dhdp, pkt, pktid) \
do { \
if ((dhdp) && (dhdp)->dbg && (dhdp)->dbg->pkt_mon.tx_pkt_mon && (pkt)) { \
(dhdp)->dbg->pkt_mon.tx_pkt_mon((dhdp), (pkt), (pktid)); \
} \
} while (0);
#define DHD_DBG_PKT_MON_TX_STATUS(dhdp, pkt, pktid, status) \
do { \
if ((dhdp) && (dhdp)->dbg && (dhdp)->dbg->pkt_mon.tx_status_mon && (pkt)) { \
(dhdp)->dbg->pkt_mon.tx_status_mon((dhdp), (pkt), (pktid), (status)); \
} \
} while (0);
#define DHD_DBG_PKT_MON_RX(dhdp, pkt) \
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)); \
} \
} \
} while (0);
#define DHD_DBG_PKT_MON_START(dhdp) \
dhd_os_dbg_start_pkt_monitor((dhdp));
#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_STATUS(dhdp, pkt, pktid, status)
#define DHD_DBG_PKT_MON_RX(dhdp, pkt)
#define DHD_DBG_PKT_MON_START(dhdp)
#define DHD_DBG_PKT_MON_STOP(dhdp)
#endif /* DBG_PKT_MON */
#ifdef DUMP_IOCTL_IOV_LIST
typedef struct dhd_iov_li {
dll_t list;
uint32 cmd; /* command number */
char buff[100]; /* command name */
} dhd_iov_li_t;
#endif /* DUMP_IOCTL_IOV_LIST */
#define IOV_LIST_MAX_LEN 5
#ifdef DHD_DEBUG
typedef struct {
dll_t list;
uint32 id; /* wasted chunk id */
uint32 handle; /* wasted chunk handle */
uint32 size; /* wasted chunk size */
} dhd_dbg_mwli_t;
#endif /* DHD_DEBUG */
#define DHD_OW_BI_RAW_EVENT_LOG_FMT 0xFFFF
/* LSB 2 bits of format number to identify the type of event log */
#define DHD_EVENT_LOG_HDR_MASK 0x3
#define DHD_EVENT_LOG_FMT_NUM_OFFSET 2
#define DHD_EVENT_LOG_FMT_NUM_MASK 0x3FFF
/**
* OW:- one word
* TW:- two word
* NB:- non binary
* BI:- binary
*/
#define DHD_OW_NB_EVENT_LOG_HDR 0
#define DHD_TW_NB_EVENT_LOG_HDR 1
#define DHD_BI_EVENT_LOG_HDR 3
#define DHD_INVALID_EVENT_LOG_HDR 2
#define DHD_TW_VALID_TAG_BITS_MASK 0xF
#define DHD_OW_BI_EVENT_FMT_NUM 0x3FFF
#define DHD_TW_BI_EVENT_FMT_NUM 0x3FFE
#define DHD_TW_EVENT_LOG_TAG_OFFSET 8
#define EVENT_TAG_TIMESTAMP_OFFSET 1
#define EVENT_TAG_TIMESTAMP_EXT_OFFSET 2
typedef struct prcd_event_log_hdr {
uint32 tag; /* Event_log entry tag */
uint32 count; /* Count of 4-byte entries */
uint32 fmt_num_raw; /* Format number */
uint32 fmt_num; /* Format number >> 2 */
uint32 armcycle; /* global ARM CYCLE for TAG */
uint32 *log_ptr; /* start of payload */
uint32 payload_len;
/* Extended event log header info
* 0 - legacy, 1 - extended event log header present
*/
bool ext_event_log_hdr;
bool binary_payload; /* 0 - non binary payload, 1 - binary payload */
} prcd_event_log_hdr_t; /* Processed event log header */
/* dhd_dbg functions */
extern void dhd_dbg_trace_evnt_handler(dhd_pub_t *dhdp, void *event_data,
void *raw_event_ptr, uint datalen);
void dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data,
void *raw_event_ptr, uint datalen, bool msgtrace_hdr_present,
uint32 msgtrace_seqnum);
extern int dhd_dbg_attach(dhd_pub_t *dhdp, dbg_pullreq_t os_pullreq,
dbg_urgent_noti_t os_urgent_notifier, void *os_priv);
extern void dhd_dbg_detach(dhd_pub_t *dhdp);
extern int dhd_dbg_start(dhd_pub_t *dhdp, bool start);
extern int dhd_dbg_set_configuration(dhd_pub_t *dhdp, int ring_id,
int log_level, int flags, uint32 threshold);
extern int dhd_dbg_find_ring_id(dhd_pub_t *dhdp, char *ring_name);
extern dhd_dbg_ring_t *dhd_dbg_get_ring_from_ring_id(dhd_pub_t *dhdp, int ring_id);
extern void *dhd_dbg_get_priv(dhd_pub_t *dhdp);
extern int dhd_dbg_send_urgent_evt(dhd_pub_t *dhdp, const void *data, const uint32 len);
extern void dhd_dbg_verboselog_printf(dhd_pub_t *dhdp, prcd_event_log_hdr_t *plog_hdr,
void *raw_event_ptr, uint32 *log_ptr, uint32 logset, uint16 block);
int dhd_dbg_pull_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len);
int dhd_dbg_pull_single_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len,
bool strip_header);
int dhd_dbg_push_to_ring(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_entry_t *hdr,
void *data);
int __dhd_dbg_get_ring_status(dhd_dbg_ring_t *ring, dhd_dbg_ring_status_t *ring_status);
int dhd_dbg_get_ring_status(dhd_pub_t *dhdp, int ring_id,
dhd_dbg_ring_status_t *dbg_ring_status);
#ifdef SHOW_LOGTRACE
void dhd_dbg_read_ring_into_trace_buf(dhd_dbg_ring_t *ring, trace_buf_info_t *trace_buf_info);
#endif /* SHOW_LOGTRACE */
#ifdef DBG_PKT_MON
extern int dhd_dbg_attach_pkt_monitor(dhd_pub_t *dhdp,
dbg_mon_tx_pkts_t tx_pkt_mon,
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_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_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);
extern int dhd_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf,
uint16 req_count, uint16 *resp_count);
extern int dhd_dbg_detach_pkt_monitor(dhd_pub_t *dhdp);
#endif /* DBG_PKT_MON */
extern bool dhd_dbg_process_tx_status(dhd_pub_t *dhdp, void *pkt,
uint32 pktid, uint16 status);
/* os wrapper function */
extern int dhd_os_dbg_attach(dhd_pub_t *dhdp);
extern void dhd_os_dbg_detach(dhd_pub_t *dhdp);
extern int dhd_os_dbg_register_callback(int ring_id,
void (*dbg_ring_sub_cb)(void *ctx, const int ring_id, const void *data,
const uint32 len, const dhd_dbg_ring_status_t dbg_ring_status));
extern int dhd_os_dbg_register_urgent_notifier(dhd_pub_t *dhdp,
void (*urgent_noti)(void *ctx, const void *data, const uint32 len, const uint32 fw_len));
extern int dhd_os_start_logging(dhd_pub_t *dhdp, char *ring_name, int log_level,
int flags, int time_intval, int threshold);
extern int dhd_os_reset_logging(dhd_pub_t *dhdp);
extern int dhd_os_suppress_logging(dhd_pub_t *dhdp, bool suppress);
extern int dhd_os_get_ring_status(dhd_pub_t *dhdp, int ring_id,
dhd_dbg_ring_status_t *dbg_ring_status);
extern int dhd_os_trigger_get_ring_data(dhd_pub_t *dhdp, char *ring_name);
extern int dhd_os_push_push_ring_data(dhd_pub_t *dhdp, int ring_id, void *data, int32 data_len);
extern int dhd_os_dbg_get_feature(dhd_pub_t *dhdp, int32 *features);
#ifdef DBG_PKT_MON
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);
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_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);
extern int dhd_os_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp,
void __user *user_buf, uint16 req_count, uint16 *resp_count);
extern int dhd_os_dbg_detach_pkt_monitor(dhd_pub_t *dhdp);
#endif /* DBG_PKT_MON */
#ifdef DUMP_IOCTL_IOV_LIST
extern void dhd_iov_li_append(dhd_pub_t *dhd, dll_t *list_head, dll_t *node);
extern void dhd_iov_li_print(dll_t *list_head);
extern void dhd_iov_li_delete(dhd_pub_t *dhd, dll_t *list_head);
#endif /* DUMP_IOCTL_IOV_LIST */
#ifdef DHD_DEBUG
extern void dhd_mw_list_delete(dhd_pub_t *dhd, dll_t *list_head);
#endif /* DHD_DEBUG */
#endif /* _dhd_debug_h_ */

View File

@@ -0,0 +1,512 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* DHD debugability Linux os layer
*
* <<Broadcom-WL-IPTag/Open:>>
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: dhd_debug_linux.c 769272 2018-06-25 09:23:27Z $
*/
#include <typedefs.h>
#include <osl.h>
#include <bcmutils.h>
#include <bcmendian.h>
#include <dngl_stats.h>
#include <dhd.h>
#include <dhd_dbg.h>
#include <dhd_debug.h>
#include <net/cfg80211.h>
#include <wl_cfgvendor.h>
typedef void (*dbg_ring_send_sub_t)(void *ctx, const int ring_id, const void *data,
const uint32 len, const dhd_dbg_ring_status_t ring_status);
typedef void (*dbg_urgent_noti_sub_t)(void *ctx, const void *data,
const uint32 len, const uint32 fw_len);
static dbg_ring_send_sub_t ring_send_sub_cb[DEBUG_RING_ID_MAX];
static dbg_urgent_noti_sub_t urgent_noti_sub_cb;
typedef struct dhd_dbg_os_ring_info {
dhd_pub_t *dhdp;
int ring_id;
int log_level;
unsigned long interval;
struct delayed_work work;
uint64 tsoffset;
} linux_dbgring_info_t;
struct log_level_table dhd_event_map[] = {
{1, WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED, "DRIVER EAPOL TX REQ"},
{1, WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED, "DRIVER EAPOL RX"},
{2, WIFI_EVENT_DRIVER_SCAN_REQUESTED, "SCAN_REQUESTED"},
{2, WIFI_EVENT_DRIVER_SCAN_COMPLETE, "SCAN COMPELETE"},
{3, WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND, "SCAN RESULT FOUND"},
{2, WIFI_EVENT_DRIVER_PNO_ADD, "PNO ADD"},
{2, WIFI_EVENT_DRIVER_PNO_REMOVE, "PNO REMOVE"},
{2, WIFI_EVENT_DRIVER_PNO_NETWORK_FOUND, "PNO NETWORK FOUND"},
{2, WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED, "PNO SCAN_REQUESTED"},
{1, WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND, "PNO SCAN RESULT FOUND"},
{1, WIFI_EVENT_DRIVER_PNO_SCAN_COMPLETE, "PNO SCAN COMPELETE"}
};
static void
debug_data_send(dhd_pub_t *dhdp, int ring_id, const void *data, const uint32 len,
const dhd_dbg_ring_status_t ring_status)
{
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))
return;
if (ring_send_sub_cb[ring_id]) {
ring_sub_send = ring_send_sub_cb[ring_id];
ring_sub_send(ndev, ring_id, data, len, ring_status);
}
}
static void
dhd_os_dbg_urgent_notifier(dhd_pub_t *dhdp, const void *data, const uint32 len)
{
struct net_device *ndev;
ndev = dhd_linux_get_primary_netdev(dhdp);
if (!ndev)
return;
if (urgent_noti_sub_cb) {
urgent_noti_sub_cb(ndev, data, len, dhdp->soc_ram_length);
}
}
static void
dbg_ring_poll_worker(struct work_struct *work)
{
struct delayed_work *d_work = to_delayed_work(work);
bool sched = TRUE;
dhd_dbg_ring_t *ring;
#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif // endif
linux_dbgring_info_t *ring_info =
container_of(d_work, linux_dbgring_info_t, work);
#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
#pragma GCC diagnostic pop
#endif // endif
dhd_pub_t *dhdp = ring_info->dhdp;
int ringid = ring_info->ring_id;
dhd_dbg_ring_status_t ring_status;
void *buf;
dhd_dbg_ring_entry_t *hdr;
uint32 buflen, rlen;
unsigned long flags;
ring = &dhdp->dbg->dbg_rings[ringid];
DHD_DBG_RING_LOCK(ring->lock, flags);
dhd_dbg_get_ring_status(dhdp, ringid, &ring_status);
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;
}
if (buflen > ring->ring_size) {
goto exit;
}
buf = MALLOCZ(dhdp->osh, buflen);
if (!buf) {
DHD_ERROR(("%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);
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);
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);
}
}
DHD_DBG_RING_UNLOCK(ring->lock, flags);
return;
}
int
dhd_os_dbg_register_callback(int ring_id, dbg_ring_send_sub_t callback)
{
if (!VALID_RING(ring_id))
return BCME_RANGE;
ring_send_sub_cb[ring_id] = callback;
return BCME_OK;
}
int
dhd_os_dbg_register_urgent_notifier(dhd_pub_t *dhdp, dbg_urgent_noti_sub_t urgent_noti_sub)
{
if (!dhdp || !urgent_noti_sub)
return BCME_BADARG;
urgent_noti_sub_cb = urgent_noti_sub;
return BCME_OK;
}
int
dhd_os_start_logging(dhd_pub_t *dhdp, char *ring_name, int log_level,
int flags, int time_intval, int threshold)
{
int ret = BCME_OK;
int ring_id;
linux_dbgring_info_t *os_priv, *ring_info;
ring_id = dhd_dbg_find_ring_id(dhdp, ring_name);
if (!VALID_RING(ring_id))
return BCME_UNSUPPORTED;
DHD_DBGIF(("%s , log_level : %d, time_intval : %d, threshod %d Bytes\n",
__FUNCTION__, log_level, time_intval, threshold));
/* change the configuration */
ret = dhd_dbg_set_configuration(dhdp, ring_id, log_level, flags, threshold);
if (ret) {
DHD_ERROR(("dhd_set_configuration is failed : %d\n", ret));
return ret;
}
os_priv = dhd_dbg_get_priv(dhdp);
if (!os_priv)
return BCME_ERROR;
ring_info = &os_priv[ring_id];
ring_info->log_level = log_level;
if (time_intval == 0 || log_level == 0) {
ring_info->interval = 0;
cancel_delayed_work_sync(&ring_info->work);
} else {
ring_info->interval = msecs_to_jiffies(time_intval * MSEC_PER_SEC);
cancel_delayed_work_sync(&ring_info->work);
schedule_delayed_work(&ring_info->work, ring_info->interval);
}
return ret;
}
int
dhd_os_reset_logging(dhd_pub_t *dhdp)
{
int ret = BCME_OK;
int ring_id;
linux_dbgring_info_t *os_priv, *ring_info;
os_priv = dhd_dbg_get_priv(dhdp);
if (!os_priv)
return BCME_ERROR;
/* Stop all rings */
for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
DHD_DBGIF(("%s: Stop ring buffer %d\n", __FUNCTION__, ring_id));
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;
/* change the configuration */
ret = dhd_dbg_set_configuration(dhdp, ring_id, 0, 0, 0);
if (ret) {
DHD_ERROR(("dhd_set_configuration is failed : %d\n", ret));
return ret;
}
}
return ret;
}
#define SUPPRESS_LOG_LEVEL 1
int
dhd_os_suppress_logging(dhd_pub_t *dhdp, bool suppress)
{
int ret = BCME_OK;
int max_log_level;
int enable = (suppress) ? 0 : 1;
linux_dbgring_info_t *os_priv;
os_priv = dhd_dbg_get_priv(dhdp);
if (!os_priv)
return BCME_ERROR;
max_log_level = os_priv[FW_VERBOSE_RING_ID].log_level;
if (max_log_level == SUPPRESS_LOG_LEVEL) {
/* suppress the logging in FW not to wake up host while device in suspend mode */
ret = dhd_iovar(dhdp, 0, "logtrace", (char *)&enable, sizeof(enable), NULL, 0,
TRUE);
if (ret < 0 && (ret != BCME_UNSUPPORTED)) {
DHD_ERROR(("logtrace is failed : %d\n", ret));
}
}
return ret;
}
int
dhd_os_get_ring_status(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_status_t *dbg_ring_status)
{
return dhd_dbg_get_ring_status(dhdp, ring_id, dbg_ring_status);
}
int
dhd_os_trigger_get_ring_data(dhd_pub_t *dhdp, char *ring_name)
{
int ret = BCME_OK;
int ring_id;
linux_dbgring_info_t *os_priv, *ring_info;
ring_id = dhd_dbg_find_ring_id(dhdp, ring_name);
if (!VALID_RING(ring_id))
return BCME_UNSUPPORTED;
os_priv = dhd_dbg_get_priv(dhdp);
if (os_priv) {
ring_info = &os_priv[ring_id];
if (ring_info->interval) {
cancel_delayed_work_sync(&ring_info->work);
}
schedule_delayed_work(&ring_info->work, 0);
} else {
DHD_ERROR(("%s : os_priv is NULL\n", __FUNCTION__));
ret = BCME_ERROR;
}
return ret;
}
int
dhd_os_push_push_ring_data(dhd_pub_t *dhdp, int ring_id, void *data, int32 data_len)
{
int ret = BCME_OK, i;
dhd_dbg_ring_entry_t msg_hdr;
log_conn_event_t *event_data = (log_conn_event_t *)data;
linux_dbgring_info_t *os_priv, *ring_info = NULL;
if (!VALID_RING(ring_id))
return BCME_UNSUPPORTED;
os_priv = dhd_dbg_get_priv(dhdp);
if (os_priv) {
ring_info = &os_priv[ring_id];
} else
return BCME_NORESOURCE;
memset(&msg_hdr, 0, sizeof(dhd_dbg_ring_entry_t));
if (ring_id == DHD_EVENT_RING_ID) {
msg_hdr.type = DBG_RING_ENTRY_EVENT_TYPE;
msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_TIMESTAMP;
msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_BINARY;
msg_hdr.timestamp = local_clock();
/* convert to ms */
msg_hdr.timestamp = DIV_U64_BY_U32(msg_hdr.timestamp, NSEC_PER_MSEC);
msg_hdr.len = data_len;
/* filter the event for higher log level with current log level */
for (i = 0; i < ARRAYSIZE(dhd_event_map); i++) {
if ((dhd_event_map[i].tag == event_data->event) &&
dhd_event_map[i].log_level > ring_info->log_level) {
return ret;
}
}
}
ret = dhd_dbg_push_to_ring(dhdp, ring_id, &msg_hdr, event_data);
if (ret) {
DHD_ERROR(("%s : failed to push data into the ring (%d) with ret(%d)\n",
__FUNCTION__, ring_id, ret));
}
return ret;
}
#ifdef DBG_PKT_MON
int
dhd_os_dbg_attach_pkt_monitor(dhd_pub_t *dhdp)
{
return dhd_dbg_attach_pkt_monitor(dhdp, dhd_os_dbg_monitor_tx_pkts,
dhd_os_dbg_monitor_tx_status, dhd_os_dbg_monitor_rx_pkts);
}
int
dhd_os_dbg_start_pkt_monitor(dhd_pub_t *dhdp)
{
return dhd_dbg_start_pkt_monitor(dhdp);
}
int
dhd_os_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid)
{
return dhd_dbg_monitor_tx_pkts(dhdp, pkt, pktid);
}
int
dhd_os_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid,
uint16 status)
{
return dhd_dbg_monitor_tx_status(dhdp, pkt, pktid, status);
}
int
dhd_os_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt)
{
return dhd_dbg_monitor_rx_pkts(dhdp, pkt);
}
int
dhd_os_dbg_stop_pkt_monitor(dhd_pub_t *dhdp)
{
return dhd_dbg_stop_pkt_monitor(dhdp);
}
int
dhd_os_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf,
uint16 req_count, uint16 *resp_count)
{
return dhd_dbg_monitor_get_tx_pkts(dhdp, user_buf, req_count, resp_count);
}
int
dhd_os_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf,
uint16 req_count, uint16 *resp_count)
{
return dhd_dbg_monitor_get_rx_pkts(dhdp, user_buf, req_count, resp_count);
}
int
dhd_os_dbg_detach_pkt_monitor(dhd_pub_t *dhdp)
{
return dhd_dbg_detach_pkt_monitor(dhdp);
}
#endif /* DBG_PKT_MON */
int
dhd_os_dbg_get_feature(dhd_pub_t *dhdp, int32 *features)
{
int ret = BCME_OK;
*features = 0;
#ifdef DEBUGABILITY
*features |= DBG_MEMORY_DUMP_SUPPORTED;
if (FW_SUPPORTED(dhdp, logtrace)) {
*features |= DBG_CONNECT_EVENT_SUPPORTED;
*features |= DBG_VERBOSE_LOG_SUPPORTED;
}
if (FW_SUPPORTED(dhdp, hchk)) {
*features |= DBG_HEALTH_CHECK_SUPPORTED;
}
#ifdef DBG_PKT_MON
if (FW_SUPPORTED(dhdp, d11status)) {
*features |= DBG_PACKET_FATE_SUPPORTED;
}
#endif /* DBG_PKT_MON */
#endif /* DEBUGABILITY */
return ret;
}
static void
dhd_os_dbg_pullreq(void *os_priv, int ring_id)
{
linux_dbgring_info_t *ring_info;
ring_info = &((linux_dbgring_info_t *)os_priv)[ring_id];
cancel_delayed_work(&ring_info->work);
schedule_delayed_work(&ring_info->work, 0);
}
int
dhd_os_dbg_attach(dhd_pub_t *dhdp)
{
int ret = BCME_OK;
linux_dbgring_info_t *os_priv, *ring_info;
int ring_id;
/* os_dbg data */
os_priv = MALLOCZ(dhdp->osh, sizeof(*os_priv) * DEBUG_RING_ID_MAX);
if (!os_priv)
return BCME_NOMEM;
for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX;
ring_id++) {
ring_info = &os_priv[ring_id];
INIT_DELAYED_WORK(&ring_info->work, dbg_ring_poll_worker);
ring_info->dhdp = dhdp;
ring_info->ring_id = ring_id;
}
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);
return ret;
}
void
dhd_os_dbg_detach(dhd_pub_t *dhdp)
{
linux_dbgring_info_t *os_priv, *ring_info;
int ring_id;
/* free os_dbg data */
os_priv = dhd_dbg_get_priv(dhdp);
if (!os_priv)
return;
/* abort pending any job */
for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
ring_info = &os_priv[ring_id];
if (ring_info->interval) {
ring_info->interval = 0;
cancel_delayed_work_sync(&ring_info->work);
}
}
MFREE(dhdp->osh, os_priv, sizeof(*os_priv) * DEBUG_RING_ID_MAX);
return dhd_dbg_detach(dhdp);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,289 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* @file Header file describing the flow rings DHD interfaces.
*
* Flow rings are transmit traffic (=propagating towards antenna) related entities.
*
* Provides type definitions and function prototypes used to create, delete and manage flow rings at
* high level.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_flowring.h 786596 2018-10-26 22:54:51Z $
*/
/****************
* Common types *
*/
#ifndef _dhd_flowrings_h_
#define _dhd_flowrings_h_
/* Max pkts held in a flow ring's backup queue */
#define FLOW_RING_QUEUE_THRESHOLD (2048)
/* Number of H2D common rings */
#define FLOW_RING_COMMON BCMPCIE_H2D_COMMON_MSGRINGS
#define FLOWID_INVALID (ID16_INVALID)
#define FLOWID_RESERVED (FLOW_RING_COMMON)
#define FLOW_RING_STATUS_OPEN 0
#define FLOW_RING_STATUS_CREATE_PENDING 1
#define FLOW_RING_STATUS_CLOSED 2
#define FLOW_RING_STATUS_DELETE_PENDING 3
#define FLOW_RING_STATUS_FLUSH_PENDING 4
#ifdef IDLE_TX_FLOW_MGMT
#define FLOW_RING_STATUS_SUSPENDED 5
#define FLOW_RING_STATUS_RESUME_PENDING 6
#endif /* IDLE_TX_FLOW_MGMT */
#define FLOW_RING_STATUS_STA_FREEING 7
#define DHD_FLOWRING_RX_BUFPOST_PKTSZ 2048
#define DHD_FLOWRING_RX_BUFPOST_PKTSZ_MAX 4096
#define DHD_FLOW_PRIO_AC_MAP 0
#define DHD_FLOW_PRIO_TID_MAP 1
/* Flow ring prority map for lossless roaming */
#define DHD_FLOW_PRIO_LLR_MAP 2
/* Hashing a MacAddress for lkup into a per interface flow hash table */
#define DHD_FLOWRING_HASH_SIZE 256
#define DHD_FLOWRING_HASHINDEX(ea, prio) \
((((uint8 *)(ea))[3] ^ ((uint8 *)(ea))[4] ^ ((uint8 *)(ea))[5] ^ ((uint8)(prio))) \
% DHD_FLOWRING_HASH_SIZE)
#define DHD_IF_ROLE(pub, idx) (((if_flow_lkup_t *)(pub)->if_flow_lkup)[idx].role)
#define DHD_IF_ROLE_AP(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_AP)
#define DHD_IF_ROLE_STA(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_STA)
#define DHD_IF_ROLE_P2PGC(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_P2P_CLIENT)
#define DHD_IF_ROLE_P2PGO(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_P2P_GO)
#define DHD_IF_ROLE_WDS(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_WDS)
#define DHD_IF_ROLE_IBSS(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_IBSS)
#ifdef WL_NAN
#define DHD_IF_ROLE_NAN(pub, idx) (DHD_IF_ROLE(pub, idx) == WLC_E_IF_ROLE_NAN)
#else
#define DHD_IF_ROLE_NAN(pub, idx) (FALSE)
#endif /* WL_NAN */
#define DHD_IF_ROLE_AWDL(pub, idx) (FALSE)
#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))
#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))
#define DHD_FLOW_RING(dhdp, flowid) \
(flow_ring_node_t *)&(((flow_ring_node_t *)((dhdp)->flow_ring_table))[flowid])
struct flow_queue;
/* Flow Ring Queue Enqueue overflow callback */
typedef int (*flow_queue_cb_t)(struct flow_queue * queue, void * pkt);
/**
* Each flow ring has an associated (tx flow controlled) queue. 802.3 packets are transferred
* between queue and ring. A packet from the host stack is first added to the queue, and in a later
* stage transferred to the flow ring. Packets in the queue are dhd owned, whereas packets in the
* flow ring are device owned.
*/
typedef struct flow_queue {
dll_t list; /* manage a flowring queue in a double linked list */
void * head; /* first packet in the queue */
void * tail; /* last packet in the queue */
uint16 len; /* number of packets in the queue */
uint16 max; /* maximum or min budget (used in cumm) */
uint32 threshold; /* parent's cummulative length threshold */
void * clen_ptr; /* parent's cummulative length counter */
uint32 failures; /* enqueue failures due to queue overflow */
flow_queue_cb_t cb; /* callback invoked on threshold crossing */
uint32 l2threshold; /* grandparent's (level 2) cummulative length threshold */
void * l2clen_ptr; /* grandparent's (level 2) cummulative length counter */
} flow_queue_t;
#define DHD_FLOW_QUEUE_LEN(queue) ((int)(queue)->len)
#define DHD_FLOW_QUEUE_MAX(queue) ((int)(queue)->max)
#define DHD_FLOW_QUEUE_THRESHOLD(queue) ((int)(queue)->threshold)
#define DHD_FLOW_QUEUE_L2THRESHOLD(queue) ((int)(queue)->l2threshold)
#define DHD_FLOW_QUEUE_EMPTY(queue) ((queue)->len == 0)
#define DHD_FLOW_QUEUE_FAILURES(queue) ((queue)->failures)
#define DHD_FLOW_QUEUE_AVAIL(queue) ((int)((queue)->max - (queue)->len))
#define DHD_FLOW_QUEUE_FULL(queue) ((queue)->len >= (queue)->max)
#define DHD_FLOW_QUEUE_OVFL(queue, budget) \
(((queue)->len) > budget)
#define DHD_FLOW_QUEUE_SET_MAX(queue, budget) \
((queue)->max) = ((budget) - 1)
/* Queue's cummulative threshold. */
#define DHD_FLOW_QUEUE_SET_THRESHOLD(queue, cumm_threshold) \
((queue)->threshold) = ((cumm_threshold) - 1)
/* Queue's cummulative length object accessor. */
#define DHD_FLOW_QUEUE_CLEN_PTR(queue) ((queue)->clen_ptr)
/* Set a queue's cumm_len point to a parent's cumm_ctr_t cummulative length */
#define DHD_FLOW_QUEUE_SET_CLEN(queue, parent_clen_ptr) \
((queue)->clen_ptr) = (void *)(parent_clen_ptr)
/* Queue's level 2 cummulative threshold. */
#define DHD_FLOW_QUEUE_SET_L2THRESHOLD(queue, l2cumm_threshold) \
((queue)->l2threshold) = ((l2cumm_threshold) - 1)
/* Queue's level 2 cummulative length object accessor. */
#define DHD_FLOW_QUEUE_L2CLEN_PTR(queue) ((queue)->l2clen_ptr)
/* Set a queue's level 2 cumm_len point to a grandparent's cumm_ctr_t cummulative length */
#define DHD_FLOW_QUEUE_SET_L2CLEN(queue, grandparent_clen_ptr) \
((queue)->l2clen_ptr) = (void *)(grandparent_clen_ptr)
#define DHD_FLOWRING_TXSTATUS_CNT_UPDATE(bus, flowid, txstatus)
/* Pkttag not compatible with PROP_TXSTATUS or WLFC */
typedef struct dhd_pkttag_fr {
uint16 flowid;
uint16 ifid;
#ifdef DHD_LB_TXC
int dataoff;
dmaaddr_t physaddr;
uint32 pa_len;
#endif /* DHD_LB_TXC */
} dhd_pkttag_fr_t;
#define DHD_PKTTAG_SET_IFID(tag, idx) ((tag)->ifid = (uint16)(idx))
#define DHD_PKTTAG_SET_PA(tag, pa) ((tag)->physaddr = (pa))
#define DHD_PKTTAG_SET_PA_LEN(tag, palen) ((tag)->pa_len = (palen))
#define DHD_PKTTAG_IFID(tag) ((tag)->ifid)
#define DHD_PKTTAG_PA(tag) ((tag)->physaddr)
#define DHD_PKTTAG_PA_LEN(tag) ((tag)->pa_len)
/** each flow ring is dedicated to a tid/sa/da combination */
typedef struct flow_info {
uint8 tid;
uint8 ifindex;
uchar sa[ETHER_ADDR_LEN];
uchar da[ETHER_ADDR_LEN];
#ifdef TX_STATUS_LATENCY_STATS
/* total number of tx_status received on this flowid */
uint64 num_tx_status;
/* cumulative tx_status latency for this flowid */
uint64 cum_tx_status_latency;
/* num tx packets sent on this flowring */
uint64 num_tx_pkts;
#endif /* TX_STATUS_LATENCY_STATS */
} flow_info_t;
/** a flow ring is used for outbound (towards antenna) 802.3 packets */
typedef struct flow_ring_node {
dll_t list; /* manage a constructed flowring in a dll, must be at first place */
flow_queue_t queue; /* queues packets before they enter the flow ring, flow control */
bool active;
uint8 status;
/*
* flowid: unique ID of a flow ring, which can either be unicast or broadcast/multicast. For
* unicast flow rings, the flow id accelerates ARM 802.3->802.11 header translation.
*/
uint16 flowid;
flow_info_t flow_info;
void *prot_info;
void *lock; /* lock for flowring access protection */
#ifdef IDLE_TX_FLOW_MGMT
uint64 last_active_ts; /* contains last active timestamp */
#endif /* IDLE_TX_FLOW_MGMT */
#ifdef DHD_HP2P
bool hp2p_ring;
#endif /* DHD_HP2P */
} flow_ring_node_t;
typedef flow_ring_node_t flow_ring_table_t;
typedef struct flow_hash_info {
uint16 flowid;
flow_info_t flow_info;
struct flow_hash_info *next;
} flow_hash_info_t;
typedef struct if_flow_lkup {
bool status;
uint8 role; /* Interface role: STA/AP */
flow_hash_info_t *fl_hash[DHD_FLOWRING_HASH_SIZE]; /* Lkup Hash table */
} if_flow_lkup_t;
static INLINE flow_ring_node_t *
dhd_constlist_to_flowring(dll_t *item)
{
return ((flow_ring_node_t *)item);
}
/* Exported API */
/* Flow ring's queue management functions */
extern flow_ring_node_t * dhd_flow_ring_node(dhd_pub_t *dhdp, uint16 flowid);
extern flow_queue_t * dhd_flow_queue(dhd_pub_t *dhdp, uint16 flowid);
extern void dhd_flow_queue_init(dhd_pub_t *dhdp, flow_queue_t *queue, int max);
extern void dhd_flow_queue_reinit(dhd_pub_t *dhdp, flow_queue_t *queue, int max);
extern void dhd_flow_queue_register(flow_queue_t *queue, flow_queue_cb_t cb);
extern int dhd_flow_queue_enqueue(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt);
extern void * dhd_flow_queue_dequeue(dhd_pub_t *dhdp, flow_queue_t *queue);
extern void dhd_flow_queue_reinsert(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt);
extern void dhd_flow_ring_config_thresholds(dhd_pub_t *dhdp, uint16 flowid,
int queue_budget, int cumm_threshold, void *cumm_ctr,
int l2cumm_threshold, void *l2cumm_ctr);
extern int dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_flow_rings);
extern void dhd_flow_rings_deinit(dhd_pub_t *dhdp);
extern int dhd_flowid_update(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio,
void *pktbuf);
extern int dhd_flowid_debug_create(dhd_pub_t *dhdp, uint8 ifindex,
uint8 prio, char *sa, char *da, uint16 *flowid);
extern int dhd_flowid_find_by_ifidx(dhd_pub_t *dhdp, uint8 ifidex, uint16 flowid);
extern void dhd_flowid_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid);
extern void dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex);
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,
char *addr);
/* Handle Interface ADD, DEL operations */
extern void dhd_update_interface_flow_info(dhd_pub_t *dhdp, uint8 ifindex,
uint8 op, uint8 role);
/* Handle a STA interface link status update */
extern int dhd_update_interface_link_status(dhd_pub_t *dhdp, uint8 ifindex,
uint8 status);
extern int dhd_flow_prio_map(dhd_pub_t *dhd, uint8 *map, bool set);
extern int dhd_update_flow_prio_map(dhd_pub_t *dhdp, uint8 map);
extern uint8 dhd_flow_rings_ifindex2role(dhd_pub_t *dhdp, uint8 ifindex);
#endif /* _dhd_flowrings_h_ */

View File

@@ -0,0 +1,350 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <osl.h>
#include <dhd_linux.h>
#include <linux/gpio.h>
#include <linux/rfkill-wlan.h>
#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
extern void *dhd_wlan_mem_prealloc(int section, unsigned long size);
#endif /* CONFIG_DHD_USE_STATIC_BUF */
static int gpio_wl_reg_on = -1; // WL_REG_ON is input pin of WLAN module
#ifdef CUSTOMER_OOB
static int gpio_wl_host_wake = -1; // WL_HOST_WAKE is output pin of WLAN module
#endif
static int
dhd_wlan_set_power(int on
#ifdef BUS_POWER_RESTORE
, wifi_adapter_info_t *adapter
#endif /* BUS_POWER_RESTORE */
)
{
int err = 0;
if (on) {
printf("======== PULL WL_REG_ON(%d) HIGH! ========\n", gpio_wl_reg_on);
if (gpio_wl_reg_on >= 0) {
err = gpio_direction_output(gpio_wl_reg_on, 1);
if (err) {
printf("%s: WL_REG_ON didn't output high\n", __FUNCTION__);
return -EIO;
}
}
rockchip_wifi_power(1);
#if defined(BUS_POWER_RESTORE)
#if defined(BCMSDIO) && (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);
}
#elif defined(BCMPCIE)
if (adapter->pci_dev) {
mdelay(100);
printf("======== pci_set_power_state PCI_D0! ========\n");
pci_set_power_state(adapter->pci_dev, PCI_D0);
if (adapter->pci_saved_state)
pci_load_and_free_saved_state(adapter->pci_dev, &adapter->pci_saved_state);
pci_restore_state(adapter->pci_dev);
err = pci_enable_device(adapter->pci_dev);
if (err < 0)
printf("%s: PCI enable device failed", __FUNCTION__);
pci_set_master(adapter->pci_dev);
}
#endif /* BCMPCIE */
#endif /* BUS_POWER_RESTORE */
/* Lets customer power to get stable */
mdelay(100);
} else {
#if defined(BUS_POWER_RESTORE)
#if defined(BCMSDIO) && (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);
}
#elif defined(BCMPCIE)
if (adapter->pci_dev) {
printf("======== pci_set_power_state PCI_D3hot! ========\n");
pci_save_state(adapter->pci_dev);
adapter->pci_saved_state = pci_store_saved_state(adapter->pci_dev);
if (pci_is_enabled(adapter->pci_dev))
pci_disable_device(adapter->pci_dev);
pci_set_power_state(adapter->pci_dev, PCI_D3hot);
}
#endif /* BCMPCIE */
#endif /* BUS_POWER_RESTORE */
printf("======== PULL WL_REG_ON(%d) LOW! ========\n", gpio_wl_reg_on);
if (gpio_wl_reg_on >= 0) {
err = gpio_direction_output(gpio_wl_reg_on, 0);
if (err) {
printf("%s: WL_REG_ON didn't output low\n", __FUNCTION__);
return -EIO;
}
}
rockchip_wifi_power(0);
}
return err;
}
static int dhd_wlan_set_reset(int onoff)
{
return 0;
}
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");
#ifdef CUSTOMER_HW_PLATFORM
err = sdhci_force_presence_change(&sdmmc_channel, 1);
#endif /* CUSTOMER_HW_PLATFORM */
rockchip_wifi_set_carddetect(1);
#elif defined(BCMPCIE)
printf("======== Card detection to detect PCIE card! ========\n");
#endif
} else {
#if defined(BCMSDIO)
printf("======== Card detection to remove SDIO card! ========\n");
#ifdef CUSTOMER_HW_PLATFORM
err = sdhci_force_presence_change(&sdmmc_channel, 0);
#endif /* CUSTOMER_HW_PLATFORM */
rockchip_wifi_set_carddetect(0);
#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
#ifdef CUSTOM_MULTI_MAC
, char *name
#endif
)
{
int err = 0;
#ifdef CUSTOM_MULTI_MAC
if (!strcmp("wlan1", name)) {
#ifdef EXAMPLE_GET_MAC
struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}};
bcopy((char *)&ea_example, buf, sizeof(struct ether_addr));
#endif /* EXAMPLE_GET_MAC */
} else
#endif /* CUSTOM_MULTI_MAC */
{
#ifdef EXAMPLE_GET_MAC
struct ether_addr ea_example = {{0x02, 0x11, 0x22, 0x33, 0x44, 0x55}};
bcopy((char *)&ea_example, buf, sizeof(struct ether_addr));
#endif /* EXAMPLE_GET_MAC */
}
#ifdef EXAMPLE_GET_MAC_VER2
/* EXAMPLE code */
{
char macpad[56]= {
0x00,0xaa,0x9c,0x84,0xc7,0xbc,0x9b,0xf6,
0x02,0x33,0xa9,0x4d,0x5c,0xb4,0x0a,0x5d,
0xa8,0xef,0xb0,0xcf,0x8e,0xbf,0x24,0x8a,
0x87,0x0f,0x6f,0x0d,0xeb,0x83,0x6a,0x70,
0x4a,0xeb,0xf6,0xe6,0x3c,0xe7,0x5f,0xfc,
0x0e,0xa7,0xb3,0x0f,0x00,0xe4,0x4a,0xaf,
0x87,0x08,0x16,0x6d,0x3a,0xe3,0xc7,0x80};
bcopy(macpad, buf+6, sizeof(macpad));
}
#endif /* EXAMPLE_GET_MAC_VER2 */
printf("======== %s err=%d ========\n", __FUNCTION__, err);
return err;
}
static struct cntry_locales_custom brcm_wlan_translate_custom_table[] = {
/* Table should be filled out based on custom platform regulatory requirement */
#ifdef EXAMPLE_TABLE
{"", "XT", 49}, /* Universal if Country code is unknown or empty */
{"US", "US", 0},
#endif /* EXMAPLE_TABLE */
};
#ifdef CUSTOM_FORCE_NODFS_FLAG
struct cntry_locales_custom brcm_wlan_translate_nodfs_table[] = {
#ifdef EXAMPLE_TABLE
{"", "XT", 50}, /* Universal if Country code is unknown or empty */
{"US", "US", 0},
#endif /* EXMAPLE_TABLE */
};
#endif
static void *dhd_wlan_get_country_code(char *ccode
#ifdef CUSTOM_FORCE_NODFS_FLAG
, u32 flags
#endif
)
{
struct cntry_locales_custom *locales;
int size;
int i;
if (!ccode)
return NULL;
#ifdef CUSTOM_FORCE_NODFS_FLAG
if (flags & WLAN_PLAT_NODFS_FLAG) {
locales = brcm_wlan_translate_nodfs_table;
size = ARRAY_SIZE(brcm_wlan_translate_nodfs_table);
} else {
#endif
locales = brcm_wlan_translate_custom_table;
size = ARRAY_SIZE(brcm_wlan_translate_custom_table);
#ifdef CUSTOM_FORCE_NODFS_FLAG
}
#endif
for (i = 0; i < size; i++)
if (strcmp(ccode, locales[i].iso_abbrev) == 0)
return &locales[i];
return NULL;
}
struct resource dhd_wlan_resources[] = {
[0] = {
.name = "bcmdhd_wlan_irq",
.start = 0, /* Dummy */
.end = 0, /* Dummy */
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE
| IORESOURCE_IRQ_HIGHLEVEL, /* Dummy */
},
};
struct wifi_platform_data dhd_wlan_control = {
.set_power = dhd_wlan_set_power,
.set_reset = dhd_wlan_set_reset,
.set_carddetect = dhd_wlan_set_carddetect,
.get_mac_addr = dhd_wlan_get_mac_addr,
#ifdef CONFIG_DHD_USE_STATIC_BUF
.mem_prealloc = dhd_wlan_mem_prealloc,
#endif /* CONFIG_DHD_USE_STATIC_BUF */
.get_country_code = dhd_wlan_get_country_code,
};
int dhd_wlan_init_gpio(void)
{
int err = 0;
#ifdef CUSTOMER_OOB
int host_oob_irq = -1;
uint host_oob_irq_flags = 0;
int irq_flags = -1;
#endif
/* Please check your schematic and fill right GPIO number which connected to
* WL_REG_ON and WL_HOST_WAKE.
*/
gpio_wl_reg_on = -1;
#ifdef CUSTOMER_OOB
gpio_wl_host_wake = -1;
#endif
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);
gpio_wl_reg_on = -1;
}
}
#ifdef CUSTOMER_OOB
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);
return -1;
}
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);
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);
gpio_free(gpio_wl_host_wake);
return -1;
}
}
host_oob_irq = rockchip_wifi_get_oob_irq();
#ifdef HW_OOB
host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE;
irq_flags = rockchip_wifi_get_oob_irq_flag();
if (irq_flags == 1)
host_oob_irq_flags |= IORESOURCE_IRQ_HIGHLEVEL;
else if (irq_flags == 0)
host_oob_irq_flags |= IORESOURCE_IRQ_LOWLEVEL;
else
pr_warn("%s: unknown oob irqflags !\n", __func__);
#else
host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE | IORESOURCE_IRQ_SHAREABLE;
#endif
dhd_wlan_resources[0].start = dhd_wlan_resources[0].end = host_oob_irq;
dhd_wlan_resources[0].flags = host_oob_irq_flags;
printf("%s: WL_HOST_WAKE=%d, oob_irq=%d, oob_irq_flags=0x%x\n", __FUNCTION__,
gpio_wl_host_wake, host_oob_irq, host_oob_irq_flags);
#endif /* CUSTOMER_OOB */
printf("%s: WL_REG_ON=%d\n", __FUNCTION__, gpio_wl_reg_on);
return 0;
}
static void dhd_wlan_deinit_gpio(void)
{
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;
}
#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;
}
#endif /* CUSTOMER_OOB */
}
int dhd_wlan_init_plat_data(void)
{
int err = 0;
printf("======== %s ========\n", __FUNCTION__);
err = dhd_wlan_init_gpio();
return err;
}
void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter)
{
printf("======== %s ========\n", __FUNCTION__);
dhd_wlan_deinit_gpio();
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,97 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Header file describing the common ip parser function.
*
* Provides type definitions and function prototypes used to parse ip packet.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_ip.h 790572 2018-11-26 11:03:46Z $
*/
#ifndef _dhd_ip_h_
#define _dhd_ip_h_
#if defined(DHDTCPACK_SUPPRESS) || defined(DHDTCPSYNC_FLOOD_BLK)
#include <dngl_stats.h>
#include <bcmutils.h>
#include <dhd.h>
#endif /* DHDTCPACK_SUPPRESS || DHDTCPSYNC_FLOOD_BLK */
typedef enum pkt_frag
{
DHD_PKT_FRAG_NONE = 0,
DHD_PKT_FRAG_FIRST,
DHD_PKT_FRAG_CONT,
DHD_PKT_FRAG_LAST
} pkt_frag_t;
extern pkt_frag_t pkt_frag_info(osl_t *osh, void *p);
#ifdef DHDTCPSYNC_FLOOD_BLK
typedef enum tcp_hdr_flags {
FLAG_SYNC,
FLAG_SYNCACK,
FLAG_RST,
FLAG_OTHERS
} tcp_hdr_flag_t;
extern tcp_hdr_flag_t dhd_tcpdata_get_flag(dhd_pub_t *dhdp, void *pkt);
#endif /* DHDTCPSYNC_FLOOD_BLK */
#ifdef DHDTCPACK_SUPPRESS
#define TCPACKSZMIN (ETHER_HDR_LEN + IPV4_MIN_HEADER_LEN + TCP_MIN_HEADER_LEN)
/* Size of MAX possible TCP ACK packet. Extra bytes for IP/TCP option fields */
#define TCPACKSZMAX (TCPACKSZMIN + 100)
/* Max number of TCP streams that have own src/dst IP addrs and TCP ports */
#define TCPACK_INFO_MAXNUM 4
#define TCPDATA_INFO_MAXNUM 4
#define TCPDATA_PSH_INFO_MAXNUM (8 * TCPDATA_INFO_MAXNUM)
#define TCPDATA_INFO_TIMEOUT 5000 /* Remove tcpdata_info if inactive for this time (in ms) */
#define DEFAULT_TCPACK_SUPP_RATIO 3
#ifndef CUSTOM_TCPACK_SUPP_RATIO
#define CUSTOM_TCPACK_SUPP_RATIO DEFAULT_TCPACK_SUPP_RATIO
#endif /* CUSTOM_TCPACK_SUPP_RATIO */
#define DEFAULT_TCPACK_DELAY_TIME 10 /* ms */
#ifndef CUSTOM_TCPACK_DELAY_TIME
#define CUSTOM_TCPACK_DELAY_TIME DEFAULT_TCPACK_DELAY_TIME
#endif /* CUSTOM_TCPACK_DELAY_TIME */
extern int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 on);
extern void dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp);
extern int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt);
extern bool dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt);
extern bool dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt);
extern bool dhd_tcpack_hold(dhd_pub_t *dhdp, void *pkt, int ifidx);
/* #define DHDTCPACK_SUP_DBG */
#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG)
extern counter_tbl_t tack_tbl;
#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */
#endif /* DHDTCPACK_SUPPRESS */
#endif /* _dhd_ip_h_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,450 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* DHD Linux header file (dhd_linux exports for cfg80211 and other components)
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_linux.h 816392 2019-04-24 14:39:02Z $
*/
/* wifi platform functions for power, interrupt and pre-alloc, either
* from Android-like platform device data, or Broadcom wifi platform
* device data.
*
*/
#ifndef __DHD_LINUX_H__
#define __DHD_LINUX_H__
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <dngl_stats.h>
#include <dhd.h>
/* Linux wireless extension support */
#if defined(WL_WIRELESS_EXT)
#include <wl_iw.h>
#endif /* defined(WL_WIRELESS_EXT) */
#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
#include <linux/earlysuspend.h>
#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */
#ifdef PCIE_FULL_DONGLE
#include <etd.h>
#endif /* PCIE_FULL_DONGLE */
#ifdef WL_MONITOR
#include <bcmmsgbuf.h>
#define MAX_RADIOTAP_SIZE 256 /* Maximum size to hold HE Radiotap header format */
#define MAX_MON_PKT_SIZE (4096 + MAX_RADIOTAP_SIZE)
#endif /* WL_MONITOR */
#define FILE_DUMP_MAX_WAIT_TIME 4000
#define htod32(i) (i)
#define htod16(i) (i)
#define dtoh32(i) (i)
#define dtoh16(i) (i)
#define htodchanspec(i) (i)
#define dtohchanspec(i) (i)
#ifdef BLOCK_IPV6_PACKET
#define HEX_PREF_STR "0x"
#define UNI_FILTER_STR "010000000000"
#define ZERO_ADDR_STR "000000000000"
#define ETHER_TYPE_STR "0000"
#define IPV6_FILTER_STR "20"
#define ZERO_TYPE_STR "00"
#endif /* BLOCK_IPV6_PACKET */
typedef struct dhd_if_event {
struct list_head list;
wl_event_data_if_t event;
char name[IFNAMSIZ+1];
uint8 mac[ETHER_ADDR_LEN];
} dhd_if_event_t;
/* Interface control information */
typedef struct dhd_if {
struct dhd_info *info; /* back pointer to dhd_info */
/* OS/stack specifics */
struct net_device *net;
int idx; /* iface idx in dongle */
uint subunit; /* subunit */
uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */
bool set_macaddress;
bool set_multicast;
uint8 bssidx; /* bsscfg index for the interface */
bool attached; /* Delayed attachment when unset */
bool txflowcontrol; /* Per interface flow control indicator */
char name[IFNAMSIZ+1]; /* linux interface name */
char dngl_name[IFNAMSIZ+1]; /* corresponding dongle interface name */
struct net_device_stats stats;
#ifdef PCIE_FULL_DONGLE
struct list_head sta_list; /* sll of associated stations */
spinlock_t sta_list_lock; /* lock for manipulating sll */
#endif /* PCIE_FULL_DONGLE */
uint32 ap_isolate; /* ap-isolation settings */
#ifdef DHD_L2_FILTER
bool parp_enable;
bool parp_discard;
bool parp_allnode;
arp_table_t *phnd_arp_table;
/* for Per BSS modification */
bool dhcp_unicast;
bool block_ping;
bool grat_arp;
bool block_tdls;
#endif /* DHD_L2_FILTER */
#ifdef DHD_MCAST_REGEN
bool mcast_regen_bss_enable;
#endif // endif
bool rx_pkt_chainable; /* set all rx packet to chainable config by default */
cumm_ctr_t cumm_ctr; /* cummulative queue length of child flowrings */
uint8 tx_paths_active;
bool del_in_progress;
bool static_if; /* used to avoid some operations on static_if */
#ifdef DHD_4WAYM4_FAIL_DISCONNECT
struct delayed_work m4state_work;
atomic_t m4state;
#endif /* DHD_4WAYM4_FAIL_DISCONNECT */
#ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
bool recv_reassoc_evt;
bool post_roam_evt;
#endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
#ifdef DHDTCPSYNC_FLOOD_BLK
uint32 tsync_rcvd;
uint32 tsyncack_txed;
u64 last_sync;
struct work_struct blk_tsfl_work;
#endif /* DHDTCPSYNC_FLOOD_BLK */
} dhd_if_t;
struct ipv6_work_info_t {
uint8 if_idx;
char ipv6_addr[IPV6_ADDR_LEN];
unsigned long event;
};
typedef struct dhd_dump {
uint8 *buf;
int bufsize;
uint8 *hscb_buf;
int hscb_bufsize;
} dhd_dump_t;
#ifdef DNGL_AXI_ERROR_LOGGING
typedef struct dhd_axi_error_dump {
ulong fault_address;
uint32 axid;
struct hnd_ext_trap_axi_error_v1 etd_axi_error_v1;
} dhd_axi_error_dump_t;
#endif /* DNGL_AXI_ERROR_LOGGING */
#ifdef DHD_PCIE_NATIVE_RUNTIMEPM
struct dhd_rx_tx_work {
struct work_struct work;
struct sk_buff *skb;
struct net_device *net;
struct dhd_pub *pub;
};
#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
#if defined(DHD_LB)
#if !defined(PCIE_FULL_DONGLE)
#error "DHD Loadbalancing only supported on PCIE_FULL_DONGLE"
#endif /* !PCIE_FULL_DONGLE */
#endif /* DHD_LB */
#if defined(DHD_LB_RXP) || defined(DHD_LB_RXC) || defined(DHD_LB_TXC) || \
defined(DHD_LB_STATS)
#if !defined(DHD_LB)
#error "DHD loadbalance derivatives are supported only if DHD_LB is defined"
#endif /* !DHD_LB */
#endif /* DHD_LB_RXP || DHD_LB_RXC || DHD_LB_TXC || DHD_LB_STATS */
#if defined(DHD_LB)
/* Dynamic CPU selection for load balancing */
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/notifier.h>
#include <linux/workqueue.h>
#include <asm/atomic.h>
#if !defined(DHD_LB_PRIMARY_CPUS)
#define DHD_LB_PRIMARY_CPUS 0x0 /* Big CPU coreids mask */
#endif // endif
#if !defined(DHD_LB_SECONDARY_CPUS)
#define DHD_LB_SECONDARY_CPUS 0xFE /* Little CPU coreids mask */
#endif // endif
#define HIST_BIN_SIZE 9
#if defined(DHD_LB_TXP)
/* Pkttag not compatible with PROP_TXSTATUS or WLFC */
typedef struct dhd_tx_lb_pkttag_fr {
struct net_device *net;
int ifidx;
} dhd_tx_lb_pkttag_fr_t;
#define DHD_LB_TX_PKTTAG_SET_NETDEV(tag, netdevp) ((tag)->net = netdevp)
#define DHD_LB_TX_PKTTAG_NETDEV(tag) ((tag)->net)
#define DHD_LB_TX_PKTTAG_SET_IFIDX(tag, ifidx) ((tag)->ifidx = ifidx)
#define DHD_LB_TX_PKTTAG_IFIDX(tag) ((tag)->ifidx)
#endif /* DHD_LB_TXP */
#endif /* DHD_LB */
#ifdef FILTER_IE
#define FILTER_IE_PATH "/etc/wifi/filter_ie"
#define FILTER_IE_BUFSZ 1024 /* ioc buffsize for FILTER_IE */
#define FILE_BLOCK_READ_SIZE 256
#define WL_FILTER_IE_IOV_HDR_SIZE OFFSETOF(wl_filter_ie_iov_v1_t, tlvs)
#endif /* FILTER_IE */
#define NULL_CHECK(p, s, err) \
do { \
if (!(p)) { \
printk("NULL POINTER (%s) : %s\n", __FUNCTION__, (s)); \
err = BCME_ERROR; \
return err; \
} \
} while (0)
/* dongle status */
enum wifi_adapter_status {
WIFI_STATUS_POWER_ON = 0,
WIFI_STATUS_ATTACH,
WIFI_STATUS_FW_READY,
WIFI_STATUS_DETTACH
};
#define wifi_chk_adapter_status(adapter, stat) (test_bit(stat, &(adapter)->status))
#define wifi_get_adapter_status(adapter, stat) (test_bit(stat, &(adapter)->status))
#define wifi_set_adapter_status(adapter, stat) (set_bit(stat, &(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))
#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 */
typedef struct wifi_adapter_info {
const char *name;
uint irq_num;
uint intr_flags;
const char *fw_path;
const char *nv_path;
const char *clm_path;
const char *conf_path;
void *wifi_plat_data; /* wifi ctrl func, for backward compatibility */
uint bus_type;
uint bus_num;
uint slot_num;
wait_queue_head_t status_event;
unsigned long status;
#if defined(BT_OVER_SDIO)
const char *btfw_path;
#endif /* defined (BT_OVER_SDIO) */
#ifdef BUS_POWER_RESTORE
#if defined(BCMSDIO)
struct sdio_func *sdio_func;
#endif /* BCMSDIO */
#if defined(BCMPCIE)
struct pci_dev *pci_dev;
struct pci_saved_state *pci_saved_state;
#endif /* BCMPCIE */
#endif
} wifi_adapter_info_t;
#define WLAN_PLAT_NODFS_FLAG 0x01
#define WLAN_PLAT_AP_FLAG 0x02
#if !defined(CONFIG_WIFI_CONTROL_FUNC)
struct wifi_platform_data {
#ifdef BUS_POWER_RESTORE
int (*set_power)(int val, wifi_adapter_info_t *adapter);
#else
int (*set_power)(int val);
#endif
int (*set_reset)(int val);
int (*set_carddetect)(int val);
void *(*mem_prealloc)(int section, unsigned long size);
#ifdef CUSTOM_MULTI_MAC
int (*get_mac_addr)(unsigned char *buf, char *name);
#else
int (*get_mac_addr)(unsigned char *buf);
#endif
#ifdef BCMSDIO
int (*get_wake_irq)(void);
#endif // endif
#ifdef CUSTOM_FORCE_NODFS_FLAG
void *(*get_country_code)(char *ccode, u32 flags);
#else /* defined (CUSTOM_FORCE_NODFS_FLAG) */
void *(*get_country_code)(char *ccode);
#endif
};
#endif
typedef struct bcmdhd_wifi_platdata {
uint num_adapters;
wifi_adapter_info_t *adapters;
} bcmdhd_wifi_platdata_t;
/** Per STA params. A list of dhd_sta objects are managed in dhd_if */
typedef struct dhd_sta {
cumm_ctr_t cumm_ctr; /* cummulative queue length of child flowrings */
uint16 flowid[NUMPRIO]; /* allocated flow ring ids (by priority) */
void * ifp; /* associated dhd_if */
struct ether_addr ea; /* stations ethernet mac address */
struct list_head list; /* link into dhd_if::sta_list */
int idx; /* index of self in dhd_pub::sta_pool[] */
int ifidx; /* index of interface in dhd */
} dhd_sta_t;
typedef dhd_sta_t dhd_sta_pool_t;
#ifdef DHD_4WAYM4_FAIL_DISCONNECT
typedef enum {
M3_RXED,
M4_TXFAILED
} msg_4way_state_t;
#define MAX_4WAY_TIMEOUT_MS 2000
#endif /* DHD_4WAYM4_FAIL_DISCONNECT */
#ifdef DHD_SEND_HANG_PRIVCMD_ERRORS
extern uint32 report_hang_privcmd_err;
#endif /* DHD_SEND_HANG_PRIVCMD_ERRORS */
#if defined(ARGOS_NOTIFY_CB)
int argos_register_notifier_init(struct net_device *net);
int argos_register_notifier_deinit(void);
extern int sec_argos_register_notifier(struct notifier_block *n, char *label);
extern int sec_argos_unregister_notifier(struct notifier_block *n, char *label);
typedef struct {
struct net_device *wlan_primary_netdev;
int argos_rps_cpus_enabled;
} argos_rps_ctrl;
#define RPS_TPUT_THRESHOLD 300
#define DELAY_TO_CLEAR_RPS_CPUS 300
#endif // endif
#if defined(BT_OVER_SDIO)
extern void wl_android_set_wifi_on_flag(bool enable);
#endif /* BT_OVER_SDIO */
#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
*/
#define LOG_DUMP_GENERAL_MAX_BUFSIZE (256 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB)
#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_FILTER_MAX_BUFSIZE)
#error "LOG_DUMP_TOTAL_BUFSIZE is lesser than sum of all rings"
#endif // 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;
typedef struct {
int attr;
char *hdr_str;
log_dump_section_type_t sec_type;
int log_type;
} dld_log_hdr_t;
#define DHD_PRINT_BUF_NAME_LEN 30
#endif /* DHD_LOG_DUMP */
int dhd_wifi_platform_register_drv(void);
void dhd_wifi_platform_unregister_drv(void);
wifi_adapter_info_t* dhd_wifi_platform_attach_adapter(uint32 bus_type,
uint32 bus_num, uint32 slot_num, unsigned long status);
wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num,
uint32 slot_num);
int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long msec);
int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present);
int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr);
int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf, char *name);
#ifdef CUSTOM_COUNTRY_CODE
void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode,
u32 flags);
#else
void *wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode);
#endif /* CUSTOM_COUNTRY_CODE */
void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size);
void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter);
int dhd_get_fw_mode(struct dhd_info *dhdinfo);
bool dhd_update_fw_nv_path(struct dhd_info *dhdinfo);
#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)
#define ADPS_ENABLE 1
#define ADPS_DISABLE 0
int dhd_enable_adps(dhd_pub_t *dhd, uint8 on);
#endif // 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 */
int compat_kernel_read(struct file *file, loff_t offset, char *addr, unsigned long count);
int compat_vfs_write(struct file *file, char *addr, int count, loff_t *offset);
#endif /* __DHD_LINUX_H__ */

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

@@ -0,0 +1,125 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Header file for the Packet dump helper functions
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_linux_pktdump.h 820929 2019-05-21 14:09:11Z $
*/
#ifndef __DHD_LINUX_PKTDUMP_H_
#define __DHD_LINUX_PKTDUMP_H_
#include <typedefs.h>
#include <dhd.h>
typedef enum {
EAPOL_OTHER = 0,
EAPOL_4WAY_M1,
EAPOL_4WAY_M2,
EAPOL_4WAY_M3,
EAPOL_4WAY_M4,
EAPOL_GROUPKEY_M1,
EAPOL_GROUPKEY_M2
} msg_eapol_t;
typedef enum pkt_cnt_rsn {
PKT_CNT_RSN_INVALID = 0,
PKT_CNT_RSN_ROAM = 1,
PKT_CNT_RSN_GRPKEY_UP = 2,
PKT_CNT_RSN_CONNECT = 3,
PKT_CNT_RSN_MAX = 4
} pkt_cnt_rsn_t;
extern msg_eapol_t dhd_is_4way_msg(uint8 *pktdata);
extern void dhd_dump_pkt(dhd_pub_t *dhd, int ifidx, uint8 *pktdata,
uint32 pktlen, bool tx, uint32 *pkthash, uint16 *pktfate);
#ifdef DHD_PKTDUMP_ROAM
extern void dhd_dump_mod_pkt_timer(dhd_pub_t *dhdp, uint16 rsn);
extern void dhd_dump_pkt_init(dhd_pub_t *dhdp);
extern void dhd_dump_pkt_deinit(dhd_pub_t *dhdp);
extern void dhd_dump_pkt_clear(dhd_pub_t *dhdp);
#else
static INLINE void dhd_dump_mod_pkt_timer(dhd_pub_t *dhdp, uint16 rsn) { }
static INLINE void dhd_dump_pkt_init(dhd_pub_t *dhdp) { }
static INLINE void dhd_dump_pkt_deinit(dhd_pub_t *dhdp) { }
static INLINE void dhd_dump_pkt_clear(dhd_pub_t *dhdp) { }
#endif /* DHD_PKTDUMP_ROAM */
/* Rx packet dump */
#ifdef DHD_TRX_DUMP
extern void dhd_trx_pkt_dump(dhd_pub_t *dhdp, int ifidx,
uint8 *pktdata, uint32 pktlen, bool tx);
#else
static INLINE void dhd_trx_pkt_dump(dhd_pub_t *dhdp, int ifidx,
uint8 *pktdata, uint32 pktlen, bool tx) { }
#endif /* DHD_TRX_DUMP */
/* DHCP packet dump */
#ifdef DHD_DHCP_DUMP
extern void dhd_dhcp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
uint32 *pkthash, uint16 *pktfate);
#else
static INLINE void dhd_dhcp_dump(dhd_pub_t *dhdp, int ifidx,
uint8 *pktdata, bool tx, uint32 *pkthash, uint16 *pktfate) { }
#endif /* DHD_DHCP_DUMP */
/* DNS packet dump */
#ifdef DHD_DNS_DUMP
extern void dhd_dns_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
uint32 *pkthash, uint16 *pktfate);
#else
static INLINE void dhd_dns_dump(dhd_pub_t *dhdp, int ifidx,
uint8 *pktdata, bool tx, uint32 *pkthash, uint16 *pktfate) { }
#endif /* DHD_DNS_DUMP */
/* ICMP packet dump */
#ifdef DHD_ICMP_DUMP
extern void dhd_icmp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
uint32 *pkthash, uint16 *pktfate);
#else
static INLINE void dhd_icmp_dump(dhd_pub_t *dhdp, int ifidx,
uint8 *pktdata, bool tx, uint32 *pkthash, uint16 *pktfate) { }
#endif /* DHD_ICMP_DUMP */
/* ARP packet dump */
#ifdef DHD_ARP_DUMP
extern void dhd_arp_dump(dhd_pub_t *dhdp, int ifidx, uint8 *pktdata, bool tx,
uint32 *pkthash, uint16 *pktfate);
#else
static INLINE void dhd_arp_dump(dhd_pub_t *dhdp, int ifidx,
uint8 *pktdata, bool tx, uint32 *pkthash, uint16 *pktfate) { }
#endif /* DHD_ARP_DUMP */
/* 802.1X packet dump */
#ifdef DHD_8021X_DUMP
extern void dhd_dump_eapol_message(dhd_pub_t *dhd, int ifidx,
uint8 *pktdata, uint32 pktlen, bool tx, uint32 *pkthash, uint16 *pktfate);
#else
static INLINE void dhd_dump_eapol_message(dhd_pub_t *dhd, int ifidx,
uint8 *pktdata, uint32 pktlen, bool tx, uint32 *pkthash, uint16 *pktfate) { }
#endif /* DHD_8021X_DUMP */
#endif /* __DHD_LINUX_PKTDUMP_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,432 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* DHD Linux header file - contains private structure definition of the Linux specific layer
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_linux_priv.h 815919 2019-04-22 09:06:50Z $
*/
#ifndef __DHD_LINUX_PRIV_H__
#define __DHD_LINUX_PRIV_H__
#include <osl.h>
#ifdef SHOW_LOGTRACE
#include <linux/syscalls.h>
#include <event_log.h>
#endif /* SHOW_LOGTRACE */
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#ifdef CONFIG_COMPAT
#include <linux/compat.h>
#endif /* CONFIG COMPAT */
#include <dngl_stats.h>
#include <dhd.h>
#include <dhd_dbg.h>
#include <dhd_debug.h>
#include <dhd_linux.h>
#include <dhd_bus.h>
#ifdef PCIE_FULL_DONGLE
#include <bcmmsgbuf.h>
#include <dhd_flowring.h>
#endif /* PCIE_FULL_DONGLE */
/*
* Do not include this header except for the dhd_linux.c dhd_linux_sysfs.c
* Local private structure (extension of pub)
*/
typedef struct dhd_info {
#if defined(WL_WIRELESS_EXT)
wl_iw_t iw; /* wireless extensions state (must be first) */
#endif /* defined(WL_WIRELESS_EXT) */
dhd_pub_t pub;
/* for supporting multiple interfaces.
* static_ifs hold the net ifaces without valid FW IF
*/
dhd_if_t *iflist[DHD_MAX_IFS + DHD_MAX_STATIC_IFS];
wifi_adapter_info_t *adapter; /* adapter information, interrupt, fw path etc. */
char fw_path[PATH_MAX]; /* path to firmware image */
char nv_path[PATH_MAX]; /* path to nvram vars file */
char clm_path[PATH_MAX]; /* path to clm vars file */
char conf_path[PATH_MAX]; /* path to config vars file */
#ifdef DHD_UCODE_DOWNLOAD
char uc_path[PATH_MAX]; /* path to ucode image */
#endif /* DHD_UCODE_DOWNLOAD */
/* serialize dhd iovars */
struct mutex dhd_iovar_mutex;
struct semaphore proto_sem;
#ifdef PROP_TXSTATUS
spinlock_t wlfc_spinlock;
#ifdef BCMDBUS
ulong wlfc_lock_flags;
ulong wlfc_pub_lock_flags;
#endif /* BCMDBUS */
#endif /* PROP_TXSTATUS */
wait_queue_head_t ioctl_resp_wait;
wait_queue_head_t d3ack_wait;
wait_queue_head_t dhd_bus_busy_state_wait;
wait_queue_head_t dmaxfer_wait;
uint32 default_wd_interval;
timer_list_compat_t timer;
bool wd_timer_valid;
struct tasklet_struct tasklet;
spinlock_t sdlock;
spinlock_t txqlock;
spinlock_t dhd_lock;
#ifdef BCMDBUS
ulong txqlock_flags;
#else
struct semaphore sdsem;
tsk_ctl_t thr_dpc_ctl;
tsk_ctl_t thr_wdt_ctl;
#endif /* BCMDBUS */
tsk_ctl_t thr_rxf_ctl;
spinlock_t rxf_lock;
bool rxthread_enabled;
/* Wakelocks */
#if defined(CONFIG_HAS_WAKELOCK)
struct wake_lock wl_wifi; /* Wifi wakelock */
struct wake_lock wl_rxwake; /* Wifi rx wakelock */
struct wake_lock wl_ctrlwake; /* Wifi ctrl wakelock */
struct wake_lock wl_wdwake; /* Wifi wd wakelock */
struct wake_lock wl_evtwake; /* Wifi event wakelock */
struct wake_lock wl_pmwake; /* Wifi pm handler wakelock */
struct wake_lock wl_txflwake; /* Wifi tx flow wakelock */
#ifdef BCMPCIE_OOB_HOST_WAKE
struct wake_lock wl_intrwake; /* Host wakeup wakelock */
#endif /* BCMPCIE_OOB_HOST_WAKE */
#ifdef DHD_USE_SCAN_WAKELOCK
struct wake_lock wl_scanwake; /* Wifi scan wakelock */
#endif /* DHD_USE_SCAN_WAKELOCK */
#endif /* CONFIG_HAS_WAKELOCK */
/* 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)
struct mutex dhd_apf_mutex;
#endif /* PKT_FILTER_SUPPORT && APF */
spinlock_t wakelock_spinlock;
spinlock_t wakelock_evt_spinlock;
uint32 wakelock_counter;
int wakelock_wd_counter;
int wakelock_rx_timeout_enable;
int wakelock_ctrl_timeout_enable;
bool waive_wakelock;
uint32 wakelock_before_waive;
/* Thread to issue ioctl for multicast */
wait_queue_head_t ctrl_wait;
atomic_t pend_8021x_cnt;
dhd_attach_states_t dhd_state;
#ifdef SHOW_LOGTRACE
dhd_event_log_t event_data;
#endif /* SHOW_LOGTRACE */
#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND)
struct early_suspend early_suspend;
#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */
#ifdef ARP_OFFLOAD_SUPPORT
u32 pend_ipaddr;
#endif /* ARP_OFFLOAD_SUPPORT */
#ifdef DHDTCPACK_SUPPRESS
spinlock_t tcpack_lock;
#endif /* DHDTCPACK_SUPPRESS */
#ifdef FIX_CPU_MIN_CLOCK
bool cpufreq_fix_status;
struct mutex cpufreq_fix;
struct pm_qos_request dhd_cpu_qos;
#ifdef FIX_BUS_MIN_CLOCK
struct pm_qos_request dhd_bus_qos;
#endif /* FIX_BUS_MIN_CLOCK */
#endif /* FIX_CPU_MIN_CLOCK */
void *dhd_deferred_wq;
#ifdef DEBUG_CPU_FREQ
struct notifier_block freq_trans;
int __percpu *new_freq;
#endif // endif
unsigned int unit;
struct notifier_block pm_notifier;
#ifdef DHD_PSTA
uint32 psta_mode; /* PSTA or PSR */
#endif /* DHD_PSTA */
#ifdef DHD_WET
uint32 wet_mode;
#endif /* DHD_WET */
#ifdef DHD_DEBUG
dhd_dump_t *dump;
struct timer_list join_timer;
u32 join_timeout_val;
bool join_timer_active;
uint scan_time_count;
struct timer_list scan_timer;
bool scan_timer_active;
#endif // endif
#if defined(DHD_LB)
/* CPU Load Balance dynamic CPU selection */
/* Variable that tracks the currect CPUs available for candidacy */
cpumask_var_t cpumask_curr_avail;
/* Primary and secondary CPU mask */
cpumask_var_t cpumask_primary, cpumask_secondary; /* configuration */
cpumask_var_t cpumask_primary_new, cpumask_secondary_new; /* temp */
struct notifier_block cpu_notifier;
/* Tasklet to handle Tx Completion packet freeing */
struct tasklet_struct tx_compl_tasklet;
atomic_t tx_compl_cpu;
/* Tasklet to handle RxBuf Post during Rx completion */
struct tasklet_struct rx_compl_tasklet;
atomic_t rx_compl_cpu;
/* Napi struct for handling rx packet sendup. Packets are removed from
* H2D RxCompl ring and placed into rx_pend_queue. rx_pend_queue is then
* appended to rx_napi_queue (w/ lock) and the rx_napi_struct is scheduled
* to run to rx_napi_cpu.
*/
struct sk_buff_head rx_pend_queue ____cacheline_aligned;
struct sk_buff_head rx_napi_queue ____cacheline_aligned;
struct napi_struct rx_napi_struct ____cacheline_aligned;
atomic_t rx_napi_cpu; /* cpu on which the napi is dispatched */
struct net_device *rx_napi_netdev; /* netdev of primary interface */
struct work_struct rx_napi_dispatcher_work;
struct work_struct tx_compl_dispatcher_work;
struct work_struct tx_dispatcher_work;
struct work_struct rx_compl_dispatcher_work;
/* Number of times DPC Tasklet ran */
uint32 dhd_dpc_cnt;
/* Number of times NAPI processing got scheduled */
uint32 napi_sched_cnt;
/* Number of times NAPI processing ran on each available core */
uint32 *napi_percpu_run_cnt;
/* Number of times RX Completions got scheduled */
uint32 rxc_sched_cnt;
/* Number of times RX Completion ran on each available core */
uint32 *rxc_percpu_run_cnt;
/* Number of times TX Completions got scheduled */
uint32 txc_sched_cnt;
/* Number of times TX Completions ran on each available core */
uint32 *txc_percpu_run_cnt;
/* CPU status */
/* Number of times each CPU came online */
uint32 *cpu_online_cnt;
/* Number of times each CPU went offline */
uint32 *cpu_offline_cnt;
/* Number of times TX processing run on each core */
uint32 *txp_percpu_run_cnt;
/* Number of times TX start run on each core */
uint32 *tx_start_percpu_run_cnt;
/* Tx load balancing */
/* TODO: Need to see if batch processing is really required in case of TX
* processing. In case of RX the Dongle can send a bunch of rx completions,
* hence we took a 3 queue approach
* enque - adds the skbs to rx_pend_queue
* dispatch - uses a lock and adds the list of skbs from pend queue to
* napi queue
* napi processing - copies the pend_queue into a local queue and works
* on it.
* But for TX its going to be 1 skb at a time, so we are just thinking
* of using only one queue and use the lock supported skb queue functions
* to add and process it. If its in-efficient we'll re-visit the queue
* design.
*/
/* When the NET_TX tries to send a TX packet put it into tx_pend_queue */
/* struct sk_buff_head tx_pend_queue ____cacheline_aligned; */
/*
* From the Tasklet that actually sends out data
* copy the list tx_pend_queue into tx_active_queue. There by we need
* to spinlock to only perform the copy the rest of the code ie to
* construct the tx_pend_queue and the code to process tx_active_queue
* can be lockless. The concept is borrowed as is from RX processing
*/
/* struct sk_buff_head tx_active_queue ____cacheline_aligned; */
/* Control TXP in runtime, enable by default */
atomic_t lb_txp_active;
/* Control RXP in runtime, enable by default */
atomic_t lb_rxp_active;
/*
* When the NET_TX tries to send a TX packet put it into tx_pend_queue
* For now, the processing tasklet will also direcly operate on this
* queue
*/
struct sk_buff_head tx_pend_queue ____cacheline_aligned;
/* Control RXP in runtime, enable by default */
/* cpu on which the DHD Tx is happenning */
atomic_t tx_cpu;
/* CPU on which the Network stack is calling the DHD's xmit function */
atomic_t net_tx_cpu;
/* Tasklet context from which the DHD's TX processing happens */
struct tasklet_struct tx_tasklet;
/*
* Consumer Histogram - NAPI RX Packet processing
* -----------------------------------------------
* On Each CPU, when the NAPI RX Packet processing call back was invoked
* how many packets were processed is captured in this data structure.
* Now its difficult to capture the "exact" number of packets processed.
* So considering the packet counter to be a 32 bit one, we have a
* bucket with 8 bins (2^1, 2^2 ... 2^8). The "number" of packets
* processed is rounded off to the next power of 2 and put in the
* approriate "bin" the value in the bin gets incremented.
* For example, assume that in CPU 1 if NAPI Rx runs 3 times
* and the packet count processed is as follows (assume the bin counters are 0)
* iteration 1 - 10 (the bin counter 2^4 increments to 1)
* iteration 2 - 30 (the bin counter 2^5 increments to 1)
* iteration 3 - 15 (the bin counter 2^4 increments by 1 to become 2)
*/
uint32 *napi_rx_hist[HIST_BIN_SIZE];
uint32 *txc_hist[HIST_BIN_SIZE];
uint32 *rxc_hist[HIST_BIN_SIZE];
#endif /* DHD_LB */
#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 */
#ifdef SHOW_LOGTRACE
#ifdef DHD_USE_KTHREAD_FOR_LOGTRACE
tsk_ctl_t thr_logtrace_ctl;
#else
struct delayed_work event_log_dispatcher_work;
#endif /* DHD_USE_KTHREAD_FOR_LOGTRACE */
#endif /* SHOW_LOGTRACE */
#if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW)
#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */
struct kobject dhd_kobj;
struct kobject dhd_conf_file_kobj;
struct timer_list timesync_timer;
#if defined(BT_OVER_SDIO)
char btfw_path[PATH_MAX];
#endif /* defined (BT_OVER_SDIO) */
#ifdef WL_MONITOR
struct net_device *monitor_dev; /* monitor pseudo device */
struct sk_buff *monitor_skb;
uint monitor_len;
uint monitor_type; /* monitor pseudo device */
#endif /* WL_MONITOR */
#if defined(BT_OVER_SDIO)
struct mutex bus_user_lock; /* lock for sdio bus apis shared between WLAN & BT */
int bus_user_count; /* User counts of sdio bus shared between WLAN & BT */
#endif /* BT_OVER_SDIO */
#ifdef SHOW_LOGTRACE
struct sk_buff_head evt_trace_queue ____cacheline_aligned;
#endif // endif
#ifdef DHD_PCIE_NATIVE_RUNTIMEPM
struct workqueue_struct *tx_wq;
struct workqueue_struct *rx_wq;
#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
#ifdef DHD_DEBUG_UART
bool duart_execute;
#endif /* DHD_DEBUG_UART */
struct mutex logdump_lock;
/* indicates mem_dump was scheduled as work queue or called directly */
bool scheduled_memdump;
struct work_struct dhd_hang_process_work;
#ifdef DHD_HP2P
spinlock_t hp2p_lock;
#endif /* DHD_HP2P */
} dhd_info_t;
extern int dhd_sysfs_init(dhd_info_t *dhd);
extern void dhd_sysfs_exit(dhd_info_t *dhd);
extern void dhd_dbg_ring_proc_create(dhd_pub_t *dhdp);
extern void dhd_dbg_ring_proc_destroy(dhd_pub_t *dhdp);
int __dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf);
#if defined(DHD_LB)
#if defined(DHD_LB_TXP)
int dhd_lb_sendpkt(dhd_info_t *dhd, struct net_device *net, int ifidx, void *skb);
void dhd_tx_dispatcher_work(struct work_struct * work);
void dhd_tx_dispatcher_fn(dhd_pub_t *dhdp);
void dhd_lb_tx_dispatch(dhd_pub_t *dhdp);
void dhd_lb_tx_handler(unsigned long data);
#endif /* DHD_LB_TXP */
#if defined(DHD_LB_RXP)
int dhd_napi_poll(struct napi_struct *napi, int budget);
void dhd_rx_napi_dispatcher_fn(struct work_struct * work);
void dhd_lb_rx_napi_dispatch(dhd_pub_t *dhdp);
void dhd_lb_rx_pkt_enqueue(dhd_pub_t *dhdp, void *pkt, int ifidx);
#endif /* DHD_LB_RXP */
void dhd_lb_set_default_cpus(dhd_info_t *dhd);
void dhd_cpumasks_deinit(dhd_info_t *dhd);
int dhd_cpumasks_init(dhd_info_t *dhd);
void dhd_select_cpu_candidacy(dhd_info_t *dhd);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))
int dhd_cpu_startup_callback(unsigned int cpu);
int dhd_cpu_teardown_callback(unsigned int cpu);
#else
int dhd_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu);
#endif /* LINUX_VERSION_CODE < 4.10.0 */
int dhd_register_cpuhp_callback(dhd_info_t *dhd);
int dhd_unregister_cpuhp_callback(dhd_info_t *dhd);
#if defined(DHD_LB_TXC)
void dhd_lb_tx_compl_dispatch(dhd_pub_t *dhdp);
#endif /* DHD_LB_TXC */
#if defined(DHD_LB_RXC)
void dhd_lb_rx_compl_dispatch(dhd_pub_t *dhdp);
void dhd_rx_compl_dispatcher_fn(struct work_struct * work);
#endif /* DHD_LB_RXC */
#endif /* DHD_LB */
#if defined(DHD_LB_IRQSET) || defined(DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON)
void dhd_irq_set_affinity(dhd_pub_t *dhdp, const struct cpumask *cpumask);
#endif /* DHD_LB_IRQSET || DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON */
#endif /* __DHD_LINUX_PRIV_H__ */

View File

@@ -0,0 +1,48 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Expose some of the kernel scheduler routines
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_linux_sched.c 815919 2019-04-22 09:06:50Z $
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <typedefs.h>
#include <linuxver.h>
int setScheduler(struct task_struct *p, int policy, struct sched_param *param)
{
int rc = 0;
rc = sched_setscheduler(p, policy, param);
return rc;
}
int get_scheduler_policy(struct task_struct *p)
{
int rc = SCHED_NORMAL;
rc = p->policy;
return rc;
}

View File

@@ -0,0 +1,397 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Broadcom Dongle Host Driver (DHD), Generic work queue framework
* Generic interface to handle dhd deferred work events
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_linux_wq.c 815919 2019-04-22 09:06:50Z $
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/ip.h>
#include <linux/kfifo.h>
#include <linuxver.h>
#include <osl.h>
#include <bcmutils.h>
#include <bcmendian.h>
#include <bcmdevs.h>
#include <dngl_stats.h>
#include <dhd.h>
#include <dhd_dbg.h>
#include <dhd_linux_wq.h>
typedef struct dhd_deferred_event {
u8 event; /* holds the event */
void *event_data; /* holds event specific data */
event_handler_t event_handler;
unsigned long pad; /* for memory alignment to power of 2 */
} dhd_deferred_event_t;
#define DEFRD_EVT_SIZE (sizeof(dhd_deferred_event_t))
/*
* work events may occur simultaneously.
* can hold upto 64 low priority events and 16 high priority events
*/
#define DHD_PRIO_WORK_FIFO_SIZE (16 * DEFRD_EVT_SIZE)
#define DHD_WORK_FIFO_SIZE (64 * DEFRD_EVT_SIZE)
#define DHD_FIFO_HAS_FREE_SPACE(fifo) \
((fifo) && (kfifo_avail(fifo) >= DEFRD_EVT_SIZE))
#define DHD_FIFO_HAS_ENOUGH_DATA(fifo) \
((fifo) && (kfifo_len(fifo) >= DEFRD_EVT_SIZE))
struct dhd_deferred_wq {
struct work_struct deferred_work; /* should be the first member */
struct kfifo *prio_fifo;
struct kfifo *work_fifo;
u8 *prio_fifo_buf;
u8 *work_fifo_buf;
spinlock_t work_lock;
void *dhd_info; /* review: does it require */
u32 event_skip_mask;
};
static inline struct kfifo*
dhd_kfifo_init(u8 *buf, int size, spinlock_t *lock)
{
struct kfifo *fifo;
gfp_t flags = CAN_SLEEP()? GFP_KERNEL : GFP_ATOMIC;
fifo = (struct kfifo *)kzalloc(sizeof(struct kfifo), flags);
if (!fifo) {
return NULL;
}
kfifo_init(fifo, buf, size);
return fifo;
}
static inline void
dhd_kfifo_free(struct kfifo *fifo)
{
kfifo_free(fifo);
}
/* deferred work functions */
static void dhd_deferred_work_handler(struct work_struct *data);
void*
dhd_deferred_work_init(void *dhd_info)
{
struct dhd_deferred_wq *work = NULL;
u8* buf;
unsigned long fifo_size = 0;
gfp_t flags = CAN_SLEEP()? GFP_KERNEL : GFP_ATOMIC;
if (!dhd_info) {
DHD_ERROR(("%s: dhd info not initialized\n", __FUNCTION__));
goto return_null;
}
work = (struct dhd_deferred_wq *)kzalloc(sizeof(struct dhd_deferred_wq),
flags);
if (!work) {
DHD_ERROR(("%s: work queue creation failed\n", __FUNCTION__));
goto return_null;
}
INIT_WORK((struct work_struct *)work, dhd_deferred_work_handler);
/* initialize event fifo */
spin_lock_init(&work->work_lock);
/* allocate buffer to hold prio events */
fifo_size = DHD_PRIO_WORK_FIFO_SIZE;
fifo_size = is_power_of_2(fifo_size) ? fifo_size :
roundup_pow_of_two(fifo_size);
buf = (u8*)kzalloc(fifo_size, flags);
if (!buf) {
DHD_ERROR(("%s: prio work fifo allocation failed\n",
__FUNCTION__));
goto return_null;
}
/* Initialize prio event fifo */
work->prio_fifo = dhd_kfifo_init(buf, fifo_size, &work->work_lock);
if (!work->prio_fifo) {
kfree(buf);
goto return_null;
}
/* allocate buffer to hold work events */
fifo_size = DHD_WORK_FIFO_SIZE;
fifo_size = is_power_of_2(fifo_size) ? fifo_size :
roundup_pow_of_two(fifo_size);
buf = (u8*)kzalloc(fifo_size, flags);
if (!buf) {
DHD_ERROR(("%s: work fifo allocation failed\n", __FUNCTION__));
goto return_null;
}
/* Initialize event fifo */
work->work_fifo = dhd_kfifo_init(buf, fifo_size, &work->work_lock);
if (!work->work_fifo) {
kfree(buf);
goto return_null;
}
work->dhd_info = dhd_info;
work->event_skip_mask = 0;
DHD_ERROR(("%s: work queue initialized\n", __FUNCTION__));
return work;
return_null:
if (work) {
dhd_deferred_work_deinit(work);
}
return NULL;
}
void
dhd_deferred_work_deinit(void *work)
{
struct dhd_deferred_wq *deferred_work = work;
if (!deferred_work) {
DHD_ERROR(("%s: deferred work has been freed already\n",
__FUNCTION__));
return;
}
/* cancel the deferred work handling */
cancel_work_sync((struct work_struct *)deferred_work);
/*
* free work event fifo.
* kfifo_free frees locally allocated fifo buffer
*/
if (deferred_work->prio_fifo) {
dhd_kfifo_free(deferred_work->prio_fifo);
}
if (deferred_work->work_fifo) {
dhd_kfifo_free(deferred_work->work_fifo);
}
kfree(deferred_work);
}
/* select kfifo according to priority */
static inline struct kfifo *
dhd_deferred_work_select_kfifo(struct dhd_deferred_wq *deferred_wq,
u8 priority)
{
if (priority == DHD_WQ_WORK_PRIORITY_HIGH) {
return deferred_wq->prio_fifo;
} else if (priority == DHD_WQ_WORK_PRIORITY_LOW) {
return deferred_wq->work_fifo;
} else {
return NULL;
}
}
/*
* Prepares event to be queued
* Schedules the event
*/
int
dhd_deferred_schedule_work(void *workq, void *event_data, u8 event,
event_handler_t event_handler, u8 priority)
{
struct dhd_deferred_wq *deferred_wq = (struct dhd_deferred_wq *)workq;
struct kfifo *fifo;
dhd_deferred_event_t deferred_event;
int bytes_copied = 0;
if (!deferred_wq) {
DHD_ERROR(("%s: work queue not initialized\n", __FUNCTION__));
ASSERT(0);
return DHD_WQ_STS_UNINITIALIZED;
}
if (!event || (event >= DHD_MAX_WQ_EVENTS)) {
DHD_ERROR(("%s: unknown event, event=%d\n", __FUNCTION__,
event));
return DHD_WQ_STS_UNKNOWN_EVENT;
}
if (!priority || (priority >= DHD_WQ_MAX_PRIORITY)) {
DHD_ERROR(("%s: unknown priority, priority=%d\n",
__FUNCTION__, priority));
return DHD_WQ_STS_UNKNOWN_PRIORITY;
}
if ((deferred_wq->event_skip_mask & (1 << event))) {
DHD_ERROR(("%s: Skip event requested. Mask = 0x%x\n",
__FUNCTION__, deferred_wq->event_skip_mask));
return DHD_WQ_STS_EVENT_SKIPPED;
}
/*
* default element size is 1, which can be changed
* using kfifo_esize(). Older kernel(FC11) doesn't support
* changing element size. For compatibility changing
* element size is not prefered
*/
ASSERT(kfifo_esize(deferred_wq->prio_fifo) == 1);
ASSERT(kfifo_esize(deferred_wq->work_fifo) == 1);
deferred_event.event = event;
deferred_event.event_data = event_data;
deferred_event.event_handler = event_handler;
fifo = dhd_deferred_work_select_kfifo(deferred_wq, priority);
if (DHD_FIFO_HAS_FREE_SPACE(fifo)) {
bytes_copied = kfifo_in_spinlocked(fifo, &deferred_event,
DEFRD_EVT_SIZE, &deferred_wq->work_lock);
}
if (bytes_copied != DEFRD_EVT_SIZE) {
DHD_ERROR(("%s: failed to schedule deferred work, "
"priority=%d, bytes_copied=%d\n", __FUNCTION__,
priority, bytes_copied));
return DHD_WQ_STS_SCHED_FAILED;
}
schedule_work((struct work_struct *)deferred_wq);
return DHD_WQ_STS_OK;
}
static bool
dhd_get_scheduled_work(struct dhd_deferred_wq *deferred_wq,
dhd_deferred_event_t *event)
{
int bytes_copied = 0;
if (!deferred_wq) {
DHD_ERROR(("%s: work queue not initialized\n", __FUNCTION__));
return DHD_WQ_STS_UNINITIALIZED;
}
/*
* default element size is 1 byte, which can be changed
* using kfifo_esize(). Older kernel(FC11) doesn't support
* changing element size. For compatibility changing
* element size is not prefered
*/
ASSERT(kfifo_esize(deferred_wq->prio_fifo) == 1);
ASSERT(kfifo_esize(deferred_wq->work_fifo) == 1);
/* handle priority work */
if (DHD_FIFO_HAS_ENOUGH_DATA(deferred_wq->prio_fifo)) {
bytes_copied = kfifo_out_spinlocked(deferred_wq->prio_fifo,
event, DEFRD_EVT_SIZE, &deferred_wq->work_lock);
}
/* handle normal work if priority work doesn't have enough data */
if ((bytes_copied != DEFRD_EVT_SIZE) &&
DHD_FIFO_HAS_ENOUGH_DATA(deferred_wq->work_fifo)) {
bytes_copied = kfifo_out_spinlocked(deferred_wq->work_fifo,
event, DEFRD_EVT_SIZE, &deferred_wq->work_lock);
}
return (bytes_copied == DEFRD_EVT_SIZE);
}
static inline void
dhd_deferred_dump_work_event(dhd_deferred_event_t *work_event)
{
if (!work_event) {
DHD_ERROR(("%s: work_event is null\n", __FUNCTION__));
return;
}
DHD_ERROR(("%s: work_event->event = %d\n", __FUNCTION__,
work_event->event));
DHD_ERROR(("%s: work_event->event_data = %p\n", __FUNCTION__,
work_event->event_data));
DHD_ERROR(("%s: work_event->event_handler = %p\n", __FUNCTION__,
work_event->event_handler));
}
/*
* Called when work is scheduled
*/
static void
dhd_deferred_work_handler(struct work_struct *work)
{
struct dhd_deferred_wq *deferred_work = (struct dhd_deferred_wq *)work;
dhd_deferred_event_t work_event;
if (!deferred_work) {
DHD_ERROR(("%s: work queue not initialized\n", __FUNCTION__));
return;
}
do {
if (!dhd_get_scheduled_work(deferred_work, &work_event)) {
DHD_TRACE(("%s: no event to handle\n", __FUNCTION__));
break;
}
if (work_event.event >= DHD_MAX_WQ_EVENTS) {
DHD_ERROR(("%s: unknown event\n", __FUNCTION__));
dhd_deferred_dump_work_event(&work_event);
ASSERT(work_event.event < DHD_MAX_WQ_EVENTS);
continue;
}
if (work_event.event_handler) {
work_event.event_handler(deferred_work->dhd_info,
work_event.event_data, work_event.event);
} else {
DHD_ERROR(("%s: event handler is null\n",
__FUNCTION__));
dhd_deferred_dump_work_event(&work_event);
ASSERT(work_event.event_handler != NULL);
}
} while (1);
return;
}
void
dhd_deferred_work_set_skip(void *work, u8 event, bool set)
{
struct dhd_deferred_wq *deferred_wq = (struct dhd_deferred_wq *)work;
if (!deferred_wq || !event || (event >= DHD_MAX_WQ_EVENTS)) {
DHD_ERROR(("%s: Invalid!!\n", __FUNCTION__));
return;
}
if (set) {
/* Set */
deferred_wq->event_skip_mask |= (1 << event);
} else {
/* Clear */
deferred_wq->event_skip_mask &= ~(1 << event);
}
}

View File

@@ -0,0 +1,93 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Broadcom Dongle Host Driver (DHD), Generic work queue framework
* Generic interface to handle dhd deferred work events
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_linux_wq.h 814378 2019-04-11 02:21:31Z $
*/
#ifndef _dhd_linux_wq_h_
#define _dhd_linux_wq_h_
/*
* Work event definitions
*/
enum _wq_event {
DHD_WQ_WORK_IF_ADD = 1,
DHD_WQ_WORK_IF_DEL,
DHD_WQ_WORK_SET_MAC,
DHD_WQ_WORK_SET_MCAST_LIST,
DHD_WQ_WORK_IPV6_NDO,
DHD_WQ_WORK_HANG_MSG,
DHD_WQ_WORK_DHD_LOG_DUMP,
DHD_WQ_WORK_PKTLOG_DUMP,
DHD_WQ_WORK_INFORM_DHD_MON,
DHD_WQ_WORK_EVENT_LOGTRACE,
DHD_WQ_WORK_DMA_LB_MEM_REL,
DHD_WQ_WORK_NATOE_EVENT,
DHD_WQ_WORK_NATOE_IOCTL,
DHD_WQ_WORK_MACDBG,
DHD_WQ_WORK_DEBUG_UART_DUMP,
DHD_WQ_WORK_GET_BIGDATA_AP,
DHD_WQ_WORK_SOC_RAM_DUMP,
#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_MAX_WQ_EVENTS
};
/*
* Work event priority
*/
enum wq_priority {
DHD_WQ_WORK_PRIORITY_LOW = 1,
DHD_WQ_WORK_PRIORITY_HIGH,
DHD_WQ_MAX_PRIORITY
};
/*
* Error definitions
*/
#define DHD_WQ_STS_OK 0
#define DHD_WQ_STS_FAILED -1 /* General failure */
#define DHD_WQ_STS_UNINITIALIZED -2
#define DHD_WQ_STS_SCHED_FAILED -3
#define DHD_WQ_STS_UNKNOWN_EVENT -4
#define DHD_WQ_STS_UNKNOWN_PRIORITY -5
#define DHD_WQ_STS_EVENT_SKIPPED -6
typedef void (*event_handler_t)(void *handle, void *event_data, u8 event);
void *dhd_deferred_work_init(void *dhd);
void dhd_deferred_work_deinit(void *workq);
int dhd_deferred_schedule_work(void *workq, void *event_data, u8 event,
event_handler_t evt_handler, u8 priority);
void dhd_deferred_work_set_skip(void *work, u8 event, bool set);
#endif /* _dhd_linux_wq_h_ */

View File

@@ -0,0 +1,789 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* DHD debugability support
*
* <<Broadcom-WL-IPTag/Open:>>
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: dhd_mschdbg.c 639872 2016-05-25 05:39:30Z $
*/
#ifdef SHOW_LOGTRACE
#include <typedefs.h>
#include <osl.h>
#include <bcmutils.h>
#include <bcmendian.h>
#include <dngl_stats.h>
#include <dhd.h>
#include <dhd_dbg.h>
#include <dhd_debug.h>
#include <dhd_mschdbg.h>
#include <event_log.h>
#include <event_trace.h>
#include <msgtrace.h>
static const char *head_log = "";
#define MSCH_EVENT_HEAD(space) \
do { \
MSCH_EVENT(("%s_E: ", head_log)); \
if (space > 0) { \
int ii; \
for (ii = 0; ii < space; ii += 4) MSCH_EVENT((" ")); \
} \
} while (0)
#define MSCH_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0)
static uint64 solt_start_time[4], req_start_time[4], profiler_start_time[4];
static uint32 solt_chanspec[4] = {0, }, req_start[4] = {0, };
static bool lastMessages = FALSE;
#define US_PRE_SEC 1000000
#define DATA_UNIT_FOR_LOG_CNT 4
static void dhd_mschdbg_us_to_sec(uint32 time_h, uint32 time_l, uint32 *sec, uint32 *remain)
{
uint64 cur_time = ((uint64)(ntoh32(time_h)) << 32) | ntoh32(time_l);
uint64 r, u = 0;
r = cur_time;
while (time_h != 0) {
u += (uint64)((0xffffffff / US_PRE_SEC)) * time_h;
r = cur_time - u * US_PRE_SEC;
time_h = (uint32)(r >> 32);
}
*sec = (uint32)(u + ((uint32)(r) / US_PRE_SEC));
*remain = (uint32)(r) % US_PRE_SEC;
}
static char *dhd_mschdbg_display_time(uint32 time_h, uint32 time_l)
{
static char display_time[32];
uint32 s, ss;
if (time_h == 0xffffffff && time_l == 0xffffffff) {
snprintf(display_time, 31, "-1");
} else {
dhd_mschdbg_us_to_sec(time_h, time_l, &s, &ss);
snprintf(display_time, 31, "%d.%06d", s, ss);
}
return display_time;
}
static void
dhd_mschdbg_chanspec_list(int sp, char *data, uint16 ptr, uint16 chanspec_cnt)
{
int i, cnt = (int)ntoh16(chanspec_cnt);
uint16 *chanspec_list = (uint16 *)(data + ntoh16(ptr));
char buf[CHANSPEC_STR_LEN];
chanspec_t c;
MSCH_EVENT_HEAD(sp);
MSCH_EVENT(("<chanspec_list>:"));
for (i = 0; i < cnt; i++) {
c = (chanspec_t)ntoh16(chanspec_list[i]);
MSCH_EVENT((" %s", wf_chspec_ntoa(c, buf)));
}
MSCH_EVENT(("\n"));
}
static void
dhd_mschdbg_elem_list(int sp, char *title, char *data, uint16 ptr, uint16 list_cnt)
{
int i, cnt = (int)ntoh16(list_cnt);
uint32 *list = (uint32 *)(data + ntoh16(ptr));
MSCH_EVENT_HEAD(sp);
MSCH_EVENT(("%s_list: ", title));
for (i = 0; i < cnt; i++) {
MSCH_EVENT(("0x%08x->", ntoh32(list[i])));
}
MSCH_EVENT(("null\n"));
}
static void
dhd_mschdbg_req_param_profiler_event_data(int sp, int ver, char *data, uint16 ptr)
{
int sn = sp + 4;
msch_req_param_profiler_event_data_t *p =
(msch_req_param_profiler_event_data_t *)(data + ntoh16(ptr));
uint32 type, flags;
MSCH_EVENT_HEAD(sp);
MSCH_EVENT(("<request parameters>\n"));
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("req_type: "));
type = p->req_type;
if (type < 4) {
char *req_type[] = {"fixed", "start-flexible", "duration-flexible",
"both-flexible"};
MSCH_EVENT(("%s", req_type[type]));
}
else
MSCH_EVENT(("unknown(%d)", type));
flags = ntoh16(p->flags);
if (flags & WL_MSCH_REQ_FLAGS_CHAN_CONTIGUOUS)
MSCH_EVENT((", CHAN_CONTIGUOUS"));
if (flags & WL_MSCH_REQ_FLAGS_MERGE_CONT_SLOTS)
MSCH_EVENT((", MERGE_CONT_SLOTS"));
if (flags & WL_MSCH_REQ_FLAGS_PREMTABLE)
MSCH_EVENT((", PREMTABLE"));
if (flags & WL_MSCH_REQ_FLAGS_PREMT_CURTS)
MSCH_EVENT((", PREMT_CURTS"));
if (flags & WL_MSCH_REQ_FLAGS_PREMT_IMMEDIATE)
MSCH_EVENT((", PREMT_IMMEDIATE"));
MSCH_EVENT((", priority: %d\n", p->priority));
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("start-time: %s, duration: %d(us), interval: %d(us)\n",
dhd_mschdbg_display_time(p->start_time_h, p->start_time_l),
ntoh32(p->duration), ntoh32(p->interval)));
if (type == WL_MSCH_RT_DUR_FLEX) {
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("dur_flex: %d(us)\n", ntoh32(p->flex.dur_flex)));
} else if (type == WL_MSCH_RT_BOTH_FLEX) {
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("min_dur: %d(us), max_away_dur: %d(us)\n",
ntoh32(p->flex.bf.min_dur), ntoh32(p->flex.bf.max_away_dur)));
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("hi_prio_time: %s, hi_prio_interval: %d(us)\n",
dhd_mschdbg_display_time(p->flex.bf.hi_prio_time_h,
p->flex.bf.hi_prio_time_l),
ntoh32(p->flex.bf.hi_prio_interval)));
}
}
static void
dhd_mschdbg_timeslot_profiler_event_data(int sp, int ver, char *title, char *data,
uint16 ptr, bool empty)
{
int s, sn = sp + 4;
msch_timeslot_profiler_event_data_t *p =
(msch_timeslot_profiler_event_data_t *)(data + ntoh16(ptr));
char *state[] = {"NONE", "CHN_SW", "ONCHAN_FIRE", "OFF_CHN_PREP",
"OFF_CHN_DONE", "TS_COMPLETE"};
MSCH_EVENT_HEAD(sp);
MSCH_EVENT(("<%s timeslot>: ", title));
if (empty) {
MSCH_EVENT((" null\n"));
return;
}
else
MSCH_EVENT(("0x%08x\n", ntoh32(p->p_timeslot)));
s = (int)(ntoh32(p->state));
if (s > 5) s = 0;
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("id: %d, state[%d]: %s, chan_ctxt: [0x%08x]\n",
ntoh32(p->timeslot_id), ntoh32(p->state), state[s], ntoh32(p->p_chan_ctxt)));
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("fire_time: %s",
dhd_mschdbg_display_time(p->fire_time_h, p->fire_time_l)));
MSCH_EVENT((", pre_start_time: %s",
dhd_mschdbg_display_time(p->pre_start_time_h, p->pre_start_time_l)));
MSCH_EVENT((", end_time: %s",
dhd_mschdbg_display_time(p->end_time_h, p->end_time_l)));
MSCH_EVENT((", sch_dur: %s\n",
dhd_mschdbg_display_time(p->sch_dur_h, p->sch_dur_l)));
}
static void
dhd_mschdbg_req_timing_profiler_event_data(int sp, int ver, char *title, char *data,
uint16 ptr, bool empty)
{
int sn = sp + 4;
msch_req_timing_profiler_event_data_t *p =
(msch_req_timing_profiler_event_data_t *)(data + ntoh16(ptr));
uint32 type;
MSCH_EVENT_HEAD(sp);
MSCH_EVENT(("<%s req_timing>: ", title));
if (empty) {
MSCH_EVENT((" null\n"));
return;
}
else
MSCH_EVENT(("0x%08x (prev 0x%08x, next 0x%08x)\n",
ntoh32(p->p_req_timing), ntoh32(p->p_prev), ntoh32(p->p_next)));
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("flags:"));
type = ntoh16(p->flags);
if ((type & 0x7f) == 0)
MSCH_EVENT((" NONE"));
else {
if (type & WL_MSCH_RC_FLAGS_ONCHAN_FIRE)
MSCH_EVENT((" ONCHAN_FIRE"));
if (type & WL_MSCH_RC_FLAGS_START_FIRE_DONE)
MSCH_EVENT((" START_FIRE"));
if (type & WL_MSCH_RC_FLAGS_END_FIRE_DONE)
MSCH_EVENT((" END_FIRE"));
if (type & WL_MSCH_RC_FLAGS_ONFIRE_DONE)
MSCH_EVENT((" ONFIRE_DONE"));
if (type & WL_MSCH_RC_FLAGS_SPLIT_SLOT_START)
MSCH_EVENT((" SPLIT_SLOT_START"));
if (type & WL_MSCH_RC_FLAGS_SPLIT_SLOT_END)
MSCH_EVENT((" SPLIT_SLOT_END"));
if (type & WL_MSCH_RC_FLAGS_PRE_ONFIRE_DONE)
MSCH_EVENT((" PRE_ONFIRE_DONE"));
}
MSCH_EVENT(("\n"));
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("pre_start_time: %s",
dhd_mschdbg_display_time(p->pre_start_time_h, p->pre_start_time_l)));
MSCH_EVENT((", start_time: %s",
dhd_mschdbg_display_time(p->start_time_h, p->start_time_l)));
MSCH_EVENT((", end_time: %s\n",
dhd_mschdbg_display_time(p->end_time_h, p->end_time_l)));
if (p->p_timeslot && (p->timeslot_ptr == 0)) {
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("<%s timeslot>: 0x%08x\n", title, ntoh32(p->p_timeslot)));
} else
dhd_mschdbg_timeslot_profiler_event_data(sn, ver, title, data, p->timeslot_ptr,
(p->timeslot_ptr == 0));
}
static void
dhd_mschdbg_chan_ctxt_profiler_event_data(int sp, int ver, char *data, uint16 ptr, bool empty)
{
int sn = sp + 4;
msch_chan_ctxt_profiler_event_data_t *p =
(msch_chan_ctxt_profiler_event_data_t *)(data + ntoh16(ptr));
chanspec_t c;
char buf[CHANSPEC_STR_LEN];
MSCH_EVENT_HEAD(sp);
MSCH_EVENT(("<chan_ctxt>: "));
if (empty) {
MSCH_EVENT((" null\n"));
return;
}
else
MSCH_EVENT(("0x%08x (prev 0x%08x, next 0x%08x)\n",
ntoh32(p->p_chan_ctxt), ntoh32(p->p_prev), ntoh32(p->p_next)));
c = (chanspec_t)ntoh16(p->chanspec);
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("channel: %s, bf_sch_pending: %s, bf_skipped: %d\n",
wf_chspec_ntoa(c, buf), p->bf_sch_pending? "TRUE" : "FALSE",
ntoh32(p->bf_skipped_count)));
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("bf_link: prev 0x%08x, next 0x%08x\n",
ntoh32(p->bf_link_prev), ntoh32(p->bf_link_next)));
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("onchan_time: %s",
dhd_mschdbg_display_time(p->onchan_time_h, p->onchan_time_l)));
MSCH_EVENT((", actual_onchan_dur: %s",
dhd_mschdbg_display_time(p->actual_onchan_dur_h, p->actual_onchan_dur_l)));
MSCH_EVENT((", pend_onchan_dur: %s\n",
dhd_mschdbg_display_time(p->pend_onchan_dur_h, p->pend_onchan_dur_l)));
dhd_mschdbg_elem_list(sn, "req_entity", data, p->req_entity_list_ptr,
p->req_entity_list_cnt);
dhd_mschdbg_elem_list(sn, "bf_entity", data, p->bf_entity_list_ptr,
p->bf_entity_list_cnt);
}
static void
dhd_mschdbg_req_entity_profiler_event_data(int sp, int ver, char *data, uint16 ptr, bool empty)
{
int sn = sp + 4;
msch_req_entity_profiler_event_data_t *p =
(msch_req_entity_profiler_event_data_t *)(data + ntoh16(ptr));
char buf[CHANSPEC_STR_LEN];
chanspec_t c;
uint32 flags;
MSCH_EVENT_HEAD(sp);
MSCH_EVENT(("<req_entity>: "));
if (empty) {
MSCH_EVENT((" null\n"));
return;
}
else
MSCH_EVENT(("0x%08x (prev 0x%08x, next 0x%08x)\n",
ntoh32(p->p_req_entity), ntoh32(p->req_hdl_link_prev),
ntoh32(p->req_hdl_link_next)));
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("req_hdl: [0x%08x]\n", ntoh32(p->p_req_hdl)));
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("chan_ctxt_link: prev 0x%08x, next 0x%08x\n",
ntoh32(p->chan_ctxt_link_prev), ntoh32(p->chan_ctxt_link_next)));
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("rt_specific_link: prev 0x%08x, next 0x%08x\n",
ntoh32(p->rt_specific_link_prev), ntoh32(p->rt_specific_link_next)));
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("start_fixed_link: prev 0x%08x, next 0x%08x\n",
ntoh32(p->start_fixed_link_prev), ntoh32(p->start_fixed_link_next)));
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("both_flex_list: prev 0x%08x, next 0x%08x\n",
ntoh32(p->both_flex_list_prev), ntoh32(p->both_flex_list_next)));
c = (chanspec_t)ntoh16(p->chanspec);
MSCH_EVENT_HEAD(sn);
if (ver >= 2) {
MSCH_EVENT(("channel: %s, onchan Id %d, current chan Id %d, priority %d",
wf_chspec_ntoa(c, buf), ntoh16(p->onchan_chn_idx), ntoh16(p->cur_chn_idx),
ntoh16(p->priority)));
flags = ntoh32(p->flags);
if (flags & WL_MSCH_ENTITY_FLAG_MULTI_INSTANCE)
MSCH_EVENT((" : MULTI_INSTANCE\n"));
else
MSCH_EVENT(("\n"));
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("actual_start_time: %s, ",
dhd_mschdbg_display_time(p->actual_start_time_h, p->actual_start_time_l)));
MSCH_EVENT(("curts_fire_time: %s, ",
dhd_mschdbg_display_time(p->curts_fire_time_h, p->curts_fire_time_l)));
} else {
MSCH_EVENT(("channel: %s, priority %d, ", wf_chspec_ntoa(c, buf),
ntoh16(p->priority)));
}
MSCH_EVENT(("bf_last_serv_time: %s\n",
dhd_mschdbg_display_time(p->bf_last_serv_time_h, p->bf_last_serv_time_l)));
dhd_mschdbg_req_timing_profiler_event_data(sn, ver, "current", data, p->cur_slot_ptr,
(p->cur_slot_ptr == 0));
dhd_mschdbg_req_timing_profiler_event_data(sn, ver, "pending", data, p->pend_slot_ptr,
(p->pend_slot_ptr == 0));
if (p->p_chan_ctxt && (p->chan_ctxt_ptr == 0)) {
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("<chan_ctxt>: 0x%08x\n", ntoh32(p->p_chan_ctxt)));
}
else
dhd_mschdbg_chan_ctxt_profiler_event_data(sn, ver, data, p->chan_ctxt_ptr,
(p->chan_ctxt_ptr == 0));
}
static void
dhd_mschdbg_req_handle_profiler_event_data(int sp, int ver, char *data, uint16 ptr, bool empty)
{
int sn = sp + 4;
msch_req_handle_profiler_event_data_t *p =
(msch_req_handle_profiler_event_data_t *)(data + ntoh16(ptr));
uint32 flags;
MSCH_EVENT_HEAD(sp);
MSCH_EVENT(("<req_handle>: "));
if (empty) {
MSCH_EVENT((" null\n"));
return;
}
else
MSCH_EVENT(("0x%08x (prev 0x%08x, next 0x%08x)\n",
ntoh32(p->p_req_handle), ntoh32(p->p_prev), ntoh32(p->p_next)));
dhd_mschdbg_elem_list(sn, "req_entity", data, p->req_entity_list_ptr,
p->req_entity_list_cnt);
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("cb_func: [0x%08x], cb_func: [0x%08x]",
ntoh32(p->cb_func), ntoh32(p->cb_ctxt)));
if (ver < 2) {
MSCH_EVENT((", chan_cnt: %d", ntoh16(p->chan_cnt)));
}
flags = ntoh32(p->flags);
if (flags & WL_MSCH_REQ_HDL_FLAGS_NEW_REQ)
MSCH_EVENT((", NEW_REQ"));
MSCH_EVENT(("\n"));
dhd_mschdbg_req_param_profiler_event_data(sn, ver, data, p->req_param_ptr);
if (ver >= 2) {
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("req_time: %s\n",
dhd_mschdbg_display_time(p->req_time_h, p->req_time_l)));
MSCH_EVENT_HEAD(sn);
MSCH_EVENT(("chan_cnt: %d, chan idx %d, last chan idx %d\n",
ntoh16(p->chan_cnt), ntoh16(p->chan_idx), ntoh16(p->last_chan_idx)));
if (p->chanspec_list && p->chanspec_cnt) {
dhd_mschdbg_chanspec_list(sn, data, p->chanspec_list, p->chanspec_cnt);
}
}
}
static void
dhd_mschdbg_profiler_profiler_event_data(int sp, int ver, char *data, uint16 ptr)
{
msch_profiler_profiler_event_data_t *p =
(msch_profiler_profiler_event_data_t *)(data + ntoh16(ptr));
uint32 flags;
MSCH_EVENT_HEAD(sp);
MSCH_EVENT(("free list: req_hdl 0x%08x, req_entity 0x%08x,"
" chan_ctxt 0x%08x, chanspec 0x%08x\n",
ntoh32(p->free_req_hdl_list), ntoh32(p->free_req_entity_list),
ntoh32(p->free_chan_ctxt_list), ntoh32(p->free_chanspec_list)));
MSCH_EVENT_HEAD(sp);
MSCH_EVENT(("alloc count: chanspec %d, req_entity %d, req_hdl %d, "
"chan_ctxt %d, timeslot %d\n",
ntoh16(p->msch_chanspec_alloc_cnt), ntoh16(p->msch_req_entity_alloc_cnt),
ntoh16(p->msch_req_hdl_alloc_cnt), ntoh16(p->msch_chan_ctxt_alloc_cnt),
ntoh16(p->msch_timeslot_alloc_cnt)));
dhd_mschdbg_elem_list(sp, "req_hdl", data, p->msch_req_hdl_list_ptr,
p->msch_req_hdl_list_cnt);
dhd_mschdbg_elem_list(sp, "chan_ctxt", data, p->msch_chan_ctxt_list_ptr,
p->msch_chan_ctxt_list_cnt);
dhd_mschdbg_elem_list(sp, "req_timing", data, p->msch_req_timing_list_ptr,
p->msch_req_timing_list_cnt);
dhd_mschdbg_elem_list(sp, "start_fixed", data, p->msch_start_fixed_list_ptr,
p->msch_start_fixed_list_cnt);
dhd_mschdbg_elem_list(sp, "both_flex_req_entity", data,
p->msch_both_flex_req_entity_list_ptr,
p->msch_both_flex_req_entity_list_cnt);
dhd_mschdbg_elem_list(sp, "start_flex", data, p->msch_start_flex_list_ptr,
p->msch_start_flex_list_cnt);
dhd_mschdbg_elem_list(sp, "both_flex", data, p->msch_both_flex_list_ptr,
p->msch_both_flex_list_cnt);
if (p->p_cur_msch_timeslot && (p->cur_msch_timeslot_ptr == 0)) {
MSCH_EVENT_HEAD(sp);
MSCH_EVENT(("<cur_msch timeslot>: 0x%08x\n",
ntoh32(p->p_cur_msch_timeslot)));
} else
dhd_mschdbg_timeslot_profiler_event_data(sp, ver, "cur_msch", data,
p->cur_msch_timeslot_ptr, (p->cur_msch_timeslot_ptr == 0));
if (p->p_next_timeslot && (p->next_timeslot_ptr == 0)) {
MSCH_EVENT_HEAD(sp);
MSCH_EVENT(("<next timeslot>: 0x%08x\n",
ntoh32(p->p_next_timeslot)));
} else
dhd_mschdbg_timeslot_profiler_event_data(sp, ver, "next", data,
p->next_timeslot_ptr, (p->next_timeslot_ptr == 0));
MSCH_EVENT_HEAD(sp);
MSCH_EVENT(("ts_id: %d, ", ntoh32(p->ts_id)));
flags = ntoh32(p->flags);
if (flags & WL_MSCH_STATE_IN_TIEMR_CTXT)
MSCH_EVENT(("IN_TIEMR_CTXT, "));
if (flags & WL_MSCH_STATE_SCHD_PENDING)
MSCH_EVENT(("SCHD_PENDING, "));
MSCH_EVENT(("slotskip_flags: %d, cur_armed_timeslot: 0x%08x\n",
(ver >= 2)? ntoh32(p->slotskip_flag) : 0, ntoh32(p->cur_armed_timeslot)));
MSCH_EVENT_HEAD(sp);
MSCH_EVENT(("flex_list_cnt: %d, service_interval: %d, "
"max_lo_prio_interval: %d\n",
ntoh16(p->flex_list_cnt), ntoh32(p->service_interval),
ntoh32(p->max_lo_prio_interval)));
}
static void dhd_mschdbg_dump_data(dhd_pub_t *dhdp, void *raw_event_ptr, int type,
char *data, int len)
{
uint64 t = 0, tt = 0;
uint32 s = 0, ss = 0;
int wlc_index, ver;
ver = (type & WL_MSCH_PROFILER_VER_MASK) >> WL_MSCH_PROFILER_VER_SHIFT;
wlc_index = (type & WL_MSCH_PROFILER_WLINDEX_MASK) >> WL_MSCH_PROFILER_WLINDEX_SHIFT;
if (wlc_index >= 4)
return;
type &= WL_MSCH_PROFILER_TYPE_MASK;
if (type <= WL_MSCH_PROFILER_PROFILE_END) {
msch_profiler_event_data_t *pevent = (msch_profiler_event_data_t *)data;
tt = ((uint64)(ntoh32(pevent->time_hi)) << 32) | ntoh32(pevent->time_lo);
dhd_mschdbg_us_to_sec(pevent->time_hi, pevent->time_lo, &s, &ss);
}
if (lastMessages && (type != WL_MSCH_PROFILER_MESSAGE) &&
(type != WL_MSCH_PROFILER_EVENT_LOG)) {
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("\n"));
lastMessages = FALSE;
}
switch (type) {
case WL_MSCH_PROFILER_START:
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("%06d.%06d START\n", s, ss));
break;
case WL_MSCH_PROFILER_EXIT:
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("%06d.%06d EXIT\n", s, ss));
break;
case WL_MSCH_PROFILER_REQ:
{
msch_req_profiler_event_data_t *p = (msch_req_profiler_event_data_t *)data;
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("\n"));
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("===============================\n"));
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("%06d.%06d [wl%d] REGISTER:\n", s, ss, wlc_index));
dhd_mschdbg_req_param_profiler_event_data(4, ver, data, p->req_param_ptr);
dhd_mschdbg_chanspec_list(4, data, p->chanspec_ptr, p->chanspec_cnt);
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("===============================\n"));
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("\n"));
}
break;
case WL_MSCH_PROFILER_CALLBACK:
{
msch_callback_profiler_event_data_t *p =
(msch_callback_profiler_event_data_t *)data;
char buf[CHANSPEC_STR_LEN];
chanspec_t chanspec;
uint16 cbtype;
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("%06d.%06d [wl%d] CALLBACK: ", s, ss, wlc_index));
chanspec = (chanspec_t)ntoh16(p->chanspec);
MSCH_EVENT(("req_hdl[0x%08x], channel %s --",
ntoh32(p->p_req_hdl), wf_chspec_ntoa(chanspec, buf)));
cbtype = ntoh16(p->type);
if (cbtype & WL_MSCH_CT_ON_CHAN)
MSCH_EVENT((" ON_CHAN"));
if (cbtype & WL_MSCH_CT_OFF_CHAN)
MSCH_EVENT((" OFF_CHAN"));
if (cbtype & WL_MSCH_CT_REQ_START)
MSCH_EVENT((" REQ_START"));
if (cbtype & WL_MSCH_CT_REQ_END)
MSCH_EVENT((" REQ_END"));
if (cbtype & WL_MSCH_CT_SLOT_START)
MSCH_EVENT((" SLOT_START"));
if (cbtype & WL_MSCH_CT_SLOT_SKIP)
MSCH_EVENT((" SLOT_SKIP"));
if (cbtype & WL_MSCH_CT_SLOT_END)
MSCH_EVENT((" SLOT_END"));
if (cbtype & WL_MSCH_CT_OFF_CHAN_DONE)
MSCH_EVENT((" OFF_CHAN_DONE"));
if (cbtype & WL_MSCH_CT_PARTIAL)
MSCH_EVENT((" PARTIAL"));
if (cbtype & WL_MSCH_CT_PRE_ONCHAN)
MSCH_EVENT((" PRE_ONCHAN"));
if (cbtype & WL_MSCH_CT_PRE_REQ_START)
MSCH_EVENT((" PRE_REQ_START"));
if (cbtype & WL_MSCH_CT_REQ_START) {
req_start[wlc_index] = 1;
req_start_time[wlc_index] = tt;
} else if (cbtype & WL_MSCH_CT_REQ_END) {
if (req_start[wlc_index]) {
MSCH_EVENT((" : REQ duration %d",
(uint32)(tt - req_start_time[wlc_index])));
req_start[wlc_index] = 0;
}
}
if (cbtype & WL_MSCH_CT_SLOT_START) {
solt_chanspec[wlc_index] = p->chanspec;
solt_start_time[wlc_index] = tt;
} else if (cbtype & WL_MSCH_CT_SLOT_END) {
if (p->chanspec == solt_chanspec[wlc_index]) {
MSCH_EVENT((" : SLOT duration %d",
(uint32)(tt - solt_start_time[wlc_index])));
solt_chanspec[wlc_index] = 0;
}
}
MSCH_EVENT(("\n"));
if (cbtype & (WL_MSCH_CT_ON_CHAN | WL_MSCH_CT_SLOT_SKIP)) {
MSCH_EVENT_HEAD(4);
if (cbtype & WL_MSCH_CT_ON_CHAN) {
MSCH_EVENT(("ID %d onchan idx %d cur_chan_seq_start %s ",
ntoh32(p->timeslot_id), ntoh32(p->onchan_idx),
dhd_mschdbg_display_time(p->cur_chan_seq_start_time_h,
p->cur_chan_seq_start_time_l)));
}
t = ((uint64)(ntoh32(p->start_time_h)) << 32) |
ntoh32(p->start_time_l);
MSCH_EVENT(("start %s ",
dhd_mschdbg_display_time(p->start_time_h,
p->start_time_l)));
tt = ((uint64)(ntoh32(p->end_time_h)) << 32) | ntoh32(p->end_time_l);
MSCH_EVENT(("end %s duration %d\n",
dhd_mschdbg_display_time(p->end_time_h, p->end_time_l),
(p->end_time_h == 0xffffffff && p->end_time_l == 0xffffffff)?
-1 : (int)(tt - t)));
}
}
break;
case WL_MSCH_PROFILER_EVENT_LOG:
{
while (len >= (int)WL_MSCH_EVENT_LOG_HEAD_SIZE) {
msch_event_log_profiler_event_data_t *p =
(msch_event_log_profiler_event_data_t *)data;
/* TODO: How to parse MSCH if extended event tag is present ??? */
prcd_event_log_hdr_t hdr;
int size = WL_MSCH_EVENT_LOG_HEAD_SIZE + p->hdr.count * sizeof(uint32);
if (len < size || size > sizeof(msch_event_log_profiler_event_data_t)) {
break;
}
data += size;
len -= size;
dhd_mschdbg_us_to_sec(p->time_hi, p->time_lo, &s, &ss);
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("%06d.%06d [wl%d]: ", s, ss, p->hdr.tag));
bzero(&hdr, sizeof(hdr));
hdr.tag = EVENT_LOG_TAG_MSCHPROFILE;
hdr.count = p->hdr.count + 1;
/* exclude LSB 2 bits which indicate binary/non-binary data */
hdr.fmt_num = ntoh16(p->hdr.fmt_num) >> 2;
hdr.fmt_num_raw = ntoh16(p->hdr.fmt_num);
if (ntoh16(p->hdr.fmt_num) == DHD_OW_BI_RAW_EVENT_LOG_FMT) {
hdr.binary_payload = TRUE;
}
dhd_dbg_verboselog_printf(dhdp, &hdr, raw_event_ptr, p->data, 0, 0);
}
lastMessages = TRUE;
break;
}
case WL_MSCH_PROFILER_MESSAGE:
{
msch_message_profiler_event_data_t *p = (msch_message_profiler_event_data_t *)data;
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("%06d.%06d [wl%d]: %s", s, ss, wlc_index, p->message));
lastMessages = TRUE;
break;
}
case WL_MSCH_PROFILER_PROFILE_START:
profiler_start_time[wlc_index] = tt;
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("-------------------------------\n"));
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("%06d.%06d [wl%d] PROFILE DATA:\n", s, ss, wlc_index));
dhd_mschdbg_profiler_profiler_event_data(4, ver, data, 0);
break;
case WL_MSCH_PROFILER_PROFILE_END:
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("%06d.%06d [wl%d] PROFILE END: take time %d\n", s, ss,
wlc_index, (uint32)(tt - profiler_start_time[wlc_index])));
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("-------------------------------\n"));
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("\n"));
break;
case WL_MSCH_PROFILER_REQ_HANDLE:
dhd_mschdbg_req_handle_profiler_event_data(4, ver, data, 0, FALSE);
break;
case WL_MSCH_PROFILER_REQ_ENTITY:
dhd_mschdbg_req_entity_profiler_event_data(4, ver, data, 0, FALSE);
break;
case WL_MSCH_PROFILER_CHAN_CTXT:
dhd_mschdbg_chan_ctxt_profiler_event_data(4, ver, data, 0, FALSE);
break;
case WL_MSCH_PROFILER_REQ_TIMING:
dhd_mschdbg_req_timing_profiler_event_data(4, ver, "msch", data, 0, FALSE);
break;
default:
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("[wl%d] ERROR: unsupported EVENT reason code:%d; ",
wlc_index, type));
break;
}
}
void
wl_mschdbg_event_handler(dhd_pub_t *dhdp, void *raw_event_ptr, int type, void *data, int len)
{
head_log = "MSCH";
dhd_mschdbg_dump_data(dhdp, raw_event_ptr, type, (char *)data, len);
}
void
wl_mschdbg_verboselog_handler(dhd_pub_t *dhdp, void *raw_event_ptr, prcd_event_log_hdr_t *plog_hdr,
uint32 *log_ptr)
{
uint32 log_pyld_len;
head_log = "CONSOLE";
if (plog_hdr->count == 0) {
return;
}
log_pyld_len = (plog_hdr->count - 1) * DATA_UNIT_FOR_LOG_CNT;
if (plog_hdr->tag == EVENT_LOG_TAG_MSCHPROFILE) {
msch_event_log_profiler_event_data_t *p =
(msch_event_log_profiler_event_data_t *)log_ptr;
/* TODO: How to parse MSCH if extended event tag is present ??? */
prcd_event_log_hdr_t hdr;
uint32 s, ss;
if (log_pyld_len < OFFSETOF(msch_event_log_profiler_event_data_t, data) ||
log_pyld_len > sizeof(msch_event_log_profiler_event_data_t)) {
return;
}
dhd_mschdbg_us_to_sec(p->time_hi, p->time_lo, &s, &ss);
MSCH_EVENT_HEAD(0);
MSCH_EVENT(("%06d.%06d [wl%d]: ", s, ss, p->hdr.tag));
bzero(&hdr, sizeof(hdr));
hdr.tag = EVENT_LOG_TAG_MSCHPROFILE;
hdr.count = p->hdr.count + 1;
/* exclude LSB 2 bits which indicate binary/non-binary data */
hdr.fmt_num = ntoh16(p->hdr.fmt_num) >> 2;
hdr.fmt_num_raw = ntoh16(p->hdr.fmt_num);
if (ntoh16(p->hdr.fmt_num) == DHD_OW_BI_RAW_EVENT_LOG_FMT) {
hdr.binary_payload = TRUE;
}
dhd_dbg_verboselog_printf(dhdp, &hdr, raw_event_ptr, p->data, 0, 0);
} else {
msch_collect_tlv_t *p = (msch_collect_tlv_t *)log_ptr;
int type = ntoh16(p->type);
int len = ntoh16(p->size);
if (log_pyld_len < OFFSETOF(msch_collect_tlv_t, value) + len) {
return;
}
dhd_mschdbg_dump_data(dhdp, raw_event_ptr, type, p->value, len);
}
}
#endif /* SHOW_LOGTRACE */

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,602 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Linux DHD Bus Module for PCIE
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_pcie.h 816392 2019-04-24 14:39:02Z $
*/
#ifndef dhd_pcie_h
#define dhd_pcie_h
#include <bcmpcie.h>
#include <hnd_cons.h>
/* defines */
#define PCIE_SHARED_VERSION PCIE_SHARED_VERSION_7
#define PCMSGBUF_HDRLEN 0
#define DONGLE_REG_MAP_SIZE (32 * 1024)
#define DONGLE_TCM_MAP_SIZE (4096 * 1024)
#define DONGLE_MIN_MEMSIZE (128 *1024)
#ifdef DHD_DEBUG
#define DHD_PCIE_SUCCESS 0
#define DHD_PCIE_FAILURE 1
#endif /* DHD_DEBUG */
#define REMAP_ENAB(bus) ((bus)->remap)
#define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize)))
#define MAX_DHD_TX_FLOWS 320
/* user defined data structures */
/* Device console log buffer state */
#define CONSOLE_LINE_MAX 192u
#define CONSOLE_BUFFER_MAX (8 * 1024)
#ifdef IDLE_TX_FLOW_MGMT
#define IDLE_FLOW_LIST_TIMEOUT 5000
#define IDLE_FLOW_RING_TIMEOUT 5000
#endif /* IDLE_TX_FLOW_MGMT */
/* HWA enabled and inited */
#define HWA_ACTIVE(dhd) (((dhd)->hwa_enable) && ((dhd)->hwa_inited))
/* implicit DMA for h2d wr and d2h rd indice from Host memory to TCM */
#define IDMA_ENAB(dhd) ((dhd)->idma_enable)
#define IDMA_ACTIVE(dhd) (((dhd)->idma_enable) && ((dhd)->idma_inited))
#define IDMA_CAPABLE(bus) (((bus)->sih->buscorerev == 19) || ((bus)->sih->buscorerev >= 23))
/* IFRM (Implicit Flow Ring Manager enable and inited */
#define IFRM_ENAB(dhd) ((dhd)->ifrm_enable)
#define IFRM_ACTIVE(dhd) (((dhd)->ifrm_enable) && ((dhd)->ifrm_inited))
/* DAR registers use for h2d doorbell */
#define DAR_ENAB(dhd) ((dhd)->dar_enable)
#define DAR_ACTIVE(dhd) (((dhd)->dar_enable) && ((dhd)->dar_inited))
/* DAR WAR for revs < 64 */
#define DAR_PWRREQ(bus) (((bus)->_dar_war) && DAR_ACTIVE((bus)->dhd))
/* PCIE CTO Prevention and Recovery */
#define PCIECTO_ENAB(bus) ((bus)->cto_enable)
/* Implicit DMA index usage :
* Index 0 for h2d write index transfer
* Index 1 for d2h read index transfer
*/
#define IDMA_IDX0 0
#define IDMA_IDX1 1
#define IDMA_IDX2 2
#define IDMA_IDX3 3
#define DMA_TYPE_SHIFT 4
#define DMA_TYPE_IDMA 1
#define DHDPCIE_CONFIG_HDR_SIZE 16
#define DHDPCIE_CONFIG_CHECK_DELAY_MS 10 /* 10ms */
#define DHDPCIE_CONFIG_CHECK_RETRY_COUNT 20
#define DHDPCIE_DONGLE_PWR_TOGGLE_DELAY 1000 /* 1ms in units of us */
#define DHDPCIE_PM_D3_DELAY 200000 /* 200ms in units of us */
#define DHDPCIE_PM_D2_DELAY 200 /* 200us */
typedef struct dhd_console {
uint count; /* Poll interval msec counter */
uint log_addr; /* Log struct address (fixed) */
hnd_log_t log; /* Log struct (host copy) */
uint bufsize; /* Size of log buffer */
uint8 *buf; /* Log buffer (host copy) */
uint last; /* Last buffer read index */
} dhd_console_t;
typedef struct ring_sh_info {
uint32 ring_mem_addr;
uint32 ring_state_w;
uint32 ring_state_r;
} ring_sh_info_t;
#define DEVICE_WAKE_NONE 0
#define DEVICE_WAKE_OOB 1
#define DEVICE_WAKE_INB 2
#define INBAND_DW_ENAB(bus) ((bus)->dw_option == DEVICE_WAKE_INB)
#define OOB_DW_ENAB(bus) ((bus)->dw_option == DEVICE_WAKE_OOB)
#define NO_DW_ENAB(bus) ((bus)->dw_option == DEVICE_WAKE_NONE)
#define PCIE_RELOAD_WAR_ENAB(buscorerev) \
((buscorerev == 66) || (buscorerev == 67) || (buscorerev == 68) || (buscorerev == 70))
/*
* HW JIRA - CRWLPCIEGEN2-672
* Producer Index Feature which is used by F1 gets reset on F0 FLR
* fixed in REV68
*/
#define PCIE_ENUM_RESET_WAR_ENAB(buscorerev) \
((buscorerev == 66) || (buscorerev == 67))
struct dhd_bus;
struct dhd_pcie_rev {
uint8 fw_rev;
void (*handle_mb_data)(struct dhd_bus *);
};
typedef struct dhdpcie_config_save
{
uint32 header[DHDPCIE_CONFIG_HDR_SIZE];
/* pmcsr save */
uint32 pmcsr;
/* express save */
uint32 exp_dev_ctrl_stat;
uint32 exp_link_ctrl_stat;
uint32 exp_dev_ctrl_stat2;
uint32 exp_link_ctrl_stat2;
/* msi save */
uint32 msi_cap;
uint32 msi_addr0;
uint32 msi_addr1;
uint32 msi_data;
/* l1pm save */
uint32 l1pm0;
uint32 l1pm1;
/* ltr save */
uint32 ltr;
/* aer save */
uint32 aer_caps_ctrl; /* 0x18 */
uint32 aer_severity; /* 0x0C */
uint32 aer_umask; /* 0x08 */
uint32 aer_cmask; /* 0x14 */
uint32 aer_root_cmd; /* 0x2c */
/* BAR0 and BAR1 windows */
uint32 bar0_win;
uint32 bar1_win;
} dhdpcie_config_save_t;
/* The level of bus communication with the dongle */
enum dhd_bus_low_power_state {
DHD_BUS_NO_LOW_POWER_STATE, /* Not in low power state */
DHD_BUS_D3_INFORM_SENT, /* D3 INFORM sent */
DHD_BUS_D3_ACK_RECIEVED, /* D3 ACK recieved */
};
/** 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 */
struct pci_dev *rc_dev; /* pci RC device handle */
struct pci_dev *dev; /* pci device handle */
dll_t flowring_active_list; /* constructed list of tx flowring queues */
#ifdef IDLE_TX_FLOW_MGMT
uint64 active_list_last_process_ts;
/* stores the timestamp of active list processing */
#endif /* IDLE_TX_FLOW_MGMT */
si_t *sih; /* Handle for SI calls */
char *vars; /* Variables (from CIS and/or other) */
uint varsz; /* Size of variables buffer */
uint32 sbaddr; /* Current SB window pointer (-1, invalid) */
sbpcieregs_t *reg; /* Registers for PCIE core */
uint armrev; /* CPU core revision */
uint coreid; /* CPU core id */
uint ramrev; /* SOCRAM core revision */
uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */
uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
bool ramsize_adjusted; /* flag to note adjustment, so that
* adjustment routine and file io
* are avoided on D3 cold -> D0
*/
uint32 srmemsize; /* Size of SRMEM */
uint32 bus; /* gSPI or SDIO bus */
uint32 intstatus; /* Intstatus bits (events) pending */
bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
bool fcstate; /* State of dongle flow-control */
uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */
char *fw_path; /* module_param: path to firmware image */
char *nv_path; /* module_param: path to nvram vars file */
struct pktq txq; /* Queue length used for flow-control */
bool intr; /* Use interrupts */
bool poll; /* Use polling */
bool ipend; /* Device interrupt is pending */
bool intdis; /* Interrupts disabled by isr */
uint intrcount; /* Count of device interrupt callbacks */
uint lastintrs; /* Count as of last watchdog timer */
dhd_console_t console; /* Console output polling support */
uint console_addr; /* Console address from shared struct */
bool alp_only; /* Don't use HT clock (ALP only) */
bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram
* Available with socram rev 16
* Remap region not DMA-able
*/
uint32 resetinstr;
uint32 dongle_ram_base;
ulong shared_addr;
pciedev_shared_t *pcie_sh;
uint32 dma_rxoffset;
volatile char *regs; /* pci device memory va */
volatile char *tcm; /* pci device memory va */
osl_t *osh;
uint32 nvram_csm; /* Nvram checksum */
uint16 pollrate;
uint16 polltick;
volatile uint32 *pcie_mb_intr_addr;
volatile uint32 *pcie_mb_intr_2_addr;
void *pcie_mb_intr_osh;
bool sleep_allowed;
wake_counts_t wake_counts;
/* version 3 shared struct related info start */
ring_sh_info_t ring_sh[BCMPCIE_COMMON_MSGRINGS + MAX_DHD_TX_FLOWS];
uint8 h2d_ring_count;
uint8 d2h_ring_count;
uint32 ringmem_ptr;
uint32 ring_state_ptr;
uint32 d2h_dma_scratch_buffer_mem_addr;
uint32 h2d_mb_data_ptr_addr;
uint32 d2h_mb_data_ptr_addr;
/* version 3 shared struct related info end */
uint32 def_intmask;
uint32 d2h_mb_mask;
uint32 pcie_mailbox_mask;
uint32 pcie_mailbox_int;
bool ltrsleep_on_unload;
uint wait_for_d3_ack;
uint16 max_tx_flowrings;
uint16 max_submission_rings;
uint16 max_completion_rings;
uint16 max_cmn_rings;
uint32 rw_index_sz;
bool db1_for_mb;
dhd_timeout_t doorbell_timer;
bool device_wake_state;
bool irq_registered;
bool d2h_intr_method;
int32 idletime; /* Control for activity timeout */
uint32 d3_inform_cnt;
uint32 d0_inform_cnt;
uint32 d0_inform_in_use_cnt;
uint8 force_suspend;
uint8 is_linkdown;
uint8 no_bus_init;
#ifdef IDLE_TX_FLOW_MGMT
bool enable_idle_flowring_mgmt;
#endif /* IDLE_TX_FLOW_MGMT */
struct dhd_pcie_rev api;
bool use_mailbox;
bool use_d0_inform;
void *bus_lock;
void *backplane_access_lock;
enum dhd_bus_low_power_state bus_low_power_state;
uint32 hostready_count; /* Number of hostready issued */
#if defined(BCMPCIE_OOB_HOST_WAKE)
bool oob_presuspend;
#endif // endif
dhdpcie_config_save_t saved_config;
ulong resume_intr_enable_count;
ulong dpc_intr_enable_count;
ulong isr_intr_disable_count;
ulong suspend_intr_disable_count;
ulong dpc_return_busdown_count;
ulong non_ours_irq_count;
#ifdef BCMPCIE_OOB_HOST_WAKE
ulong oob_intr_count;
ulong oob_intr_enable_count;
ulong oob_intr_disable_count;
uint64 last_oob_irq_time;
uint64 last_oob_irq_enable_time;
uint64 last_oob_irq_disable_time;
#endif /* BCMPCIE_OOB_HOST_WAKE */
uint64 isr_entry_time;
uint64 isr_exit_time;
uint64 dpc_sched_time;
uint64 dpc_entry_time;
uint64 dpc_exit_time;
uint64 resched_dpc_time;
uint64 last_d3_inform_time;
uint64 last_process_ctrlbuf_time;
uint64 last_process_flowring_time;
uint64 last_process_txcpl_time;
uint64 last_process_rxcpl_time;
uint64 last_process_infocpl_time;
uint64 last_process_edl_time;
uint64 last_suspend_start_time;
uint64 last_suspend_end_time;
uint64 last_resume_start_time;
uint64 last_resume_end_time;
uint64 last_non_ours_irq_time;
uint8 hwa_enab_bmap;
bool idma_enabled;
bool ifrm_enabled;
bool dar_enabled;
uint32 dmaxfer_complete;
uint8 dw_option;
bool _dar_war;
uint8 dma_chan;
bool cto_enable; /* enable PCIE CTO Prevention and recovery */
uint32 cto_threshold; /* PCIE CTO timeout threshold */
bool cto_triggered; /* CTO is triggered */
int pwr_req_ref;
bool flr_force_fail; /* user intends to simulate flr force fail */
bool intr_enabled; /* ready to receive interrupts from dongle */
bool force_bt_quiesce; /* send bt_quiesce command to BT driver. */
#if defined(DHD_H2D_LOG_TIME_SYNC)
ulong dhd_rte_time_sync_count; /* OSL_SYSUPTIME_US() */
#endif /* DHD_H2D_LOG_TIME_SYNC */
bool rc_ep_aspm_cap; /* RC and EP ASPM capable */
bool rc_ep_l1ss_cap; /* EC and EP L1SS capable */
uint16 hp2p_txcpl_max_items;
uint16 hp2p_rxcpl_max_items;
/* PCIE coherent status */
uint32 coherent_state;
} dhd_bus_t;
#ifdef DHD_MSI_SUPPORT
extern uint enable_msi;
#endif /* DHD_MSI_SUPPORT */
enum {
PCIE_INTX = 0,
PCIE_MSI = 1
};
/* function declarations */
extern uint32* dhdpcie_bus_reg_map(osl_t *osh, ulong addr, int size);
extern int dhdpcie_bus_register(void);
extern void dhdpcie_bus_unregister(void);
extern bool dhdpcie_chipmatch(uint16 vendor, uint16 device);
extern int dhdpcie_bus_attach(osl_t *osh, dhd_bus_t **bus_ptr,
volatile char *regs, volatile char *tcm, void *pci_dev);
extern uint32 dhdpcie_bus_cfg_read_dword(struct dhd_bus *bus, uint32 addr, uint32 size);
extern void dhdpcie_bus_cfg_write_dword(struct dhd_bus *bus, uint32 addr, uint32 size, uint32 data);
extern void dhdpcie_bus_intr_enable(struct dhd_bus *bus);
extern void dhdpcie_bus_intr_disable(struct dhd_bus *bus);
extern int dhpcie_bus_mask_interrupt(dhd_bus_t *bus);
extern void dhdpcie_bus_release(struct dhd_bus *bus);
extern int32 dhdpcie_bus_isr(struct dhd_bus *bus);
extern void dhdpcie_free_irq(dhd_bus_t *bus);
extern void dhdpcie_bus_ringbell_fast(struct dhd_bus *bus, uint32 value);
extern void dhdpcie_bus_ringbell_2_fast(struct dhd_bus *bus, uint32 value, bool devwake);
extern void dhdpcie_dongle_reset(dhd_bus_t *bus);
#ifdef DHD_PCIE_NATIVE_RUNTIMEPM
extern int dhdpcie_bus_suspend(struct dhd_bus *bus, bool state, bool byint);
#else
extern int dhdpcie_bus_suspend(struct dhd_bus *bus, bool state);
#endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
extern int dhdpcie_pci_suspend_resume(struct dhd_bus *bus, bool state);
extern uint32 dhdpcie_force_alp(struct dhd_bus *bus, bool enable);
extern uint32 dhdpcie_set_l1_entry_time(struct dhd_bus *bus, int force_l1_entry_time);
extern bool dhdpcie_tcm_valid(dhd_bus_t *bus);
extern void dhdpcie_pme_active(osl_t *osh, bool enable);
extern bool dhdpcie_pme_cap(osl_t *osh);
extern uint32 dhdpcie_lcreg(osl_t *osh, uint32 mask, uint32 val);
extern void dhdpcie_set_pmu_min_res_mask(struct dhd_bus *bus, uint min_res_mask);
extern uint8 dhdpcie_clkreq(osl_t *osh, uint32 mask, uint32 val);
extern int dhdpcie_disable_irq(dhd_bus_t *bus);
extern int dhdpcie_disable_irq_nosync(dhd_bus_t *bus);
extern int dhdpcie_enable_irq(dhd_bus_t *bus);
extern void dhd_bus_dump_dar_registers(struct dhd_bus *bus);
extern uint32 dhdpcie_rc_config_read(dhd_bus_t *bus, uint offset);
extern uint32 dhdpcie_rc_access_cap(dhd_bus_t *bus, int cap, uint offset, bool is_ext,
bool is_write, uint32 writeval);
extern uint32 dhdpcie_ep_access_cap(dhd_bus_t *bus, int cap, uint offset, bool is_ext,
bool is_write, uint32 writeval);
extern uint32 dhd_debug_get_rc_linkcap(dhd_bus_t *bus);
extern int dhdpcie_start_host_pcieclock(dhd_bus_t *bus);
extern int dhdpcie_stop_host_pcieclock(dhd_bus_t *bus);
extern int dhdpcie_disable_device(dhd_bus_t *bus);
extern int dhdpcie_alloc_resource(dhd_bus_t *bus);
extern void dhdpcie_free_resource(dhd_bus_t *bus);
extern void dhdpcie_dump_resource(dhd_bus_t *bus);
extern int dhdpcie_bus_request_irq(struct dhd_bus *bus);
void dhdpcie_os_setbar1win(dhd_bus_t *bus, uint32 addr);
void dhdpcie_os_wtcm8(dhd_bus_t *bus, ulong offset, uint8 data);
uint8 dhdpcie_os_rtcm8(dhd_bus_t *bus, ulong offset);
void dhdpcie_os_wtcm16(dhd_bus_t *bus, ulong offset, uint16 data);
uint16 dhdpcie_os_rtcm16(dhd_bus_t *bus, ulong offset);
void dhdpcie_os_wtcm32(dhd_bus_t *bus, ulong offset, uint32 data);
uint32 dhdpcie_os_rtcm32(dhd_bus_t *bus, ulong offset);
#ifdef DHD_SUPPORT_64BIT
void dhdpcie_os_wtcm64(dhd_bus_t *bus, ulong offset, uint64 data);
uint64 dhdpcie_os_rtcm64(dhd_bus_t *bus, ulong offset);
#endif // endif
extern int dhdpcie_enable_device(dhd_bus_t *bus);
#ifdef BCMPCIE_OOB_HOST_WAKE
extern int dhdpcie_oob_intr_register(dhd_bus_t *bus);
extern void dhdpcie_oob_intr_unregister(dhd_bus_t *bus);
extern void dhdpcie_oob_intr_set(dhd_bus_t *bus, bool enable);
extern int dhdpcie_get_oob_irq_num(struct dhd_bus *bus);
extern int dhdpcie_get_oob_irq_status(struct dhd_bus *bus);
extern int dhdpcie_get_oob_irq_level(void);
#endif /* BCMPCIE_OOB_HOST_WAKE */
#if defined(CONFIG_ARCH_EXYNOS)
#define SAMSUNG_PCIE_VENDOR_ID 0x144d
#if defined(CONFIG_MACH_UNIVERSAL7420) || defined(CONFIG_SOC_EXYNOS7420)
#define SAMSUNG_PCIE_DEVICE_ID 0xa575
#define SAMSUNG_PCIE_CH_NUM 1
#elif defined(CONFIG_SOC_EXYNOS8890)
#define SAMSUNG_PCIE_DEVICE_ID 0xa544
#define SAMSUNG_PCIE_CH_NUM 0
#elif defined(CONFIG_SOC_EXYNOS8895) || defined(CONFIG_SOC_EXYNOS9810) || \
defined(CONFIG_SOC_EXYNOS9820)
#define SAMSUNG_PCIE_DEVICE_ID 0xecec
#define SAMSUNG_PCIE_CH_NUM 0
#else
#error "Not supported platform"
#endif /* CONFIG_SOC_EXYNOSXXXX & CONFIG_MACH_UNIVERSALXXXX */
#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)
#define MSM_PCIE_DEVICE_ID 0x0106
#else
#error "Not supported platform"
#endif // 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 */
#define HIKEY_PCIE_VENDOR_ID 0x19e5
#define HIKEY_PCIE_DEVICE_ID 0x3660
#define DUMMY_PCIE_VENDOR_ID 0xffff
#define DUMMY_PCIE_DEVICE_ID 0xffff
#if defined(CONFIG_ARCH_EXYNOS)
#define PCIE_RC_VENDOR_ID SAMSUNG_PCIE_VENDOR_ID
#define PCIE_RC_DEVICE_ID SAMSUNG_PCIE_DEVICE_ID
#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
#else
#define PCIE_RC_VENDOR_ID HIKEY_PCIE_VENDOR_ID
#define PCIE_RC_DEVICE_ID HIKEY_PCIE_DEVICE_ID
#endif /* CONFIG_ARCH_EXYNOS */
#define DHD_REGULAR_RING 0
#define DHD_HP2P_RING 1
#ifdef USE_EXYNOS_PCIE_RC_PMPATCH
extern int exynos_pcie_pm_suspend(int ch_num);
extern int exynos_pcie_pm_resume(int ch_num);
#endif /* USE_EXYNOS_PCIE_RC_PMPATCH */
#ifdef CONFIG_ARCH_TEGRA
extern int tegra_pcie_pm_suspend(void);
extern int tegra_pcie_pm_resume(void);
#endif /* CONFIG_ARCH_TEGRA */
extern int dhd_buzzz_dump_dngl(dhd_bus_t *bus);
#ifdef IDLE_TX_FLOW_MGMT
extern int dhd_bus_flow_ring_resume_request(struct dhd_bus *bus, void *arg);
extern void dhd_bus_flow_ring_resume_response(struct dhd_bus *bus, uint16 flowid, int32 status);
extern int dhd_bus_flow_ring_suspend_request(struct dhd_bus *bus, void *arg);
extern void dhd_bus_flow_ring_suspend_response(struct dhd_bus *bus, uint16 flowid, uint32 status);
extern void dhd_flow_ring_move_to_active_list_head(struct dhd_bus *bus,
flow_ring_node_t *flow_ring_node);
extern void dhd_flow_ring_add_to_active_list(struct dhd_bus *bus,
flow_ring_node_t *flow_ring_node);
extern void dhd_flow_ring_delete_from_active_list(struct dhd_bus *bus,
flow_ring_node_t *flow_ring_node);
extern void __dhd_flow_ring_delete_from_active_list(struct dhd_bus *bus,
flow_ring_node_t *flow_ring_node);
#endif /* IDLE_TX_FLOW_MGMT */
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);
#endif /* DHD_WAKE_STATUS */
extern bool dhdpcie_bus_get_pcie_hostready_supported(dhd_bus_t *bus);
extern void dhd_bus_hostready(struct dhd_bus *bus);
extern void dhdpcie_bus_enab_pcie_dw(dhd_bus_t *bus, uint8 dw_option);
extern int dhdpcie_irq_disabled(struct dhd_bus *bus);
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; }
int dhdpcie_config_check(dhd_bus_t *bus);
int dhdpcie_config_restore(dhd_bus_t *bus, bool restore_pmcsr);
int dhdpcie_config_save(dhd_bus_t *bus);
int dhdpcie_set_pwr_state(dhd_bus_t *bus, uint state);
extern bool dhdpcie_bus_get_pcie_hwa_supported(dhd_bus_t *bus);
extern bool dhdpcie_bus_get_pcie_idma_supported(dhd_bus_t *bus);
extern bool dhdpcie_bus_get_pcie_ifrm_supported(dhd_bus_t *bus);
extern bool dhdpcie_bus_get_pcie_dar_supported(dhd_bus_t *bus);
static INLINE uint32
dhd_pcie_config_read(osl_t *osh, uint offset, uint size)
{
OSL_DELAY(100);
return OSL_PCI_READ_CONFIG(osh, offset, size);
}
static INLINE uint32
dhd_pcie_corereg_read(si_t *sih, uint val)
{
OSL_DELAY(100);
si_corereg(sih, sih->buscoreidx, OFFSETOF(sbpcieregs_t, configaddr), ~0, val);
return si_corereg(sih, sih->buscoreidx, OFFSETOF(sbpcieregs_t, configdata), 0, 0);
}
extern int dhdpcie_get_fwpath_otp(dhd_bus_t *bus, char *fw_path, char *nv_path,
char *clm_path, char *txcap_path);
extern int dhd_pcie_debug_info_dump(dhd_pub_t *dhd);
extern void dhd_pcie_intr_count_dump(dhd_pub_t *dhd);
extern void dhdpcie_bus_clear_intstatus(dhd_bus_t *bus);
#ifdef DHD_HP2P
extern uint16 dhd_bus_get_hp2p_ring_max_size(dhd_bus_t *bus, bool tx);
#endif // endif
#endif /* dhd_pcie_h */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,585 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Header file of Broadcom Dongle Host Driver (DHD)
* Prefered Network Offload code and Wi-Fi Location Service(WLS) code.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_pno.h 805174 2019-02-15 17:26:01Z $
*/
#ifndef __DHD_PNO_H__
#define __DHD_PNO_H__
#if defined(PNO_SUPPORT)
#define PNO_TLV_PREFIX 'S'
#define PNO_TLV_VERSION '1'
#define PNO_TLV_SUBTYPE_LEGACY_PNO '2'
#define PNO_TLV_RESERVED '0'
#define PNO_BATCHING_SET "SET"
#define PNO_BATCHING_GET "GET"
#define PNO_BATCHING_STOP "STOP"
#define PNO_PARAMS_DELIMETER " "
#define PNO_PARAM_CHANNEL_DELIMETER ","
#define PNO_PARAM_VALUE_DELLIMETER '='
#define PNO_PARAM_SCANFREQ "SCANFREQ"
#define PNO_PARAM_BESTN "BESTN"
#define PNO_PARAM_MSCAN "MSCAN"
#define PNO_PARAM_CHANNEL "CHANNEL"
#define PNO_PARAM_RTT "RTT"
#define PNO_TLV_TYPE_SSID_IE 'S'
#define PNO_TLV_TYPE_TIME 'T'
#define PNO_TLV_FREQ_REPEAT 'R'
#define PNO_TLV_FREQ_EXPO_MAX 'M'
#define MAXNUM_SSID_PER_ADD 16
#define MAXNUM_PNO_PARAMS 2
#define PNO_TLV_COMMON_LENGTH 1
#define DEFAULT_BATCH_MSCAN 16
#define RESULTS_END_MARKER "----\n"
#define SCAN_END_MARKER "####\n"
#define AP_END_MARKER "====\n"
#define PNO_RSSI_MARGIN_DBM 30
#define CSCAN_COMMAND "CSCAN "
#define CSCAN_TLV_PREFIX 'S'
#define CSCAN_TLV_VERSION 1
#define CSCAN_TLV_SUBVERSION 0
#define CSCAN_TLV_TYPE_SSID_IE 'S'
#define CSCAN_TLV_TYPE_CHANNEL_IE 'C'
#define CSCAN_TLV_TYPE_NPROBE_IE 'N'
#define CSCAN_TLV_TYPE_ACTIVE_IE 'A'
#define CSCAN_TLV_TYPE_PASSIVE_IE 'P'
#define CSCAN_TLV_TYPE_HOME_IE 'H'
#define CSCAN_TLV_TYPE_STYPE_IE 'T'
#define WL_SCAN_PARAMS_SSID_MAX 10
#define GET_SSID "SSID="
#define GET_CHANNEL "CH="
#define GET_NPROBE "NPROBE="
#define GET_ACTIVE_ASSOC_DWELL "ACTIVE="
#define GET_PASSIVE_ASSOC_DWELL "PASSIVE="
#define GET_HOME_DWELL "HOME="
#define GET_SCAN_TYPE "TYPE="
#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
#define GSCAN_MAX_CH_BUCKETS 8
#define GSCAN_MAX_CHANNELS_IN_BUCKET 32
#define GSCAN_MAX_AP_CACHE_PER_SCAN 32
#define GSCAN_MAX_AP_CACHE 320
#define GSCAN_BG_BAND_MASK (1 << 0)
#define GSCAN_A_BAND_MASK (1 << 1)
#define GSCAN_DFS_MASK (1 << 2)
#define GSCAN_ABG_BAND_MASK (GSCAN_A_BAND_MASK | GSCAN_BG_BAND_MASK)
#define GSCAN_BAND_MASK (GSCAN_ABG_BAND_MASK | GSCAN_DFS_MASK)
#define GSCAN_FLUSH_HOTLIST_CFG (1 << 0)
#define GSCAN_FLUSH_SIGNIFICANT_CFG (1 << 1)
#define GSCAN_FLUSH_SCAN_CFG (1 << 2)
#define GSCAN_FLUSH_EPNO_CFG (1 << 3)
#define GSCAN_FLUSH_ALL_CFG (GSCAN_FLUSH_SCAN_CFG | \
GSCAN_FLUSH_SIGNIFICANT_CFG | \
GSCAN_FLUSH_HOTLIST_CFG | \
GSCAN_FLUSH_EPNO_CFG)
#define DHD_EPNO_HIDDEN_SSID (1 << 0)
#define DHD_EPNO_A_BAND_TRIG (1 << 1)
#define DHD_EPNO_BG_BAND_TRIG (1 << 2)
#define DHD_EPNO_STRICT_MATCH (1 << 3)
#define DHD_EPNO_SAME_NETWORK (1 << 4)
#define DHD_PNO_USE_SSID (DHD_EPNO_HIDDEN_SSID | DHD_EPNO_STRICT_MATCH)
/* Do not change GSCAN_BATCH_RETRIEVAL_COMPLETE */
#define GSCAN_BATCH_RETRIEVAL_COMPLETE 0
#define GSCAN_BATCH_RETRIEVAL_IN_PROGRESS 1
#define GSCAN_BATCH_NO_THR_SET 101
#define GSCAN_LOST_AP_WINDOW_DEFAULT 4
#define GSCAN_MIN_BSSID_TIMEOUT 90
#define GSCAN_BATCH_GET_MAX_WAIT 500
#define CHANNEL_BUCKET_EMPTY_INDEX 0xFFFF
#define GSCAN_RETRY_THRESHOLD 3
#define MAX_EPNO_SSID_NUM 64
#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
enum scan_status {
/* SCAN ABORT by other scan */
PNO_STATUS_ABORT,
/* RTT is presence or not */
PNO_STATUS_RTT_PRESENCE,
/* Disable PNO by Driver */
PNO_STATUS_DISABLE,
/* NORMAL BATCHING GET */
PNO_STATUS_NORMAL,
/* WLC_E_PFN_BEST_BATCHING */
PNO_STATUS_EVENT,
PNO_STATUS_MAX
};
#define PNO_STATUS_ABORT_MASK 0x0001
#define PNO_STATUS_RTT_MASK 0x0002
#define PNO_STATUS_DISABLE_MASK 0x0004
#define PNO_STATUS_OOM_MASK 0x0010
enum index_mode {
INDEX_OF_LEGACY_PARAMS,
INDEX_OF_BATCH_PARAMS,
INDEX_OF_HOTLIST_PARAMS,
/* GSCAN includes hotlist scan and they do not run
* independent of each other
*/
INDEX_OF_GSCAN_PARAMS = INDEX_OF_HOTLIST_PARAMS,
INDEX_MODE_MAX
};
enum dhd_pno_status {
DHD_PNO_DISABLED,
DHD_PNO_ENABLED,
DHD_PNO_SUSPEND
};
typedef struct cmd_tlv {
char prefix;
char version;
char subtype;
char reserved;
} cmd_tlv_t;
#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
typedef enum {
WIFI_BAND_UNSPECIFIED,
WIFI_BAND_BG = 1, /* 2.4 GHz */
WIFI_BAND_A = 2, /* 5 GHz without DFS */
WIFI_BAND_A_DFS = 4, /* 5 GHz DFS only */
WIFI_BAND_A_WITH_DFS = 6, /* 5 GHz with DFS */
WIFI_BAND_ABG = 3, /* 2.4 GHz + 5 GHz; no DFS */
WIFI_BAND_ABG_WITH_DFS = 7, /* 2.4 GHz + 5 GHz with DFS */
} gscan_wifi_band_t;
typedef enum {
HOTLIST_LOST,
HOTLIST_FOUND
} hotlist_type_t;
typedef enum dhd_pno_gscan_cmd_cfg {
DHD_PNO_BATCH_SCAN_CFG_ID = 0,
DHD_PNO_GEOFENCE_SCAN_CFG_ID,
DHD_PNO_SIGNIFICANT_SCAN_CFG_ID,
DHD_PNO_SCAN_CFG_ID,
DHD_PNO_GET_CAPABILITIES,
DHD_PNO_GET_BATCH_RESULTS,
DHD_PNO_GET_CHANNEL_LIST,
DHD_PNO_GET_NEW_EPNO_SSID_ELEM,
DHD_PNO_EPNO_CFG_ID,
DHD_PNO_GET_AUTOJOIN_CAPABILITIES,
DHD_PNO_EPNO_PARAMS_ID
} dhd_pno_gscan_cmd_cfg_t;
typedef enum dhd_pno_mode {
/* Wi-Fi Legacy PNO Mode */
DHD_PNO_NONE_MODE = 0,
DHD_PNO_LEGACY_MODE = (1 << (0)),
/* Wi-Fi Android BATCH SCAN Mode */
DHD_PNO_BATCH_MODE = (1 << (1)),
/* Wi-Fi Android Hotlist SCAN Mode */
DHD_PNO_HOTLIST_MODE = (1 << (2)),
/* Wi-Fi Google Android SCAN Mode */
DHD_PNO_GSCAN_MODE = (1 << (3))
} dhd_pno_mode_t;
#else
typedef enum dhd_pno_mode {
/* Wi-Fi Legacy PNO Mode */
DHD_PNO_NONE_MODE = 0,
DHD_PNO_LEGACY_MODE = (1 << (0)),
/* Wi-Fi Android BATCH SCAN Mode */
DHD_PNO_BATCH_MODE = (1 << (1)),
/* Wi-Fi Android Hotlist SCAN Mode */
DHD_PNO_HOTLIST_MODE = (1 << (2))
} dhd_pno_mode_t;
#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
typedef struct dhd_pno_ssid {
bool hidden;
int8 rssi_thresh;
uint8 dummy;
uint16 SSID_len;
uint32 flags;
int32 wpa_auth;
uchar SSID[DOT11_MAX_SSID_LEN];
struct list_head list;
} dhd_pno_ssid_t;
struct dhd_pno_bssid {
struct ether_addr macaddr;
/* Bit4: suppress_lost, Bit3: suppress_found */
uint16 flags;
struct list_head list;
};
typedef struct dhd_pno_bestnet_entry {
struct ether_addr BSSID;
uint8 SSID_len;
uint8 SSID[DOT11_MAX_SSID_LEN];
int8 RSSI;
uint8 channel;
uint32 timestamp;
uint16 rtt0; /* distance_cm based on RTT */
uint16 rtt1; /* distance_cm based on sample standard deviation */
unsigned long recorded_time;
struct list_head list;
} dhd_pno_bestnet_entry_t;
#define BESTNET_ENTRY_SIZE (sizeof(dhd_pno_bestnet_entry_t))
typedef struct dhd_pno_bestnet_header {
struct dhd_pno_bestnet_header *next;
uint8 reason;
uint32 tot_cnt;
uint32 tot_size;
struct list_head entry_list;
} dhd_pno_best_header_t;
#define BEST_HEADER_SIZE (sizeof(dhd_pno_best_header_t))
typedef struct dhd_pno_scan_results {
dhd_pno_best_header_t *bestnetheader;
uint8 cnt_header;
struct list_head list;
} dhd_pno_scan_results_t;
#define SCAN_RESULTS_SIZE (sizeof(dhd_pno_scan_results_t))
struct dhd_pno_get_batch_info {
/* info related to get batch */
char *buf;
bool batch_started;
uint32 tot_scan_cnt;
uint32 expired_tot_scan_cnt;
uint32 top_node_cnt;
uint32 bufsize;
uint32 bytes_written;
int reason;
struct list_head scan_results_list;
struct list_head expired_scan_results_list;
};
struct dhd_pno_legacy_params {
uint16 scan_fr;
uint16 chan_list[WL_NUMCHANNELS];
uint16 nchan;
int pno_repeat;
int pno_freq_expo_max;
int nssid;
struct list_head ssid_list;
};
struct dhd_pno_batch_params {
int32 scan_fr;
uint8 bestn;
uint8 mscan;
uint8 band;
uint16 chan_list[WL_NUMCHANNELS];
uint16 nchan;
uint16 rtt;
struct dhd_pno_get_batch_info get_batch;
};
struct dhd_pno_hotlist_params {
uint8 band;
int32 scan_fr;
uint16 chan_list[WL_NUMCHANNELS];
uint16 nchan;
uint16 nbssid;
struct list_head bssid_list;
};
#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
#define DHD_PNO_REPORT_NO_BATCH (1 << 2)
typedef struct dhd_pno_gscan_channel_bucket {
uint16 bucket_freq_multiple;
/* band = 1 All bg band channels,
* band = 2 All a band channels,
* band = 0 chan_list channels
*/
uint16 band;
uint8 report_flag;
uint8 num_channels;
uint16 repeat;
uint16 bucket_max_multiple;
uint16 chan_list[GSCAN_MAX_CHANNELS_IN_BUCKET];
} dhd_pno_gscan_channel_bucket_t;
#define DHD_PNO_AUTH_CODE_OPEN 1 /* Open */
#define DHD_PNO_AUTH_CODE_PSK 2 /* WPA_PSK or WPA2PSK */
#define DHD_PNO_AUTH_CODE_EAPOL 4 /* any EAPOL */
#define DHD_EPNO_DEFAULT_INDEX 0xFFFFFFFF
typedef struct dhd_epno_params {
uint8 ssid[DOT11_MAX_SSID_LEN];
uint8 ssid_len;
int8 rssi_thresh;
uint8 flags;
uint8 auth;
/* index required only for visble ssid */
uint32 index;
struct list_head list;
} dhd_epno_params_t;
typedef struct dhd_epno_results {
uint8 ssid[DOT11_MAX_SSID_LEN];
uint8 ssid_len;
int8 rssi;
uint16 channel;
uint16 flags;
struct ether_addr bssid;
} dhd_epno_results_t;
typedef struct dhd_pno_swc_evt_param {
uint16 results_rxed_so_far;
wl_pfn_significant_net_t *change_array;
} dhd_pno_swc_evt_param_t;
typedef struct wifi_gscan_result {
uint64 ts; /* Time of discovery */
char ssid[DOT11_MAX_SSID_LEN+1]; /* null terminated */
struct ether_addr macaddr; /* BSSID */
uint32 channel; /* channel frequency in MHz */
int32 rssi; /* in db */
uint64 rtt; /* in nanoseconds */
uint64 rtt_sd; /* standard deviation in rtt */
uint16 beacon_period; /* units are Kusec */
uint16 capability; /* Capability information */
uint32 pad;
} wifi_gscan_result_t;
typedef struct wifi_gscan_full_result {
wifi_gscan_result_t fixed;
uint32 scan_ch_bucket;
uint32 ie_length; /* byte length of Information Elements */
char ie_data[1]; /* IE data to follow */
} wifi_gscan_full_result_t;
typedef struct gscan_results_cache {
struct gscan_results_cache *next;
uint8 scan_id;
uint8 flag;
uint8 tot_count;
uint8 tot_consumed;
uint32 scan_ch_bucket;
wifi_gscan_result_t results[1];
} gscan_results_cache_t;
typedef struct dhd_pno_gscan_capabilities {
int max_scan_cache_size;
int max_scan_buckets;
int max_ap_cache_per_scan;
int max_rssi_sample_size;
int max_scan_reporting_threshold;
int max_hotlist_bssids;
int max_hotlist_ssids;
int max_significant_wifi_change_aps;
int max_bssid_history_entries;
int max_epno_ssid_crc32;
int max_epno_hidden_ssid;
int max_white_list_ssid;
} dhd_pno_gscan_capabilities_t;
typedef struct dhd_epno_ssid_cfg {
wl_ssid_ext_params_t params;
uint32 num_epno_ssid;
struct list_head epno_ssid_list;
} dhd_epno_ssid_cfg_t;
struct dhd_pno_gscan_params {
int32 scan_fr;
uint8 bestn;
uint8 mscan;
uint8 buffer_threshold;
uint8 swc_nbssid_threshold;
uint8 swc_rssi_window_size;
uint8 lost_ap_window;
uint8 nchannel_buckets;
uint8 reason;
uint8 get_batch_flag;
uint8 send_all_results_flag;
uint16 max_ch_bucket_freq;
gscan_results_cache_t *gscan_batch_cache;
gscan_results_cache_t *gscan_hotlist_found;
gscan_results_cache_t*gscan_hotlist_lost;
uint16 nbssid_significant_change;
uint16 nbssid_hotlist;
struct dhd_pno_swc_evt_param param_significant;
struct dhd_pno_gscan_channel_bucket channel_bucket[GSCAN_MAX_CH_BUCKETS];
struct list_head hotlist_bssid_list;
struct list_head significant_bssid_list;
dhd_epno_ssid_cfg_t epno_cfg;
uint32 scan_id;
};
typedef struct gscan_scan_params {
int32 scan_fr;
uint16 nchannel_buckets;
struct dhd_pno_gscan_channel_bucket channel_bucket[GSCAN_MAX_CH_BUCKETS];
} gscan_scan_params_t;
typedef struct gscan_batch_params {
uint8 bestn;
uint8 mscan;
uint8 buffer_threshold;
} gscan_batch_params_t;
struct bssid_t {
struct ether_addr macaddr;
int16 rssi_reporting_threshold; /* 0 -> no reporting threshold */
};
typedef struct gscan_hotlist_scan_params {
uint16 lost_ap_window; /* number of scans to declare LOST */
uint16 nbssid; /* number of bssids */
struct bssid_t bssid[1]; /* n bssids to follow */
} gscan_hotlist_scan_params_t;
#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
typedef union dhd_pno_params {
struct dhd_pno_legacy_params params_legacy;
struct dhd_pno_batch_params params_batch;
struct dhd_pno_hotlist_params params_hotlist;
#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
struct dhd_pno_gscan_params params_gscan;
#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
} dhd_pno_params_t;
typedef struct dhd_pno_status_info {
dhd_pub_t *dhd;
struct work_struct work;
struct mutex pno_mutex;
#ifdef GSCAN_SUPPORT
wait_queue_head_t batch_get_wait;
#endif /* GSCAN_SUPPORT */
struct completion get_batch_done;
bool wls_supported; /* wifi location service supported or not */
enum dhd_pno_status pno_status;
enum dhd_pno_mode pno_mode;
dhd_pno_params_t pno_params_arr[INDEX_MODE_MAX];
struct list_head head_list;
} dhd_pno_status_info_t;
/* wrapper functions */
extern int
dhd_dev_pno_enable(struct net_device *dev, int enable);
extern int
dhd_dev_pno_stop_for_ssid(struct net_device *dev);
extern int
dhd_dev_pno_set_for_ssid(struct net_device *dev, wlc_ssid_ext_t* ssids_local, int nssid,
uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan);
extern int
dhd_dev_pno_set_for_batch(struct net_device *dev,
struct dhd_pno_batch_params *batch_params);
extern int
dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize);
extern int
dhd_dev_pno_stop_for_batch(struct net_device *dev);
extern int
dhd_dev_pno_set_for_hotlist(struct net_device *dev, wl_pfn_bssid_t *p_pfn_bssid,
struct dhd_pno_hotlist_params *hotlist_params);
extern bool dhd_dev_is_legacy_pno_enabled(struct net_device *dev);
#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
extern void *
dhd_dev_pno_get_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, void *info,
uint32 *len);
#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
#ifdef GSCAN_SUPPORT
extern int
dhd_dev_pno_set_cfg_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type,
void *buf, bool flush);
int dhd_dev_pno_lock_access_batch_results(struct net_device *dev);
void dhd_dev_pno_unlock_access_batch_results(struct net_device *dev);
extern int dhd_dev_pno_run_gscan(struct net_device *dev, bool run, bool flush);
extern int dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time);
int dhd_retreive_batch_scan_results(dhd_pub_t *dhd);
extern void * dhd_dev_hotlist_scan_event(struct net_device *dev,
const void *data, int *send_evt_bytes, hotlist_type_t type, u32 *buf_len);
void * dhd_dev_process_full_gscan_result(struct net_device *dev,
const void *data, uint32 len, int *send_evt_bytes);
extern int dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev);
extern void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type);
extern int dhd_dev_wait_batch_results_complete(struct net_device *dev);
extern void * dhd_dev_process_epno_result(struct net_device *dev,
const void *data, uint32 event, int *send_evt_bytes);
extern int dhd_dev_set_epno(struct net_device *dev);
extern int dhd_dev_flush_fw_epno(struct net_device *dev);
#endif /* GSCAN_SUPPORT */
/* dhd pno fuctions */
extern int dhd_pno_stop_for_ssid(dhd_pub_t *dhd);
extern int dhd_pno_enable(dhd_pub_t *dhd, int enable);
extern int dhd_pno_set_for_ssid(dhd_pub_t *dhd, wlc_ssid_ext_t* ssid_list, int nssid,
uint16 scan_fr, int pno_repeat, int pno_freq_expo_max, uint16 *channel_list, int nchan);
extern int dhd_pno_set_for_batch(dhd_pub_t *dhd, struct dhd_pno_batch_params *batch_params);
extern int dhd_pno_get_for_batch(dhd_pub_t *dhd, char *buf, int bufsize, int reason);
extern int dhd_pno_stop_for_batch(dhd_pub_t *dhd);
extern int dhd_pno_set_for_hotlist(dhd_pub_t *dhd, wl_pfn_bssid_t *p_pfn_bssid,
struct dhd_pno_hotlist_params *hotlist_params);
extern int dhd_pno_stop_for_hotlist(dhd_pub_t *dhd);
extern int dhd_pno_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data);
extern int dhd_pno_init(dhd_pub_t *dhd);
extern int dhd_pno_deinit(dhd_pub_t *dhd);
extern bool dhd_is_pno_supported(dhd_pub_t *dhd);
extern bool dhd_is_legacy_pno_enabled(dhd_pub_t *dhd);
#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS)
extern void * dhd_pno_get_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *info,
uint32 *len);
#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */
#ifdef GSCAN_SUPPORT
extern int dhd_pno_set_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type,
void *buf, bool flush);
extern int dhd_pno_lock_batch_results(dhd_pub_t *dhd);
extern void dhd_pno_unlock_batch_results(dhd_pub_t *dhd);
extern int dhd_pno_initiate_gscan_request(dhd_pub_t *dhd, bool run, bool flush);
extern int dhd_pno_enable_full_scan_result(dhd_pub_t *dhd, bool real_time_flag);
extern int dhd_pno_cfg_gscan(dhd_pub_t *dhd, dhd_pno_gscan_cmd_cfg_t type, void *buf);
extern int dhd_dev_retrieve_batch_scan(struct net_device *dev);
extern void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data,
int *send_evt_bytes, hotlist_type_t type, u32 *buf_len);
extern void *dhd_process_full_gscan_result(dhd_pub_t *dhd, const void *event_data,
uint32 len, int *send_evt_bytes);
extern int dhd_gscan_batch_cache_cleanup(dhd_pub_t *dhd);
extern void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type);
extern int dhd_wait_batch_results_complete(dhd_pub_t *dhd);
extern void * dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data,
uint32 event, int *size);
extern void dhd_pno_translate_epno_fw_flags(uint32 *flags);
extern int dhd_pno_set_epno(dhd_pub_t *dhd);
extern int dhd_pno_flush_fw_epno(dhd_pub_t *dhd);
extern void dhd_pno_set_epno_auth_flag(uint32 *wpa_auth);
#endif /* GSCAN_SUPPORT */
#endif // endif
#endif /* __DHD_PNO_H__ */

View File

@@ -0,0 +1,243 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Header file describing the internal (inter-module) DHD interfaces.
*
* Provides type definitions and function prototypes used to link the
* DHD OS, bus, and protocol modules.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_proto.h 814912 2019-04-15 10:38:59Z $
*/
#ifndef _dhd_proto_h_
#define _dhd_proto_h_
#include <dhdioctl.h>
#include <wlioctl.h>
#ifdef BCMPCIE
#include <dhd_flowring.h>
#endif // endif
#define DEFAULT_IOCTL_RESP_TIMEOUT 5000
#ifndef IOCTL_RESP_TIMEOUT
/* In milli second default value for Production FW */
#define IOCTL_RESP_TIMEOUT DEFAULT_IOCTL_RESP_TIMEOUT
#endif /* IOCTL_RESP_TIMEOUT */
/* In milli second default value for Production FW */
#define IOCTL_DMAXFER_TIMEOUT 10000
#ifndef MFG_IOCTL_RESP_TIMEOUT
#define MFG_IOCTL_RESP_TIMEOUT 20000 /* In milli second default value for MFG FW */
#endif /* MFG_IOCTL_RESP_TIMEOUT */
#define DEFAULT_D3_ACK_RESP_TIMEOUT 2000
#ifndef D3_ACK_RESP_TIMEOUT
#define D3_ACK_RESP_TIMEOUT DEFAULT_D3_ACK_RESP_TIMEOUT
#endif /* D3_ACK_RESP_TIMEOUT */
#define DEFAULT_DHD_BUS_BUSY_TIMEOUT (IOCTL_RESP_TIMEOUT + 1000)
#ifndef DHD_BUS_BUSY_TIMEOUT
#define DHD_BUS_BUSY_TIMEOUT DEFAULT_DHD_BUS_BUSY_TIMEOUT
#endif /* DEFAULT_DHD_BUS_BUSY_TIMEOUT */
#define DS_EXIT_TIMEOUT 1000 /* In ms */
#define DS_ENTER_TIMEOUT 1000 /* In ms */
#define IOCTL_DISABLE_TIMEOUT 0
/*
* Exported from the dhd protocol module (dhd_cdc, dhd_rndis)
*/
/* Linkage, sets prot link and updates hdrlen in pub */
extern int dhd_prot_attach(dhd_pub_t *dhdp);
/* Initilizes the index block for dma'ing indices */
extern int dhd_prot_dma_indx_init(dhd_pub_t *dhdp, uint32 rw_index_sz,
uint8 type, uint32 length);
/* Unlink, frees allocated protocol memory (including dhd_prot) */
extern void dhd_prot_detach(dhd_pub_t *dhdp);
/* Initialize protocol: sync w/dongle state.
* Sets dongle media info (iswl, drv_version, mac address).
*/
extern int dhd_sync_with_dongle(dhd_pub_t *dhdp);
/* Protocol initialization needed for IOCTL/IOVAR path */
extern int dhd_prot_init(dhd_pub_t *dhd);
/* Stop protocol: sync w/dongle state. */
extern void dhd_prot_stop(dhd_pub_t *dhdp);
/* Add any protocol-specific data header.
* Caller must reserve prot_hdrlen prepend space.
*/
extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp);
extern uint dhd_prot_hdrlen(dhd_pub_t *, void *txp);
/* Remove any protocol-specific data header. */
extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp, uchar *buf, uint *len);
/* Use protocol to issue ioctl to dongle */
extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len);
/* Handles a protocol control response asynchronously */
extern int dhd_prot_ctl_complete(dhd_pub_t *dhd);
/* Check for and handle local prot-specific iovar commands */
extern int dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name,
void *params, int plen, void *arg, int len, bool set);
/* Add prot dump output to a buffer */
extern void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
/* Dump extended trap data */
extern int dhd_prot_dump_extended_trap(dhd_pub_t *dhdp, struct bcmstrbuf *b, bool raw);
/* Update local copy of dongle statistics */
extern void dhd_prot_dstats(dhd_pub_t *dhdp);
extern int dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen);
extern int dhd_preinit_ioctls(dhd_pub_t *dhd);
extern int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf,
uint reorder_info_len, void **pkt, uint32 *free_buf_count);
#ifdef BCMPCIE
extern bool dhd_prot_process_msgbuf_txcpl(dhd_pub_t *dhd, uint bound, int ringtype);
extern bool dhd_prot_process_msgbuf_rxcpl(dhd_pub_t *dhd, uint bound, int ringtype);
extern bool dhd_prot_process_msgbuf_infocpl(dhd_pub_t *dhd, uint bound);
extern int dhd_prot_process_ctrlbuf(dhd_pub_t * dhd);
extern int dhd_prot_process_trapbuf(dhd_pub_t * dhd);
extern bool dhd_prot_dtohsplit(dhd_pub_t * dhd);
extern int dhd_post_dummy_msg(dhd_pub_t *dhd);
extern int dhdmsgbuf_lpbk_req(dhd_pub_t *dhd, uint len);
extern void dhd_prot_rx_dataoffset(dhd_pub_t *dhd, uint32 offset);
extern int dhd_prot_txdata(dhd_pub_t *dhd, void *p, uint8 ifidx);
extern int dhdmsgbuf_dmaxfer_req(dhd_pub_t *dhd,
uint len, uint srcdelay, uint destdelay, uint d11_lpbk, uint core_num);
extern int dhdmsgbuf_dmaxfer_status(dhd_pub_t *dhd, dma_xfer_info_t *result);
extern void dhd_dma_buf_init(dhd_pub_t *dhd, void *dma_buf,
void *va, uint32 len, dmaaddr_t pa, void *dmah, void *secdma);
extern void dhd_prot_flowrings_pool_release(dhd_pub_t *dhd,
uint16 flowid, void *msgbuf_ring);
extern int dhd_prot_flow_ring_create(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node);
extern int dhd_post_tx_ring_item(dhd_pub_t *dhd, void *PKTBUF, uint8 ifindex);
extern int dhd_prot_flow_ring_delete(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node);
extern int dhd_prot_flow_ring_flush(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node);
extern int dhd_prot_ringupd_dump(dhd_pub_t *dhd, struct bcmstrbuf *b);
extern uint32 dhd_prot_metadata_dbg_set(dhd_pub_t *dhd, bool val);
extern uint32 dhd_prot_metadata_dbg_get(dhd_pub_t *dhd);
extern uint32 dhd_prot_metadatalen_set(dhd_pub_t *dhd, uint32 val, bool rx);
extern uint32 dhd_prot_metadatalen_get(dhd_pub_t *dhd, bool rx);
extern void dhd_prot_print_flow_ring(dhd_pub_t *dhd, void *msgbuf_flow_info,
struct bcmstrbuf *strbuf, const char * fmt);
extern void dhd_prot_print_info(dhd_pub_t *dhd, struct bcmstrbuf *strbuf);
extern void dhd_prot_update_txflowring(dhd_pub_t *dhdp, uint16 flow_id, void *msgring_info);
extern void dhd_prot_txdata_write_flush(dhd_pub_t *dhd, uint16 flow_id);
extern uint32 dhd_prot_txp_threshold(dhd_pub_t *dhd, bool set, uint32 val);
extern void dhd_prot_reset(dhd_pub_t *dhd);
extern uint16 dhd_get_max_flow_rings(dhd_pub_t *dhd);
#ifdef IDLE_TX_FLOW_MGMT
extern int dhd_prot_flow_ring_batch_suspend_request(dhd_pub_t *dhd, uint16 *ringid, uint16 count);
extern int dhd_prot_flow_ring_resume(dhd_pub_t *dhd, flow_ring_node_t *flow_ring_node);
#endif /* IDLE_TX_FLOW_MGMT */
extern int dhd_prot_init_info_rings(dhd_pub_t *dhd);
#ifdef DHD_HP2P
extern int dhd_prot_init_hp2p_rings(dhd_pub_t *dhd);
#endif /* DHD_HP2P */
extern int dhd_prot_check_tx_resource(dhd_pub_t *dhd);
extern void dhd_prot_update_pktid_txq_stop_cnt(dhd_pub_t *dhd);
extern void dhd_prot_update_pktid_txq_start_cnt(dhd_pub_t *dhd);
#else
static INLINE void dhd_prot_update_pktid_txq_stop_cnt(dhd_pub_t *dhd) { return; }
static INLINE void dhd_prot_update_pktid_txq_start_cnt(dhd_pub_t *dhd) { return; }
#endif /* BCMPCIE */
#ifdef DHD_LB
extern void dhd_lb_tx_compl_handler(unsigned long data);
extern void dhd_lb_rx_compl_handler(unsigned long data);
extern void dhd_lb_rx_process_handler(unsigned long data);
#endif /* DHD_LB */
extern int dhd_prot_h2d_mbdata_send_ctrlmsg(dhd_pub_t *dhd, uint32 mb_data);
#ifdef BCMPCIE
extern int dhd_prot_send_host_timestamp(dhd_pub_t *dhdp, uchar *tlv, uint16 tlv_len,
uint16 seq, uint16 xt_id);
extern bool dhd_prot_data_path_tx_timestamp_logging(dhd_pub_t *dhd, bool enable, bool set);
extern bool dhd_prot_data_path_rx_timestamp_logging(dhd_pub_t *dhd, bool enable, bool set);
extern bool dhd_prot_pkt_noretry(dhd_pub_t *dhd, bool enable, bool set);
extern bool dhd_prot_pkt_noaggr(dhd_pub_t *dhd, bool enable, bool set);
extern bool dhd_prot_pkt_fixed_rate(dhd_pub_t *dhd, bool enable, bool set);
#else /* BCMPCIE */
#define dhd_prot_send_host_timestamp(a, b, c, d, e) 0
#define dhd_prot_data_path_tx_timestamp_logging(a, b, c) 0
#define dhd_prot_data_path_rx_timestamp_logging(a, b, c) 0
#endif /* BCMPCIE */
extern void dhd_prot_dma_indx_free(dhd_pub_t *dhd);
#ifdef EWP_EDL
int dhd_prot_init_edl_rings(dhd_pub_t *dhd);
bool dhd_prot_process_msgbuf_edl(dhd_pub_t *dhd);
int dhd_prot_process_edl_complete(dhd_pub_t *dhd, void *evt_decode_data);
#endif /* EWP_EDL */
/* APIs for managing a DMA-able buffer */
int dhd_dma_buf_alloc(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf, uint32 buf_len);
void dhd_dma_buf_free(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf);
/********************************
* For version-string expansion *
*/
#if defined(BDC)
#define DHD_PROTOCOL "bdc"
#elif defined(CDC)
#define DHD_PROTOCOL "cdc"
#else
#define DHD_PROTOCOL "unknown"
#endif /* proto */
int dhd_get_hscb_info(dhd_pub_t *dhd, void ** va, uint32 *len);
int dhd_get_hscb_buff(dhd_pub_t *dhd, uint32 offset, uint32 length, void * buff);
#ifdef DHD_HP2P
extern uint8 dhd_prot_hp2p_enable(dhd_pub_t *dhd, bool set, int enable);
extern uint32 dhd_prot_pkt_threshold(dhd_pub_t *dhd, bool set, uint32 val);
extern uint32 dhd_prot_time_threshold(dhd_pub_t *dhd, bool set, uint32 val);
extern uint32 dhd_prot_pkt_expiry(dhd_pub_t *dhd, bool set, uint32 val);
#endif // endif
#ifdef DHD_MAP_LOGGING
extern void dhd_prot_smmu_fault_dump(dhd_pub_t *dhdp);
#endif /* DHD_MAP_LOGGING */
#endif /* _dhd_proto_h_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,537 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Broadcom Dongle Host Driver (DHD), RTT
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id$
*/
#ifndef __DHD_RTT_H__
#define __DHD_RTT_H__
#include "dngl_stats.h"
#define RTT_MAX_TARGET_CNT 50
#define RTT_MAX_FRAME_CNT 25
#define RTT_MAX_RETRY_CNT 10
#define DEFAULT_FTM_CNT 6
#define DEFAULT_RETRY_CNT 6
#define DEFAULT_FTM_FREQ 5180
#define DEFAULT_FTM_CNTR_FREQ0 5210
#define RTT_MAX_GEOFENCE_TARGET_CNT 8
#define TARGET_INFO_SIZE(count) (sizeof(rtt_target_info_t) * count)
#define TARGET_TYPE(target) (target->type)
#define RTT_IS_ENABLED(rtt_status) (rtt_status->status == RTT_ENABLED)
#define RTT_IS_STOPPED(rtt_status) (rtt_status->status == RTT_STOPPED)
#define GEOFENCE_RTT_LOCK(rtt_status) mutex_lock(&(rtt_status)->geofence_mutex)
#define GEOFENCE_RTT_UNLOCK(rtt_status) mutex_unlock(&(rtt_status)->geofence_mutex)
#ifndef BIT
#define BIT(x) (1 << (x))
#endif // endif
/* DSSS, CCK and 802.11n rates in [500kbps] units */
#define WL_MAXRATE 108 /* in 500kbps units */
#define WL_RATE_1M 2 /* in 500kbps units */
#define WL_RATE_2M 4 /* in 500kbps units */
#define WL_RATE_5M5 11 /* in 500kbps units */
#define WL_RATE_11M 22 /* in 500kbps units */
#define WL_RATE_6M 12 /* in 500kbps units */
#define WL_RATE_9M 18 /* in 500kbps units */
#define WL_RATE_12M 24 /* in 500kbps units */
#define WL_RATE_18M 36 /* in 500kbps units */
#define WL_RATE_24M 48 /* in 500kbps units */
#define WL_RATE_36M 72 /* in 500kbps units */
#define WL_RATE_48M 96 /* in 500kbps units */
#define WL_RATE_54M 108 /* in 500kbps units */
#define GET_RTTSTATE(dhd) ((rtt_status_info_t *)dhd->rtt_state)
#ifdef WL_NAN
/* RTT Retry Timer Interval */
#define DHD_RTT_RETRY_TIMER_INTERVAL_MS 3000u
#endif /* WL_NAN */
#define DHD_RTT_INVALID_TARGET_INDEX -1
enum rtt_role {
RTT_INITIATOR = 0,
RTT_TARGET = 1
};
enum rtt_status {
RTT_STOPPED = 0,
RTT_STARTED = 1,
RTT_ENABLED = 2
};
typedef int64_t wifi_timestamp; /* In microseconds (us) */
typedef int64_t wifi_timespan;
typedef int32 wifi_rssi_rtt;
typedef enum {
RTT_INVALID,
RTT_ONE_WAY,
RTT_TWO_WAY,
RTT_AUTO
} rtt_type_t;
/* RTT peer type */
typedef enum {
RTT_PEER_AP = 0x1,
RTT_PEER_STA = 0x2,
RTT_PEER_P2P_GO = 0x3,
RTT_PEER_P2P_CLIENT = 0x4,
RTT_PEER_NAN = 0x5,
RTT_PEER_INVALID = 0x6
} rtt_peer_type_t;
/* Ranging status */
typedef enum rtt_reason {
RTT_STATUS_SUCCESS = 0,
RTT_STATUS_FAILURE = 1, // general failure status
RTT_STATUS_FAIL_NO_RSP = 2, // target STA does not respond to request
RTT_STATUS_FAIL_REJECTED = 3, // request rejected. Applies to 2-sided RTT only
RTT_STATUS_FAIL_NOT_SCHEDULED_YET = 4,
RTT_STATUS_FAIL_TM_TIMEOUT = 5, // timing measurement times out
RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6, // Target on different channel, cannot range
RTT_STATUS_FAIL_NO_CAPABILITY = 7, // ranging not supported
RTT_STATUS_ABORTED = 8, // request aborted for unknown reason
RTT_STATUS_FAIL_INVALID_TS = 9, // Invalid T1-T4 timestamp
RTT_STATUS_FAIL_PROTOCOL = 10, // 11mc protocol failed
RTT_STATUS_FAIL_SCHEDULE = 11, // request could not be scheduled
RTT_STATUS_FAIL_BUSY_TRY_LATER = 12, // responder cannot collaborate at time of request
RTT_STATUS_INVALID_REQ = 13, // bad request args
RTT_STATUS_NO_WIFI = 14, // WiFi not enabled Responder overrides param info
// cannot range with new params
RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE = 15
} rtt_reason_t;
enum {
RTT_CAP_ONE_WAY = BIT(0),
/* IEEE802.11mc */
RTT_CAP_FTM_WAY = BIT(1)
};
enum {
RTT_FEATURE_LCI = BIT(0),
RTT_FEATURE_LCR = BIT(1),
RTT_FEATURE_PREAMBLE = BIT(2),
RTT_FEATURE_BW = BIT(3)
};
enum {
RTT_PREAMBLE_LEGACY = BIT(0),
RTT_PREAMBLE_HT = BIT(1),
RTT_PREAMBLE_VHT = BIT(2)
};
enum {
RTT_BW_5 = BIT(0),
RTT_BW_10 = BIT(1),
RTT_BW_20 = BIT(2),
RTT_BW_40 = BIT(3),
RTT_BW_80 = BIT(4),
RTT_BW_160 = BIT(5)
};
enum rtt_rate_bw {
RTT_RATE_20M,
RTT_RATE_40M,
RTT_RATE_80M,
RTT_RATE_160M
};
typedef enum ranging_type {
RTT_TYPE_INVALID = 0,
RTT_TYPE_LEGACY = 1,
RTT_TYPE_NAN_DIRECTED = 2,
RTT_TYPE_NAN_GEOFENCE = 3
} ranging_type_t;
#define FTM_MAX_NUM_BURST_EXP 14
#define HAS_11MC_CAP(cap) (cap & RTT_CAP_FTM_WAY)
#define HAS_ONEWAY_CAP(cap) (cap & RTT_CAP_ONE_WAY)
#define HAS_RTT_CAP(cap) (HAS_ONEWAY_CAP(cap) || HAS_11MC_CAP(cap))
typedef struct wifi_channel_info {
wifi_channel_width_t width;
wifi_channel center_freq; /* primary 20 MHz channel */
wifi_channel center_freq0; /* center freq (MHz) first segment */
wifi_channel center_freq1; /* center freq (MHz) second segment valid for 80 + 80 */
} wifi_channel_info_t;
typedef struct wifi_rate {
uint32 preamble :3; /* 0: OFDM, 1: CCK, 2 : HT, 3: VHT, 4..7 reserved */
uint32 nss :2; /* 1 : 1x1, 2: 2x2, 3: 3x3, 4: 4x4 */
uint32 bw :3; /* 0: 20Mhz, 1: 40Mhz, 2: 80Mhz, 3: 160Mhz */
/* OFDM/CCK rate code would be as per IEEE std in the unit of 0.5 mb
* HT/VHT it would be mcs index
*/
uint32 rateMcsIdx :8;
uint32 reserved :16; /* reserved */
uint32 bitrate; /* unit of 100 Kbps */
} wifi_rate_t;
typedef struct rtt_target_info {
struct ether_addr addr;
struct ether_addr local_addr;
rtt_type_t type; /* rtt_type */
rtt_peer_type_t peer; /* peer type */
wifi_channel_info_t channel; /* channel information */
chanspec_t chanspec; /* chanspec for channel */
bool disable; /* disable for RTT measurement */
/*
* Time interval between bursts (units: 100 ms).
* Applies to 1-sided and 2-sided RTT multi-burst requests.
* Range: 0-31, 0: no preference by initiator (2-sided RTT)
*/
uint32 burst_period;
/*
* Total number of RTT bursts to be executed. It will be
* specified in the same way as the parameter "Number of
* Burst Exponent" found in the FTM frame format. It
* applies to both: 1-sided RTT and 2-sided RTT. Valid
* values are 0 to 15 as defined in 802.11mc std.
* 0 means single shot
* The implication of this parameter on the maximum
* number of RTT results is the following:
* for 1-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst)
* for 2-sided RTT: max num of RTT results = (2^num_burst)*(num_frames_per_burst - 1)
*/
uint16 num_burst;
/*
* num of frames per burst.
* Minimum value = 1, Maximum value = 31
* For 2-sided this equals the number of FTM frames
* to be attempted in a single burst. This also
* equals the number of FTM frames that the
* initiator will request that the responder send
* in a single frame
*/
uint32 num_frames_per_burst;
/*
* num of frames in each RTT burst
* for single side, measurement result num = frame number
* for 2 side RTT, measurement result num = frame number - 1
*/
uint32 num_retries_per_ftm; /* retry time for RTT measurment frame */
/* following fields are only valid for 2 side RTT */
uint32 num_retries_per_ftmr;
uint8 LCI_request;
uint8 LCR_request;
/*
* Applies to 1-sided and 2-sided RTT. Valid values will
* be 2-11 and 15 as specified by the 802.11mc std for
* the FTM parameter burst duration. In a multi-burst
* request, if responder overrides with larger value,
* the initiator will return failure. In a single-burst
* request if responder overrides with larger value,
* the initiator will sent TMR_STOP to terminate RTT
* at the end of the burst_duration it requested.
*/
uint32 burst_duration;
uint32 burst_timeout;
uint8 preamble; /* 1 - Legacy, 2 - HT, 4 - VHT */
uint8 bw; /* 5, 10, 20, 40, 80, 160 */
} rtt_target_info_t;
typedef struct rtt_goefence_target_info {
bool valid;
struct ether_addr peer_addr;
} rtt_geofence_target_info_t;
typedef struct rtt_config_params {
int8 rtt_target_cnt;
rtt_target_info_t *target_info;
} rtt_config_params_t;
typedef struct rtt_geofence_cfg {
int8 geofence_target_cnt;
bool rtt_in_progress;
bool role_concurr_state;
int8 cur_target_idx;
rtt_geofence_target_info_t geofence_target_info[RTT_MAX_GEOFENCE_TARGET_CNT];
int geofence_rtt_interval;
#ifdef RTT_GEOFENCE_CONT
bool geofence_cont;
#endif /* RTT_GEOFENCE_CONT */
} rtt_geofence_cfg_t;
/*
* Keep Adding more reasons
* going forward if needed
*/
enum rtt_schedule_reason {
RTT_SCHED_HOST_TRIGGER = 1, /* On host command for directed RTT */
RTT_SCHED_SUB_MATCH = 2, /* on Sub Match for svc with range req */
RTT_SCHED_DIR_TRIGGER_FAIL = 3, /* On failure of Directed RTT Trigger */
RTT_SCHED_DP_END = 4, /* ON NDP End event from fw */
RTT_SCHED_DP_REJECTED = 5, /* On receving reject dp event from fw */
RTT_SCHED_RNG_RPT_DIRECTED = 6, /* On Ranging report for directed RTT */
RTT_SCHED_RNG_TERM = 7, /* On Range Term Indicator */
RTT_SHCED_HOST_DIRECTED_TERM = 8, /* On host terminating directed RTT sessions */
RTT_SCHED_RNG_RPT_GEOFENCE = 9, /* On Ranging report for geofence RTT */
RTT_SCHED_RTT_RETRY_GEOFENCE = 10, /* On Geofence Retry */
RTT_SCHED_RNG_TERM_PEND_ROLE_CHANGE = 11 /* On Rng Term, while pending role change */
};
/*
* Keep Adding more invalid RTT states
* going forward if needed
*/
enum rtt_invalid_state {
RTT_STATE_VALID = 0, /* RTT state is valid */
RTT_STATE_INV_REASON_NDP_EXIST = 1 /* RTT state invalid as ndp exists */
};
typedef struct rtt_status_info {
dhd_pub_t *dhd;
int8 status; /* current status for the current entry */
int8 txchain; /* current device tx chain */
int pm; /* to save current value of pm */
int8 pm_restore; /* flag to reset the old value of pm */
int8 cur_idx; /* current entry to do RTT */
bool all_cancel; /* cancel all request once we got the cancel requet */
uint32 flags; /* indicate whether device is configured as initiator or target */
struct capability {
int32 proto :8;
int32 feature :8;
int32 preamble :8;
int32 bw :8;
} rtt_capa; /* rtt capability */
struct mutex rtt_mutex;
struct mutex rtt_work_mutex;
struct mutex geofence_mutex;
rtt_config_params_t rtt_config;
rtt_geofence_cfg_t geofence_cfg;
struct work_struct work;
struct list_head noti_fn_list;
struct list_head rtt_results_cache; /* store results for RTT */
int rtt_sched_reason; /* rtt_schedule_reason: what scheduled RTT */
struct delayed_work proxd_timeout; /* Proxd Timeout work */
struct delayed_work rtt_retry_timer; /* Timer for retry RTT after all targets done */
} rtt_status_info_t;
typedef struct rtt_report {
struct ether_addr addr;
unsigned int burst_num; /* # of burst inside a multi-burst request */
unsigned int ftm_num; /* total RTT measurement frames attempted */
unsigned int success_num; /* total successful RTT measurement frames */
uint8 num_per_burst_peer; /* max number of FTM number per burst the peer support */
rtt_reason_t status; /* raging status */
/* in s, 11mc only, only for RTT_REASON_FAIL_BUSY_TRY_LATER, 1- 31s */
uint8 retry_after_duration;
rtt_type_t type; /* rtt type */
wifi_rssi_rtt rssi; /* average rssi in 0.5 dB steps e.g. 143 implies -71.5 dB */
wifi_rssi_rtt rssi_spread; /* rssi spread in 0.5 db steps e.g. 5 implies 2.5 spread */
/*
* 1-sided RTT: TX rate of RTT frame.
* 2-sided RTT: TX rate of initiator's Ack in response to FTM frame.
*/
wifi_rate_t tx_rate;
/*
* 1-sided RTT: TX rate of Ack from other side.
* 2-sided RTT: TX rate of FTM frame coming from responder.
*/
wifi_rate_t rx_rate;
wifi_timespan rtt; /* round trip time in 0.1 nanoseconds */
wifi_timespan rtt_sd; /* rtt standard deviation in 0.1 nanoseconds */
wifi_timespan rtt_spread; /* difference between max and min rtt times recorded */
int distance; /* distance in cm (optional) */
int distance_sd; /* standard deviation in cm (optional) */
int distance_spread; /* difference between max and min distance recorded (optional) */
wifi_timestamp ts; /* time of the measurement (in microseconds since boot) */
int burst_duration; /* in ms, how long the FW time is to fininish one burst measurement */
int negotiated_burst_num; /* Number of bursts allowed by the responder */
bcm_tlv_t *LCI; /* LCI Report */
bcm_tlv_t *LCR; /* Location Civic Report */
} rtt_report_t;
#define RTT_REPORT_SIZE (sizeof(rtt_report_t))
/* rtt_results_header to maintain rtt result list per mac address */
typedef struct rtt_results_header {
struct ether_addr peer_mac;
uint32 result_cnt;
uint32 result_tot_len; /* sum of report_len of rtt_result */
struct list_head list;
struct list_head result_list;
} rtt_results_header_t;
struct rtt_result_detail {
uint8 num_ota_meas;
uint32 result_flags;
};
/* rtt_result to link all of rtt_report */
typedef struct rtt_result {
struct list_head list;
struct rtt_report report;
int32 report_len; /* total length of rtt_report */
struct rtt_result_detail rtt_detail;
int32 detail_len;
} rtt_result_t;
/* RTT Capabilities */
typedef struct rtt_capabilities {
uint8 rtt_one_sided_supported; /* if 1-sided rtt data collection is supported */
uint8 rtt_ftm_supported; /* if ftm rtt data collection is supported */
uint8 lci_support; /* location configuration information */
uint8 lcr_support; /* Civic Location */
uint8 preamble_support; /* bit mask indicate what preamble is supported */
uint8 bw_support; /* bit mask indicate what BW is supported */
} rtt_capabilities_t;
/* RTT responder information */
typedef struct wifi_rtt_responder {
wifi_channel_info channel; /* channel of responder */
uint8 preamble; /* preamble supported by responder */
} wifi_rtt_responder_t;
typedef void (*dhd_rtt_compl_noti_fn)(void *ctx, void *rtt_data);
/* Linux wrapper to call common dhd_rtt_set_cfg */
int
dhd_dev_rtt_set_cfg(struct net_device *dev, void *buf);
int
dhd_dev_rtt_cancel_cfg(struct net_device *dev, struct ether_addr *mac_list, int mac_cnt);
int
dhd_dev_rtt_register_noti_callback(struct net_device *dev, void *ctx,
dhd_rtt_compl_noti_fn noti_fn);
int
dhd_dev_rtt_unregister_noti_callback(struct net_device *dev, dhd_rtt_compl_noti_fn noti_fn);
int
dhd_dev_rtt_capability(struct net_device *dev, rtt_capabilities_t *capa);
int
dhd_dev_rtt_avail_channel(struct net_device *dev, wifi_channel_info *channel_info);
int
dhd_dev_rtt_enable_responder(struct net_device *dev, wifi_channel_info *channel_info);
int
dhd_dev_rtt_cancel_responder(struct net_device *dev);
/* export to upper layer */
chanspec_t
dhd_rtt_convert_to_chspec(wifi_channel_info_t channel);
int
dhd_rtt_idx_to_burst_duration(uint idx);
int
dhd_rtt_set_cfg(dhd_pub_t *dhd, rtt_config_params_t *params);
#ifdef WL_NAN
void dhd_rtt_initialize_geofence_cfg(dhd_pub_t *dhd);
#ifdef RTT_GEOFENCE_CONT
void dhd_rtt_set_geofence_cont_ind(dhd_pub_t *dhd, bool geofence_cont);
void dhd_rtt_get_geofence_cont_ind(dhd_pub_t *dhd, bool* geofence_cont);
#endif /* RTT_GEOFENCE_CONT */
#ifdef RTT_GEOFENCE_INTERVAL
void dhd_rtt_set_geofence_rtt_interval(dhd_pub_t *dhd, int interval);
#endif /* RTT_GEOFENCE_INTERVAL */
void dhd_rtt_set_role_concurrency_state(dhd_pub_t *dhd, bool state);
bool dhd_rtt_get_role_concurrency_state(dhd_pub_t *dhd);
int8 dhd_rtt_get_geofence_target_cnt(dhd_pub_t *dhd);
void dhd_rtt_set_geofence_rtt_state(dhd_pub_t *dhd, bool state);
bool dhd_rtt_get_geofence_rtt_state(dhd_pub_t *dhd);
rtt_geofence_target_info_t*
dhd_rtt_get_geofence_target_head(dhd_pub_t *dhd);
rtt_geofence_target_info_t*
dhd_rtt_get_geofence_current_target(dhd_pub_t *dhd);
rtt_geofence_target_info_t*
dhd_rtt_get_geofence_target(dhd_pub_t *dhd, struct ether_addr* peer_addr,
int8 *index);
int
dhd_rtt_add_geofence_target(dhd_pub_t *dhd, rtt_geofence_target_info_t *target);
int
dhd_rtt_remove_geofence_target(dhd_pub_t *dhd, struct ether_addr *peer_addr);
int
dhd_rtt_delete_geofence_target_list(dhd_pub_t *dhd);
int
dhd_rtt_delete_nan_session(dhd_pub_t *dhd);
#endif /* WL_NAN */
uint8
dhd_rtt_invalid_states(struct net_device *ndev, struct ether_addr *peer_addr);
void
dhd_rtt_schedule_rtt_work_thread(dhd_pub_t *dhd, int sched_reason);
int
dhd_rtt_stop(dhd_pub_t *dhd, struct ether_addr *mac_list, int mac_cnt);
int
dhd_rtt_register_noti_callback(dhd_pub_t *dhd, void *ctx, dhd_rtt_compl_noti_fn noti_fn);
int
dhd_rtt_unregister_noti_callback(dhd_pub_t *dhd, dhd_rtt_compl_noti_fn noti_fn);
int
dhd_rtt_event_handler(dhd_pub_t *dhd, wl_event_msg_t *event, void *event_data);
int
dhd_rtt_capability(dhd_pub_t *dhd, rtt_capabilities_t *capa);
int
dhd_rtt_avail_channel(dhd_pub_t *dhd, wifi_channel_info *channel_info);
int
dhd_rtt_enable_responder(dhd_pub_t *dhd, wifi_channel_info *channel_info);
int
dhd_rtt_cancel_responder(dhd_pub_t *dhd);
int
dhd_rtt_init(dhd_pub_t *dhd);
int
dhd_rtt_deinit(dhd_pub_t *dhd);
#ifdef WL_CFG80211
int dhd_rtt_handle_nan_rtt_session_end(dhd_pub_t *dhd,
struct ether_addr *peer);
void dhd_rtt_move_geofence_cur_target_idx_to_next(dhd_pub_t *dhd);
int8 dhd_rtt_get_geofence_cur_target_idx(dhd_pub_t *dhd);
#endif /* WL_CFG80211 */
#endif /* __DHD_RTT_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,586 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/skbuff.h>
#define DHD_STATIC_VERSION_STR "100.10.545.7 (r826445-20200110-2)"
#define BCMDHD_SDIO
#define BCMDHD_PCIE
enum dhd_prealloc_index {
DHD_PREALLOC_PROT = 0,
#if defined(BCMDHD_SDIO)
DHD_PREALLOC_RXBUF = 1,
DHD_PREALLOC_DATABUF = 2,
#endif
DHD_PREALLOC_OSL_BUF = 3,
DHD_PREALLOC_SKB_BUF = 4,
DHD_PREALLOC_WIPHY_ESCAN0 = 5,
DHD_PREALLOC_WIPHY_ESCAN1 = 6,
DHD_PREALLOC_DHD_INFO = 7,
DHD_PREALLOC_DHD_WLFC_INFO = 8,
#ifdef BCMDHD_PCIE
DHD_PREALLOC_IF_FLOW_LKUP = 9,
#endif
DHD_PREALLOC_MEMDUMP_BUF = 10,
DHD_PREALLOC_MEMDUMP_RAM = 11,
DHD_PREALLOC_DHD_WLFC_HANGER = 12,
DHD_PREALLOC_PKTID_MAP = 13,
DHD_PREALLOC_PKTID_MAP_IOCTL = 14,
DHD_PREALLOC_DHD_LOG_DUMP_BUF = 15,
DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX = 16,
DHD_PREALLOC_DHD_PKTLOG_DUMP_BUF = 17,
DHD_PREALLOC_STAT_REPORT_BUF = 18,
DHD_PREALLOC_WL_ESCAN = 19,
DHD_PREALLOC_FW_VERBOSE_RING = 20,
DHD_PREALLOC_FW_EVENT_RING = 21,
DHD_PREALLOC_DHD_EVENT_RING = 22,
DHD_PREALLOC_NAN_EVENT_RING = 23,
DHD_PREALLOC_MAX
};
#define STATIC_BUF_MAX_NUM 20
#define STATIC_BUF_SIZE (PAGE_SIZE*2)
#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 DHD_PREALLOC_PROT_SIZE (16 * 1024)
#define DHD_PREALLOC_RXBUF_SIZE (24 * 1024)
#define DHD_PREALLOC_DATABUF_SIZE (64 * 1024)
#define DHD_PREALLOC_OSL_BUF_SIZE (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE)
#define DHD_PREALLOC_WIPHY_ESCAN0_SIZE (64 * 1024)
#define DHD_PREALLOC_DHD_INFO_SIZE (32 * 1024)
#define DHD_PREALLOC_MEMDUMP_RAM_SIZE (1290 * 1024)
#define DHD_PREALLOC_DHD_WLFC_HANGER_SIZE (73 * 1024)
#define DHD_PREALLOC_DHD_LOG_DUMP_BUF_SIZE (1024 * 1024 * CUSTOM_LOG_DUMP_BUFSIZE_MB)
#define DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX_SIZE (8 * 1024)
#define DHD_PREALLOC_WL_ESCAN_SIZE (70 * 1024)
#ifdef CONFIG_64BIT
#define DHD_PREALLOC_IF_FLOW_LKUP_SIZE (20 * 1024 * 2)
#else
#define DHD_PREALLOC_IF_FLOW_LKUP_SIZE (20 * 1024)
#endif
#define FW_VERBOSE_RING_SIZE (256 * 1024)
#define FW_EVENT_RING_SIZE (64 * 1024)
#define DHD_EVENT_RING_SIZE (64 * 1024)
#define NAN_EVENT_RING_SIZE (64 * 1024)
#if defined(CONFIG_64BIT)
#define WLAN_DHD_INFO_BUF_SIZE (24 * 1024)
#define WLAN_DHD_WLFC_BUF_SIZE (64 * 1024)
#define WLAN_DHD_IF_FLOW_LKUP_SIZE (64 * 1024)
#else
#define WLAN_DHD_INFO_BUF_SIZE (16 * 1024)
#define WLAN_DHD_WLFC_BUF_SIZE (64 * 1024)
#define WLAN_DHD_IF_FLOW_LKUP_SIZE (20 * 1024)
#endif /* CONFIG_64BIT */
#define WLAN_DHD_MEMDUMP_SIZE (800 * 1024)
#define DHD_SKB_1PAGE_BUFSIZE (PAGE_SIZE*1)
#define DHD_SKB_2PAGE_BUFSIZE (PAGE_SIZE*2)
#define DHD_SKB_4PAGE_BUFSIZE (PAGE_SIZE*4)
#define DHD_SKB_1PAGE_BUF_NUM 8
#ifdef BCMDHD_PCIE
#define DHD_SKB_2PAGE_BUF_NUM 64
#elif defined(BCMDHD_SDIO)
#define DHD_SKB_2PAGE_BUF_NUM 8
#endif
#define DHD_SKB_4PAGE_BUF_NUM 1
/* The number is defined in linux_osl.c
* WLAN_SKB_1_2PAGE_BUF_NUM => STATIC_PKT_1_2PAGE_NUM
* WLAN_SKB_BUF_NUM => STATIC_PKT_MAX_NUM
*/
#define WLAN_SKB_1_2PAGE_BUF_NUM ((DHD_SKB_1PAGE_BUF_NUM) + \
(DHD_SKB_2PAGE_BUF_NUM))
#define WLAN_SKB_BUF_NUM ((WLAN_SKB_1_2PAGE_BUF_NUM) + (DHD_SKB_4PAGE_BUF_NUM))
void *wlan_static_prot = NULL;
void *wlan_static_rxbuf = NULL;
void *wlan_static_databuf = NULL;
void *wlan_static_osl_buf = NULL;
void *wlan_static_scan_buf0 = NULL;
void *wlan_static_scan_buf1 = NULL;
void *wlan_static_dhd_info_buf = NULL;
void *wlan_static_dhd_wlfc_info_buf = NULL;
void *wlan_static_if_flow_lkup = NULL;
void *wlan_static_dhd_memdump_ram_buf = NULL;
void *wlan_static_dhd_wlfc_hanger_buf = NULL;
void *wlan_static_dhd_log_dump_buf = NULL;
void *wlan_static_dhd_log_dump_buf_ex = NULL;
void *wlan_static_wl_escan_info_buf = NULL;
void *wlan_static_fw_verbose_ring_buf = NULL;
void *wlan_static_fw_event_ring_buf = NULL;
void *wlan_static_dhd_event_ring_buf = NULL;
void *wlan_static_nan_event_ring_buf = NULL;
static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM];
void *dhd_wlan_mem_prealloc(int section, unsigned long size)
{
pr_err("%s: sectoin %d, %ld\n", __func__, section, size);
if (section == DHD_PREALLOC_PROT)
return wlan_static_prot;
#if defined(BCMDHD_SDIO)
if (section == DHD_PREALLOC_RXBUF)
return wlan_static_rxbuf;
if (section == DHD_PREALLOC_DATABUF)
return wlan_static_databuf;
#endif /* BCMDHD_SDIO */
if (section == DHD_PREALLOC_SKB_BUF)
return wlan_static_skb;
if (section == DHD_PREALLOC_WIPHY_ESCAN0)
return wlan_static_scan_buf0;
if (section == DHD_PREALLOC_WIPHY_ESCAN1)
return wlan_static_scan_buf1;
if (section == DHD_PREALLOC_OSL_BUF) {
if (size > DHD_PREALLOC_OSL_BUF_SIZE) {
pr_err("request OSL_BUF(%lu) > %ld\n",
size, DHD_PREALLOC_OSL_BUF_SIZE);
return NULL;
}
return wlan_static_osl_buf;
}
if (section == DHD_PREALLOC_DHD_INFO) {
if (size > DHD_PREALLOC_DHD_INFO_SIZE) {
pr_err("request DHD_INFO size(%lu) > %d\n",
size, DHD_PREALLOC_DHD_INFO_SIZE);
return NULL;
}
return wlan_static_dhd_info_buf;
}
if (section == DHD_PREALLOC_DHD_WLFC_INFO) {
if (size > WLAN_DHD_WLFC_BUF_SIZE) {
pr_err("request DHD_WLFC_INFO size(%lu) > %d\n",
size, WLAN_DHD_WLFC_BUF_SIZE);
return NULL;
}
return wlan_static_dhd_wlfc_info_buf;
}
#ifdef BCMDHD_PCIE
if (section == DHD_PREALLOC_IF_FLOW_LKUP) {
if (size > DHD_PREALLOC_IF_FLOW_LKUP_SIZE) {
pr_err("request DHD_IF_FLOW_LKUP size(%lu) > %d\n",
size, DHD_PREALLOC_IF_FLOW_LKUP_SIZE);
return NULL;
}
return wlan_static_if_flow_lkup;
}
#endif /* BCMDHD_PCIE */
if (section == DHD_PREALLOC_MEMDUMP_RAM) {
if (size > DHD_PREALLOC_MEMDUMP_RAM_SIZE) {
pr_err("request DHD_PREALLOC_MEMDUMP_RAM_SIZE(%lu) > %d\n",
size, DHD_PREALLOC_MEMDUMP_RAM_SIZE);
return NULL;
}
return wlan_static_dhd_memdump_ram_buf;
}
if (section == DHD_PREALLOC_DHD_WLFC_HANGER) {
if (size > DHD_PREALLOC_DHD_WLFC_HANGER_SIZE) {
pr_err("request DHD_WLFC_HANGER size(%lu) > %d\n",
size, DHD_PREALLOC_DHD_WLFC_HANGER_SIZE);
return NULL;
}
return wlan_static_dhd_wlfc_hanger_buf;
}
if (section == DHD_PREALLOC_DHD_LOG_DUMP_BUF) {
if (size > DHD_PREALLOC_DHD_LOG_DUMP_BUF_SIZE) {
pr_err("request DHD_PREALLOC_DHD_LOG_DUMP_BUF_SIZE(%lu) > %d\n",
size, DHD_PREALLOC_DHD_LOG_DUMP_BUF_SIZE);
return NULL;
}
return wlan_static_dhd_log_dump_buf;
}
if (section == DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX) {
if (size > DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX_SIZE) {
pr_err("request DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX_SIZE(%lu) > %d\n",
size, DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX_SIZE);
return NULL;
}
return wlan_static_dhd_log_dump_buf_ex;
}
if (section == DHD_PREALLOC_WL_ESCAN) {
if (size > DHD_PREALLOC_WL_ESCAN_SIZE) {
pr_err("request DHD_PREALLOC_WL_ESCAN_SIZE(%lu) > %d\n",
size, DHD_PREALLOC_WL_ESCAN_SIZE);
return NULL;
}
return wlan_static_wl_escan_info_buf;
}
if (section == DHD_PREALLOC_FW_VERBOSE_RING) {
if (size > FW_VERBOSE_RING_SIZE) {
pr_err("request DHD_PREALLOC_FW_VERBOSE_RING(%lu) > %d\n",
size, FW_VERBOSE_RING_SIZE);
return NULL;
}
return wlan_static_fw_verbose_ring_buf;
}
if (section == DHD_PREALLOC_FW_EVENT_RING) {
if (size > FW_EVENT_RING_SIZE) {
pr_err("request DHD_PREALLOC_FW_EVENT_RING(%lu) > %d\n",
size, FW_EVENT_RING_SIZE);
return NULL;
}
return wlan_static_fw_event_ring_buf;
}
if (section == DHD_PREALLOC_DHD_EVENT_RING) {
if (size > DHD_EVENT_RING_SIZE) {
pr_err("request DHD_PREALLOC_DHD_EVENT_RING(%lu) > %d\n",
size, DHD_EVENT_RING_SIZE);
return NULL;
}
return wlan_static_dhd_event_ring_buf;
}
if (section == DHD_PREALLOC_NAN_EVENT_RING) {
if (size > NAN_EVENT_RING_SIZE) {
pr_err("request DHD_PREALLOC_NAN_EVENT_RING(%lu) > %d\n",
size, NAN_EVENT_RING_SIZE);
return NULL;
}
return wlan_static_nan_event_ring_buf;
}
if ((section < 0) || (section > DHD_PREALLOC_MAX))
pr_err("request section id(%d) is out of max index %d\n",
section, DHD_PREALLOC_MAX);
pr_err("%s: failed to alloc section %d, size=%ld\n",
__func__, section, size);
return NULL;
}
EXPORT_SYMBOL(dhd_wlan_mem_prealloc);
static int dhd_init_wlan_mem(void)
{
int i;
int j;
printk(KERN_ERR "%s(): %s\n", __func__, DHD_STATIC_VERSION_STR);
for (i = 0; i < DHD_SKB_1PAGE_BUF_NUM; i++) {
wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_1PAGE_BUFSIZE);
if (!wlan_static_skb[i]) {
goto err_skb_alloc;
}
pr_err("%s: sectoin %d skb[%d], size=%ld\n", __func__,
DHD_PREALLOC_SKB_BUF, i, DHD_SKB_1PAGE_BUFSIZE);
}
for (i = DHD_SKB_1PAGE_BUF_NUM; i < WLAN_SKB_1_2PAGE_BUF_NUM; i++) {
wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_2PAGE_BUFSIZE);
if (!wlan_static_skb[i]) {
goto err_skb_alloc;
}
pr_err("%s: sectoin %d skb[%d], size=%ld\n", __func__,
DHD_PREALLOC_SKB_BUF, i, DHD_SKB_2PAGE_BUFSIZE);
}
#if defined(BCMDHD_SDIO)
wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_4PAGE_BUFSIZE);
if (!wlan_static_skb[i])
goto err_skb_alloc;
pr_err("%s: sectoin %d skb[%d], size=%ld\n", __func__,
DHD_PREALLOC_SKB_BUF, i, DHD_SKB_4PAGE_BUFSIZE);
#endif /* BCMDHD_SDIO */
wlan_static_prot = kmalloc(DHD_PREALLOC_PROT_SIZE, GFP_KERNEL);
if (!wlan_static_prot)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%d\n", __func__,
DHD_PREALLOC_PROT, DHD_PREALLOC_PROT_SIZE);
#if defined(BCMDHD_SDIO)
wlan_static_rxbuf = kmalloc(DHD_PREALLOC_RXBUF_SIZE, GFP_KERNEL);
if (!wlan_static_rxbuf)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%d\n", __func__,
DHD_PREALLOC_RXBUF, DHD_PREALLOC_RXBUF_SIZE);
wlan_static_databuf = kmalloc(DHD_PREALLOC_DATABUF_SIZE, GFP_KERNEL);
if (!wlan_static_databuf)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%d\n", __func__,
DHD_PREALLOC_DATABUF, DHD_PREALLOC_DATABUF_SIZE);
#endif /* BCMDHD_SDIO */
wlan_static_osl_buf = kmalloc(DHD_PREALLOC_OSL_BUF_SIZE, GFP_KERNEL);
if (!wlan_static_osl_buf)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%ld\n", __func__,
DHD_PREALLOC_OSL_BUF, DHD_PREALLOC_OSL_BUF_SIZE);
wlan_static_scan_buf0 = kmalloc(DHD_PREALLOC_WIPHY_ESCAN0_SIZE, GFP_KERNEL);
if (!wlan_static_scan_buf0)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%d\n", __func__,
DHD_PREALLOC_WIPHY_ESCAN0, DHD_PREALLOC_WIPHY_ESCAN0_SIZE);
wlan_static_dhd_info_buf = kmalloc(DHD_PREALLOC_DHD_INFO_SIZE, GFP_KERNEL);
if (!wlan_static_dhd_info_buf)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%d\n", __func__,
DHD_PREALLOC_DHD_INFO, DHD_PREALLOC_DHD_INFO_SIZE);
wlan_static_dhd_wlfc_info_buf = kmalloc(WLAN_DHD_WLFC_BUF_SIZE, GFP_KERNEL);
if (!wlan_static_dhd_wlfc_info_buf)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%d\n", __func__,
DHD_PREALLOC_DHD_WLFC_INFO, WLAN_DHD_WLFC_BUF_SIZE);
#ifdef BCMDHD_PCIE
wlan_static_if_flow_lkup = kmalloc(DHD_PREALLOC_IF_FLOW_LKUP_SIZE, GFP_KERNEL);
if (!wlan_static_if_flow_lkup)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%d\n", __func__,
DHD_PREALLOC_IF_FLOW_LKUP, DHD_PREALLOC_IF_FLOW_LKUP_SIZE);
#endif /* BCMDHD_PCIE */
wlan_static_dhd_memdump_ram_buf = kmalloc(DHD_PREALLOC_MEMDUMP_RAM_SIZE, GFP_KERNEL);
if (!wlan_static_dhd_memdump_ram_buf)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%d\n", __func__,
DHD_PREALLOC_MEMDUMP_RAM, DHD_PREALLOC_MEMDUMP_RAM_SIZE);
wlan_static_dhd_wlfc_hanger_buf = kmalloc(DHD_PREALLOC_DHD_WLFC_HANGER_SIZE, GFP_KERNEL);
if (!wlan_static_dhd_wlfc_hanger_buf)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%d\n", __func__,
DHD_PREALLOC_DHD_WLFC_HANGER, DHD_PREALLOC_DHD_WLFC_HANGER_SIZE);
wlan_static_dhd_log_dump_buf = kmalloc(DHD_PREALLOC_DHD_LOG_DUMP_BUF_SIZE, GFP_KERNEL);
if (!wlan_static_dhd_log_dump_buf)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%d\n", __func__,
DHD_PREALLOC_DHD_LOG_DUMP_BUF, DHD_PREALLOC_DHD_LOG_DUMP_BUF_SIZE);
wlan_static_dhd_log_dump_buf_ex = kmalloc(DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX_SIZE, GFP_KERNEL);
if (!wlan_static_dhd_log_dump_buf_ex)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%d\n", __func__,
DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX, DHD_PREALLOC_DHD_LOG_DUMP_BUF_EX_SIZE);
wlan_static_wl_escan_info_buf = kmalloc(DHD_PREALLOC_WL_ESCAN_SIZE, GFP_KERNEL);
if (!wlan_static_wl_escan_info_buf)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%d\n", __func__,
DHD_PREALLOC_WL_ESCAN, DHD_PREALLOC_WL_ESCAN_SIZE);
wlan_static_fw_verbose_ring_buf = kmalloc(FW_VERBOSE_RING_SIZE, GFP_KERNEL);
if (!wlan_static_fw_verbose_ring_buf)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%d\n", __func__,
DHD_PREALLOC_FW_VERBOSE_RING, FW_VERBOSE_RING_SIZE);
wlan_static_fw_event_ring_buf = kmalloc(FW_EVENT_RING_SIZE, GFP_KERNEL);
if (!wlan_static_fw_event_ring_buf)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%d\n", __func__,
DHD_PREALLOC_FW_EVENT_RING, FW_EVENT_RING_SIZE);
wlan_static_dhd_event_ring_buf = kmalloc(DHD_EVENT_RING_SIZE, GFP_KERNEL);
if (!wlan_static_dhd_event_ring_buf)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%d\n", __func__,
DHD_PREALLOC_DHD_EVENT_RING, DHD_EVENT_RING_SIZE);
wlan_static_nan_event_ring_buf = kmalloc(NAN_EVENT_RING_SIZE, GFP_KERNEL);
if (!wlan_static_nan_event_ring_buf)
goto err_mem_alloc;
pr_err("%s: sectoin %d, size=%d\n", __func__,
DHD_PREALLOC_NAN_EVENT_RING, NAN_EVENT_RING_SIZE);
return 0;
err_mem_alloc:
if (wlan_static_prot)
kfree(wlan_static_prot);
#if defined(BCMDHD_SDIO)
if (wlan_static_rxbuf)
kfree(wlan_static_rxbuf);
if (wlan_static_databuf)
kfree(wlan_static_databuf);
#endif /* BCMDHD_SDIO */
if (wlan_static_osl_buf)
kfree(wlan_static_osl_buf);
if (wlan_static_scan_buf0)
kfree(wlan_static_scan_buf0);
if (wlan_static_scan_buf1)
kfree(wlan_static_scan_buf1);
if (wlan_static_dhd_info_buf)
kfree(wlan_static_dhd_info_buf);
if (wlan_static_dhd_wlfc_info_buf)
kfree(wlan_static_dhd_wlfc_info_buf);
#ifdef BCMDHD_PCIE
if (wlan_static_if_flow_lkup)
kfree(wlan_static_if_flow_lkup);
#endif /* BCMDHD_PCIE */
if (wlan_static_dhd_memdump_ram_buf)
kfree(wlan_static_dhd_memdump_ram_buf);
if (wlan_static_dhd_wlfc_hanger_buf)
kfree(wlan_static_dhd_wlfc_hanger_buf);
if (wlan_static_dhd_log_dump_buf)
kfree(wlan_static_dhd_log_dump_buf);
if (wlan_static_dhd_log_dump_buf_ex)
kfree(wlan_static_dhd_log_dump_buf_ex);
if (wlan_static_wl_escan_info_buf)
kfree(wlan_static_wl_escan_info_buf);
#ifdef BCMDHD_PCIE
if (wlan_static_fw_verbose_ring_buf)
kfree(wlan_static_fw_verbose_ring_buf);
if (wlan_static_fw_event_ring_buf)
kfree(wlan_static_fw_event_ring_buf);
if (wlan_static_dhd_event_ring_buf)
kfree(wlan_static_dhd_event_ring_buf);
if (wlan_static_nan_event_ring_buf)
kfree(wlan_static_nan_event_ring_buf);
#endif /* BCMDHD_PCIE */
pr_err("%s: Failed to mem_alloc for WLAN\n", __func__);
i = WLAN_SKB_BUF_NUM;
err_skb_alloc:
pr_err("%s: Failed to skb_alloc for WLAN\n", __func__);
for (j = 0; j < i; j++)
dev_kfree_skb(wlan_static_skb[j]);
return -ENOMEM;
}
static int __init
dhd_static_buf_init(void)
{
dhd_init_wlan_mem();
return 0;
}
static void __exit
dhd_static_buf_exit(void)
{
int i;
pr_err("%s()\n", __FUNCTION__);
for (i = 0; i < DHD_SKB_1PAGE_BUF_NUM; i++) {
if (wlan_static_skb[i])
dev_kfree_skb(wlan_static_skb[i]);
}
for (i = DHD_SKB_1PAGE_BUF_NUM; i < WLAN_SKB_1_2PAGE_BUF_NUM; i++) {
if (wlan_static_skb[i])
dev_kfree_skb(wlan_static_skb[i]);
}
#if defined(BCMDHD_SDIO)
if (wlan_static_skb[i])
dev_kfree_skb(wlan_static_skb[i]);
#endif /* BCMDHD_SDIO */
if (wlan_static_prot)
kfree(wlan_static_prot);
#if defined(BCMDHD_SDIO)
if (wlan_static_rxbuf)
kfree(wlan_static_rxbuf);
if (wlan_static_databuf)
kfree(wlan_static_databuf);
#endif /* BCMDHD_SDIO */
if (wlan_static_osl_buf)
kfree(wlan_static_osl_buf);
if (wlan_static_scan_buf0)
kfree(wlan_static_scan_buf0);
if (wlan_static_scan_buf1)
kfree(wlan_static_scan_buf1);
if (wlan_static_dhd_info_buf)
kfree(wlan_static_dhd_info_buf);
if (wlan_static_dhd_wlfc_info_buf)
kfree(wlan_static_dhd_wlfc_info_buf);
#ifdef BCMDHD_PCIE
if (wlan_static_if_flow_lkup)
kfree(wlan_static_if_flow_lkup);
#endif /* BCMDHD_PCIE */
if (wlan_static_dhd_memdump_ram_buf)
kfree(wlan_static_dhd_memdump_ram_buf);
if (wlan_static_dhd_wlfc_hanger_buf)
kfree(wlan_static_dhd_wlfc_hanger_buf);
if (wlan_static_dhd_log_dump_buf)
kfree(wlan_static_dhd_log_dump_buf);
if (wlan_static_dhd_log_dump_buf_ex)
kfree(wlan_static_dhd_log_dump_buf_ex);
if (wlan_static_wl_escan_info_buf)
kfree(wlan_static_wl_escan_info_buf);
#ifdef BCMDHD_PCIE
if (wlan_static_fw_verbose_ring_buf)
kfree(wlan_static_fw_verbose_ring_buf);
if (wlan_static_fw_event_ring_buf)
kfree(wlan_static_fw_event_ring_buf);
if (wlan_static_dhd_event_ring_buf)
kfree(wlan_static_dhd_event_ring_buf);
if (wlan_static_nan_event_ring_buf)
kfree(wlan_static_nan_event_ring_buf);
#endif
return;
}
module_init(dhd_static_buf_init);
module_exit(dhd_static_buf_exit);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,563 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dhd_wlfc.h 690477 2017-03-16 10:17:17Z $
*
*/
#ifndef __wlfc_host_driver_definitions_h__
#define __wlfc_host_driver_definitions_h__
/* #define OOO_DEBUG */
#define KERNEL_THREAD_RETURN_TYPE int
typedef int (*f_commitpkt_t)(void* ctx, void* p);
typedef bool (*f_processpkt_t)(void* p, void* arg);
#define WLFC_UNSUPPORTED -9999
#define WLFC_NO_TRAFFIC -1
#define WLFC_MULTI_TRAFFIC 0
#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */
/** 16 bits will provide an absolute max of 65536 slots */
#define WLFC_HANGER_MAXITEMS 3072
#define WLFC_HANGER_ITEM_STATE_FREE 1
#define WLFC_HANGER_ITEM_STATE_INUSE 2
#define WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3
#define WLFC_HANGER_ITEM_STATE_FLUSHED 4
#define WLFC_HANGER_PKT_STATE_TXSTATUS 1
#define WLFC_HANGER_PKT_STATE_BUSRETURNED 2
#define WLFC_HANGER_PKT_STATE_COMPLETE \
(WLFC_HANGER_PKT_STATE_TXSTATUS | WLFC_HANGER_PKT_STATE_BUSRETURNED)
typedef enum {
Q_TYPE_PSQ, /**< Power Save Queue, contains both delayed and suppressed packets */
Q_TYPE_AFQ /**< At Firmware Queue */
} q_type_t;
typedef enum ewlfc_packet_state {
eWLFC_PKTTYPE_NEW, /**< unused in the code (Jan 2015) */
eWLFC_PKTTYPE_DELAYED, /**< packet did not enter wlfc yet */
eWLFC_PKTTYPE_SUPPRESSED, /**< packet entered wlfc and was suppressed by the dongle */
eWLFC_PKTTYPE_MAX
} ewlfc_packet_state_t;
typedef enum ewlfc_mac_entry_action {
eWLFC_MAC_ENTRY_ACTION_ADD,
eWLFC_MAC_ENTRY_ACTION_DEL,
eWLFC_MAC_ENTRY_ACTION_UPDATE,
eWLFC_MAC_ENTRY_ACTION_MAX
} ewlfc_mac_entry_action_t;
typedef struct wlfc_hanger_item {
uint8 state;
uint8 gen;
uint8 pkt_state; /**< bitmask containing eg WLFC_HANGER_PKT_STATE_TXCOMPLETE */
uint8 pkt_txstatus;
uint32 identifier;
void* pkt;
#ifdef PROP_TXSTATUS_DEBUG
uint32 push_time;
#endif // endif
struct wlfc_hanger_item *next;
} wlfc_hanger_item_t;
/** hanger contains packets that have been posted by the dhd to the dongle and are expected back */
typedef struct wlfc_hanger {
int max_items;
uint32 pushed;
uint32 popped;
uint32 failed_to_push;
uint32 failed_to_pop;
uint32 failed_slotfind;
uint32 slot_pos;
wlfc_hanger_item_t items[1];
} wlfc_hanger_t;
#define WLFC_HANGER_SIZE(n) ((sizeof(wlfc_hanger_t) - \
sizeof(wlfc_hanger_item_t)) + ((n)*sizeof(wlfc_hanger_item_t)))
#define WLFC_STATE_OPEN 1 /**< remote MAC is able to receive packets */
#define WLFC_STATE_CLOSE 2 /**< remote MAC is in power save mode */
#define WLFC_PSQ_PREC_COUNT ((AC_COUNT + 1) * 2) /**< 2 for each AC traffic and bc/mc */
#define WLFC_AFQ_PREC_COUNT (AC_COUNT + 1)
#define WLFC_PSQ_LEN (4096 * 8)
#ifdef BCMDBUS
#define WLFC_FLOWCONTROL_HIWATER 512
#define WLFC_FLOWCONTROL_LOWATER (WLFC_FLOWCONTROL_HIWATER / 4)
#else
#define WLFC_FLOWCONTROL_HIWATER ((4096 * 8) - 256)
#define WLFC_FLOWCONTROL_LOWATER 256
#endif
#if (WLFC_FLOWCONTROL_HIWATER >= (WLFC_PSQ_LEN - 256))
#undef WLFC_FLOWCONTROL_HIWATER
#define WLFC_FLOWCONTROL_HIWATER (WLFC_PSQ_LEN - 256)
#undef WLFC_FLOWCONTROL_LOWATER
#define WLFC_FLOWCONTROL_LOWATER (WLFC_FLOWCONTROL_HIWATER / 4)
#endif // endif
#define WLFC_LOG_BUF_SIZE (1024*1024)
/** Properties related to a remote MAC entity */
typedef struct wlfc_mac_descriptor {
uint8 occupied; /**< if 0, this descriptor is unused and thus can be (re)used */
uint8 interface_id;
uint8 iftype; /**< eg WLC_E_IF_ROLE_STA */
uint8 state; /**< eg WLFC_STATE_OPEN */
uint8 ac_bitmap; /**< automatic power save delivery (APSD) */
uint8 requested_credit;
uint8 requested_packet; /**< unit: [number of packets] */
uint8 ea[ETHER_ADDR_LEN];
/** maintain (MAC,AC) based seq count for packets going to the device. As well as bc/mc. */
uint8 seq[AC_COUNT + 1];
uint8 generation; /**< toggles between 0 and 1 */
struct pktq psq; /**< contains both 'delayed' and 'suppressed' packets */
/** packets at firmware queue */
struct pktq afq;
/** The AC pending bitmap that was reported to the fw at last change */
uint8 traffic_lastreported_bmp;
/** The new AC pending bitmap */
uint8 traffic_pending_bmp;
/** 1= send on next opportunity */
uint8 send_tim_signal;
uint8 mac_handle; /**< mac handles are assigned by the dongle */
/** Number of packets at dongle for this entry. */
int transit_count;
/** Number of suppression to wait before evict from delayQ */
int suppr_transit_count;
/** pkt sent to bus but no bus TX complete yet */
int onbus_pkts_count;
/** flag. TRUE when remote MAC is in suppressed state */
uint8 suppressed;
#ifdef PROP_TXSTATUS_DEBUG
uint32 dstncredit_sent_packets;
uint32 dstncredit_acks;
uint32 opened_ct;
uint32 closed_ct;
#endif // endif
struct wlfc_mac_descriptor* prev;
struct wlfc_mac_descriptor* next;
} wlfc_mac_descriptor_t;
/** A 'commit' is the hand over of a packet from the host OS layer to the layer below (eg DBUS) */
typedef struct dhd_wlfc_commit_info {
uint8 needs_hdr;
uint8 ac_fifo_credit_spent;
ewlfc_packet_state_t pkt_type;
wlfc_mac_descriptor_t* mac_entry;
void* p;
} dhd_wlfc_commit_info_t;
#define WLFC_DECR_SEQCOUNT(entry, prec) do { if (entry->seq[(prec)] == 0) {\
entry->seq[prec] = 0xff; } else entry->seq[prec]--;} while (0)
#define WLFC_INCR_SEQCOUNT(entry, prec) entry->seq[(prec)]++
#define WLFC_SEQCOUNT(entry, prec) entry->seq[(prec)]
typedef struct athost_wl_stat_counters {
uint32 pktin;
uint32 pktout;
uint32 pkt2bus;
uint32 pktdropped;
uint32 tlv_parse_failed;
uint32 rollback;
uint32 rollback_failed;
uint32 delayq_full_error;
uint32 credit_request_failed;
uint32 packet_request_failed;
uint32 mac_update_failed;
uint32 psmode_update_failed;
uint32 interface_update_failed;
uint32 wlfc_header_only_pkt;
uint32 txstatus_in;
uint32 d11_suppress;
uint32 wl_suppress;
uint32 bad_suppress;
uint32 pkt_dropped;
uint32 pkt_exptime;
uint32 pkt_freed;
uint32 pkt_free_err;
uint32 psq_wlsup_retx;
uint32 psq_wlsup_enq;
uint32 psq_d11sup_retx;
uint32 psq_d11sup_enq;
uint32 psq_hostq_retx;
uint32 psq_hostq_enq;
uint32 mac_handle_notfound;
uint32 wlc_tossed_pkts;
uint32 dhd_hdrpulls;
uint32 generic_error;
/* an extra one for bc/mc traffic */
uint32 send_pkts[AC_COUNT + 1];
uint32 drop_pkts[WLFC_PSQ_PREC_COUNT];
uint32 ooo_pkts[AC_COUNT + 1];
#ifdef PROP_TXSTATUS_DEBUG
/** all pkt2bus -> txstatus latency accumulated */
uint32 latency_sample_count;
uint32 total_status_latency;
uint32 latency_most_recent;
int idx_delta;
uint32 deltas[10];
uint32 fifo_credits_sent[6];
uint32 fifo_credits_back[6];
uint32 dropped_qfull[6];
uint32 signal_only_pkts_sent;
uint32 signal_only_pkts_freed;
#endif // endif
uint32 cleanup_txq_cnt;
uint32 cleanup_psq_cnt;
uint32 cleanup_fw_cnt;
} athost_wl_stat_counters_t;
#ifdef PROP_TXSTATUS_DEBUG
#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do { \
(ctx)->stats.fifo_credits_sent[(ac)]++;} while (0)
#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do { \
(ctx)->stats.fifo_credits_back[(ac)]++;} while (0)
#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do { \
(ctx)->stats.dropped_qfull[(ac)]++;} while (0)
#else
#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do {} while (0)
#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do {} while (0)
#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do {} while (0)
#endif // endif
#define WLFC_PACKET_BOUND 10
#define WLFC_FCMODE_NONE 0
#define WLFC_FCMODE_IMPLIED_CREDIT 1
#define WLFC_FCMODE_EXPLICIT_CREDIT 2
#define WLFC_ONLY_AMPDU_HOSTREORDER 3
/** Reserved credits ratio when borrowed by hihger priority */
#define WLFC_BORROW_LIMIT_RATIO 4
/** How long to defer borrowing in milliseconds */
#define WLFC_BORROW_DEFER_PERIOD_MS 100
/** How long to defer flow control in milliseconds */
#define WLFC_FC_DEFER_PERIOD_MS 200
/** How long to detect occurance per AC in miliseconds */
#define WLFC_RX_DETECTION_THRESHOLD_MS 100
/** Mask to represent available ACs (note: BC/MC is ignored) */
#define WLFC_AC_MASK 0xF
/** flow control specific information, only 1 instance during driver lifetime */
typedef struct athost_wl_status_info {
uint8 last_seqid_to_wlc;
/** OSL handle */
osl_t *osh;
/** dhd public struct pointer */
void *dhdp;
f_commitpkt_t fcommit;
void* commit_ctx;
/** statistics */
athost_wl_stat_counters_t stats;
/** incremented on eg receiving a credit map event from the dongle */
int Init_FIFO_credit[AC_COUNT + 2];
/** the additional ones are for bc/mc and ATIM FIFO */
int FIFO_credit[AC_COUNT + 2];
/** Credit borrow counts for each FIFO from each of the other FIFOs */
int credits_borrowed[AC_COUNT + 2][AC_COUNT + 2];
/** packet hanger and MAC->handle lookup table */
void *hanger;
struct {
/** table for individual nodes */
wlfc_mac_descriptor_t nodes[WLFC_MAC_DESC_TABLE_SIZE];
/** table for interfaces */
wlfc_mac_descriptor_t interfaces[WLFC_MAX_IFNUM];
/* OS may send packets to unknown (unassociated) destinations */
/** A place holder for bc/mc and packets to unknown destinations */
wlfc_mac_descriptor_t other;
} destination_entries;
wlfc_mac_descriptor_t *active_entry_head; /**< a chain of MAC descriptors */
int active_entry_count;
wlfc_mac_descriptor_t *requested_entry[WLFC_MAC_DESC_TABLE_SIZE];
int requested_entry_count;
/* pkt counts for each interface and ac */
int pkt_cnt_in_q[WLFC_MAX_IFNUM][AC_COUNT+1];
int pkt_cnt_per_ac[AC_COUNT+1];
int pkt_cnt_in_drv[WLFC_MAX_IFNUM][AC_COUNT+1];
int pkt_cnt_in_psq;
uint8 allow_fc; /**< Boolean */
uint32 fc_defer_timestamp;
uint32 rx_timestamp[AC_COUNT+1];
/** ON/OFF state for flow control to the host network interface */
uint8 hostif_flow_state[WLFC_MAX_IFNUM];
uint8 host_ifidx;
/** to flow control an OS interface */
uint8 toggle_host_if;
/** To borrow credits */
uint8 allow_credit_borrow;
/** ac number for the first single ac traffic */
uint8 single_ac;
/** Timestamp for the first single ac traffic */
uint32 single_ac_timestamp;
bool bcmc_credit_supported;
} athost_wl_status_info_t;
/** Please be mindful that total pkttag space is 32 octets only */
typedef struct dhd_pkttag {
#ifdef BCM_OBJECT_TRACE
/* if use this field, keep it at the first 4 bytes */
uint32 sn;
#endif /* BCM_OBJECT_TRACE */
/**
b[15] - 1 = wlfc packet
b[14:13] - encryption exemption
b[12 ] - 1 = event channel
b[11 ] - 1 = this packet was sent in response to one time packet request,
do not increment credit on status for this one. [WLFC_CTL_TYPE_MAC_REQUEST_PACKET].
b[10 ] - 1 = signal-only-packet to firmware [i.e. nothing to piggyback on]
b[9 ] - 1 = packet is host->firmware (transmit direction)
- 0 = packet received from firmware (firmware->host)
b[8 ] - 1 = packet was sent due to credit_request (pspoll),
packet does not count against FIFO credit.
- 0 = normal transaction, packet counts against FIFO credit
b[7 ] - 1 = AP, 0 = STA
b[6:4] - AC FIFO number
b[3:0] - interface index
*/
uint16 if_flags;
/**
* destination MAC address for this packet so that not every module needs to open the packet
* to find this
*/
uint8 dstn_ether[ETHER_ADDR_LEN];
/** This 32-bit goes from host to device for every packet. */
uint32 htod_tag;
/** This 16-bit is original d11seq number for every suppressed packet. */
uint16 htod_seq;
/** This address is mac entry for every packet. */
void *entry;
/** bus specific stuff */
union {
struct {
void *stuff;
uint32 thing1;
uint32 thing2;
} sd;
struct {
void *bus;
void *urb;
} usb;
} bus_specific;
} dhd_pkttag_t;
#define DHD_PKTTAG_WLFCPKT_MASK 0x1
#define DHD_PKTTAG_WLFCPKT_SHIFT 15
#define DHD_PKTTAG_WLFCPKT_SET(tag, value) ((dhd_pkttag_t*)(tag))->if_flags = \
(((dhd_pkttag_t*)(tag))->if_flags & \
~(DHD_PKTTAG_WLFCPKT_MASK << DHD_PKTTAG_WLFCPKT_SHIFT)) | \
(((value) & DHD_PKTTAG_WLFCPKT_MASK) << DHD_PKTTAG_WLFCPKT_SHIFT)
#define DHD_PKTTAG_WLFCPKT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \
DHD_PKTTAG_WLFCPKT_SHIFT) & DHD_PKTTAG_WLFCPKT_MASK)
#define DHD_PKTTAG_EXEMPT_MASK 0x3
#define DHD_PKTTAG_EXEMPT_SHIFT 13
#define DHD_PKTTAG_EXEMPT_SET(tag, value) ((dhd_pkttag_t*)(tag))->if_flags = \
(((dhd_pkttag_t*)(tag))->if_flags & \
~(DHD_PKTTAG_EXEMPT_MASK << DHD_PKTTAG_EXEMPT_SHIFT)) | \
(((value) & DHD_PKTTAG_EXEMPT_MASK) << DHD_PKTTAG_EXEMPT_SHIFT)
#define DHD_PKTTAG_EXEMPT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \
DHD_PKTTAG_EXEMPT_SHIFT) & DHD_PKTTAG_EXEMPT_MASK)
#define DHD_PKTTAG_EVENT_MASK 0x1
#define DHD_PKTTAG_EVENT_SHIFT 12
#define DHD_PKTTAG_SETEVENT(tag, event) ((dhd_pkttag_t*)(tag))->if_flags = \
(((dhd_pkttag_t*)(tag))->if_flags & \
~(DHD_PKTTAG_EVENT_MASK << DHD_PKTTAG_EVENT_SHIFT)) | \
(((event) & DHD_PKTTAG_EVENT_MASK) << DHD_PKTTAG_EVENT_SHIFT)
#define DHD_PKTTAG_EVENT(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \
DHD_PKTTAG_EVENT_SHIFT) & DHD_PKTTAG_EVENT_MASK)
#define DHD_PKTTAG_ONETIMEPKTRQST_MASK 0x1
#define DHD_PKTTAG_ONETIMEPKTRQST_SHIFT 11
#define DHD_PKTTAG_SETONETIMEPKTRQST(tag) ((dhd_pkttag_t*)(tag))->if_flags = \
(((dhd_pkttag_t*)(tag))->if_flags & \
~(DHD_PKTTAG_ONETIMEPKTRQST_MASK << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT)) | \
(1 << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT)
#define DHD_PKTTAG_ONETIMEPKTRQST(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \
DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) & DHD_PKTTAG_ONETIMEPKTRQST_MASK)
#define DHD_PKTTAG_SIGNALONLY_MASK 0x1
#define DHD_PKTTAG_SIGNALONLY_SHIFT 10
#define DHD_PKTTAG_SETSIGNALONLY(tag, signalonly) ((dhd_pkttag_t*)(tag))->if_flags = \
(((dhd_pkttag_t*)(tag))->if_flags & \
~(DHD_PKTTAG_SIGNALONLY_MASK << DHD_PKTTAG_SIGNALONLY_SHIFT)) | \
(((signalonly) & DHD_PKTTAG_SIGNALONLY_MASK) << DHD_PKTTAG_SIGNALONLY_SHIFT)
#define DHD_PKTTAG_SIGNALONLY(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \
DHD_PKTTAG_SIGNALONLY_SHIFT) & DHD_PKTTAG_SIGNALONLY_MASK)
#define DHD_PKTTAG_PKTDIR_MASK 0x1
#define DHD_PKTTAG_PKTDIR_SHIFT 9
#define DHD_PKTTAG_SETPKTDIR(tag, dir) ((dhd_pkttag_t*)(tag))->if_flags = \
(((dhd_pkttag_t*)(tag))->if_flags & \
~(DHD_PKTTAG_PKTDIR_MASK << DHD_PKTTAG_PKTDIR_SHIFT)) | \
(((dir) & DHD_PKTTAG_PKTDIR_MASK) << DHD_PKTTAG_PKTDIR_SHIFT)
#define DHD_PKTTAG_PKTDIR(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \
DHD_PKTTAG_PKTDIR_SHIFT) & DHD_PKTTAG_PKTDIR_MASK)
#define DHD_PKTTAG_CREDITCHECK_MASK 0x1
#define DHD_PKTTAG_CREDITCHECK_SHIFT 8
#define DHD_PKTTAG_SETCREDITCHECK(tag, check) ((dhd_pkttag_t*)(tag))->if_flags = \
(((dhd_pkttag_t*)(tag))->if_flags & \
~(DHD_PKTTAG_CREDITCHECK_MASK << DHD_PKTTAG_CREDITCHECK_SHIFT)) | \
(((check) & DHD_PKTTAG_CREDITCHECK_MASK) << DHD_PKTTAG_CREDITCHECK_SHIFT)
#define DHD_PKTTAG_CREDITCHECK(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \
DHD_PKTTAG_CREDITCHECK_SHIFT) & DHD_PKTTAG_CREDITCHECK_MASK)
#define DHD_PKTTAG_IFTYPE_MASK 0x1
#define DHD_PKTTAG_IFTYPE_SHIFT 7
#define DHD_PKTTAG_SETIFTYPE(tag, isAP) ((dhd_pkttag_t*)(tag))->if_flags = \
(((dhd_pkttag_t*)(tag))->if_flags & \
~(DHD_PKTTAG_IFTYPE_MASK << DHD_PKTTAG_IFTYPE_SHIFT)) | \
(((isAP) & DHD_PKTTAG_IFTYPE_MASK) << DHD_PKTTAG_IFTYPE_SHIFT)
#define DHD_PKTTAG_IFTYPE(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \
DHD_PKTTAG_IFTYPE_SHIFT) & DHD_PKTTAG_IFTYPE_MASK)
#define DHD_PKTTAG_FIFO_MASK 0x7
#define DHD_PKTTAG_FIFO_SHIFT 4
#define DHD_PKTTAG_SETFIFO(tag, fifo) ((dhd_pkttag_t*)(tag))->if_flags = \
(((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_FIFO_MASK << DHD_PKTTAG_FIFO_SHIFT)) | \
(((fifo) & DHD_PKTTAG_FIFO_MASK) << DHD_PKTTAG_FIFO_SHIFT)
#define DHD_PKTTAG_FIFO(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \
DHD_PKTTAG_FIFO_SHIFT) & DHD_PKTTAG_FIFO_MASK)
#define DHD_PKTTAG_IF_MASK 0xf
#define DHD_PKTTAG_IF_SHIFT 0
#define DHD_PKTTAG_SETIF(tag, if) ((dhd_pkttag_t*)(tag))->if_flags = \
(((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_IF_MASK << DHD_PKTTAG_IF_SHIFT)) | \
(((if) & DHD_PKTTAG_IF_MASK) << DHD_PKTTAG_IF_SHIFT)
#define DHD_PKTTAG_IF(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \
DHD_PKTTAG_IF_SHIFT) & DHD_PKTTAG_IF_MASK)
#define DHD_PKTTAG_SETDSTN(tag, dstn_MAC_ea) memcpy(((dhd_pkttag_t*)((tag)))->dstn_ether, \
(dstn_MAC_ea), ETHER_ADDR_LEN)
#define DHD_PKTTAG_DSTN(tag) ((dhd_pkttag_t*)(tag))->dstn_ether
#define DHD_PKTTAG_SET_H2DTAG(tag, h2dvalue) ((dhd_pkttag_t*)(tag))->htod_tag = (h2dvalue)
#define DHD_PKTTAG_H2DTAG(tag) (((dhd_pkttag_t*)(tag))->htod_tag)
#define DHD_PKTTAG_SET_H2DSEQ(tag, seq) ((dhd_pkttag_t*)(tag))->htod_seq = (seq)
#define DHD_PKTTAG_H2DSEQ(tag) (((dhd_pkttag_t*)(tag))->htod_seq)
#define DHD_PKTTAG_SET_ENTRY(tag, entry) ((dhd_pkttag_t*)(tag))->entry = (entry)
#define DHD_PKTTAG_ENTRY(tag) (((dhd_pkttag_t*)(tag))->entry)
#define PSQ_SUP_IDX(x) (x * 2 + 1)
#define PSQ_DLY_IDX(x) (x * 2)
#ifdef PROP_TXSTATUS_DEBUG
#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do { (entry)->closed_ct++; } while (0)
#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do { (entry)->opened_ct++; } while (0)
#else
#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do {} while (0)
#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do {} while (0)
#endif // endif
#ifdef BCM_OBJECT_TRACE
#define DHD_PKTTAG_SET_SN(tag, val) ((dhd_pkttag_t*)(tag))->sn = (val)
#define DHD_PKTTAG_SN(tag) (((dhd_pkttag_t*)(tag))->sn)
#endif /* BCM_OBJECT_TRACE */
/* public functions */
int dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len,
uchar *reorder_info_buf, uint *reorder_info_len);
KERNEL_THREAD_RETURN_TYPE dhd_wlfc_transfer_packets(void *data);
int dhd_wlfc_commit_packets(dhd_pub_t *dhdp, f_commitpkt_t fcommit,
void* commit_ctx, void *pktbuf, bool need_toggle_host_if);
int dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success);
int dhd_wlfc_init(dhd_pub_t *dhd);
#ifdef SUPPORT_P2P_GO_PS
int dhd_wlfc_suspend(dhd_pub_t *dhd);
int dhd_wlfc_resume(dhd_pub_t *dhd);
#endif /* SUPPORT_P2P_GO_PS */
int dhd_wlfc_hostreorder_init(dhd_pub_t *dhd);
int dhd_wlfc_cleanup_txq(dhd_pub_t *dhd, f_processpkt_t fn, void *arg);
int dhd_wlfc_cleanup(dhd_pub_t *dhd, f_processpkt_t fn, void* arg);
int dhd_wlfc_deinit(dhd_pub_t *dhd);
int dhd_wlfc_interface_event(dhd_pub_t *dhdp, uint8 action, uint8 ifid, uint8 iftype, uint8* ea);
int dhd_wlfc_FIFOcreditmap_event(dhd_pub_t *dhdp, uint8* event_data);
#ifdef LIMIT_BORROW
int dhd_wlfc_disable_credit_borrow_event(dhd_pub_t *dhdp, uint8* event_data);
#endif /* LIMIT_BORROW */
int dhd_wlfc_BCMCCredit_support_event(dhd_pub_t *dhdp);
int dhd_wlfc_enable(dhd_pub_t *dhdp);
int dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
int dhd_wlfc_clear_counts(dhd_pub_t *dhd);
int dhd_wlfc_get_enable(dhd_pub_t *dhd, bool *val);
int dhd_wlfc_get_mode(dhd_pub_t *dhd, int *val);
int dhd_wlfc_set_mode(dhd_pub_t *dhd, int val);
bool dhd_wlfc_is_supported(dhd_pub_t *dhd);
bool dhd_wlfc_is_header_only_pkt(dhd_pub_t * dhd, void *pktbuf);
int dhd_wlfc_flowcontrol(dhd_pub_t *dhdp, bool state, bool bAcquireLock);
int dhd_wlfc_save_rxpath_ac_time(dhd_pub_t * dhd, uint8 prio);
int dhd_wlfc_get_module_ignore(dhd_pub_t *dhd, int *val);
int dhd_wlfc_set_module_ignore(dhd_pub_t *dhd, int val);
int dhd_wlfc_get_credit_ignore(dhd_pub_t *dhd, int *val);
int dhd_wlfc_set_credit_ignore(dhd_pub_t *dhd, int val);
int dhd_wlfc_get_txstatus_ignore(dhd_pub_t *dhd, int *val);
int dhd_wlfc_set_txstatus_ignore(dhd_pub_t *dhd, int val);
int dhd_wlfc_get_rxpkt_chk(dhd_pub_t *dhd, int *val);
int dhd_wlfc_set_rxpkt_chk(dhd_pub_t *dhd, int val);
#endif /* __wlfc_host_driver_definitions_h__ */

View File

@@ -0,0 +1,387 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Common stats definitions for clients of dongle
* ports
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dngl_stats.h 716269 2017-08-17 09:22:46Z $
*/
#ifndef _dngl_stats_h_
#define _dngl_stats_h_
#include <ethernet.h>
#include <802.11.h>
typedef struct {
unsigned long rx_packets; /* total packets received */
unsigned long tx_packets; /* total packets transmitted */
unsigned long rx_bytes; /* total bytes received */
unsigned long tx_bytes; /* total bytes transmitted */
unsigned long rx_errors; /* bad packets received */
unsigned long tx_errors; /* packet transmit problems */
unsigned long rx_dropped; /* packets dropped by dongle */
unsigned long tx_dropped; /* packets dropped by dongle */
unsigned long multicast; /* multicast packets received */
} dngl_stats_t;
typedef int32 wifi_radio;
typedef int32 wifi_channel;
typedef int32 wifi_rssi;
typedef struct { uint16 version; uint16 length; } ver_len;
typedef enum wifi_channel_width {
WIFI_CHAN_WIDTH_20 = 0,
WIFI_CHAN_WIDTH_40 = 1,
WIFI_CHAN_WIDTH_80 = 2,
WIFI_CHAN_WIDTH_160 = 3,
WIFI_CHAN_WIDTH_80P80 = 4,
WIFI_CHAN_WIDTH_5 = 5,
WIFI_CHAN_WIDTH_10 = 6,
WIFI_CHAN_WIDTH_INVALID = -1
} wifi_channel_width_t;
typedef enum {
WIFI_DISCONNECTED = 0,
WIFI_AUTHENTICATING = 1,
WIFI_ASSOCIATING = 2,
WIFI_ASSOCIATED = 3,
WIFI_EAPOL_STARTED = 4, /* if done by firmware/driver */
WIFI_EAPOL_COMPLETED = 5, /* if done by firmware/driver */
} wifi_connection_state;
typedef enum {
WIFI_ROAMING_IDLE = 0,
WIFI_ROAMING_ACTIVE = 1
} wifi_roam_state;
typedef enum {
WIFI_INTERFACE_STA = 0,
WIFI_INTERFACE_SOFTAP = 1,
WIFI_INTERFACE_IBSS = 2,
WIFI_INTERFACE_P2P_CLIENT = 3,
WIFI_INTERFACE_P2P_GO = 4,
WIFI_INTERFACE_NAN = 5,
WIFI_INTERFACE_MESH = 6
} wifi_interface_mode;
#define WIFI_CAPABILITY_QOS 0x00000001 /* set for QOS association */
#define WIFI_CAPABILITY_PROTECTED 0x00000002 /* set for protected association (802.11
* beacon frame control protected bit set)
*/
#define WIFI_CAPABILITY_INTERWORKING 0x00000004 /* set if 802.11 Extended Capabilities
* element interworking bit is set
*/
#define WIFI_CAPABILITY_HS20 0x00000008 /* set for HS20 association */
#define WIFI_CAPABILITY_SSID_UTF8 0x00000010 /* set is 802.11 Extended Capabilities
* element UTF-8 SSID bit is set
*/
#define WIFI_CAPABILITY_COUNTRY 0x00000020 /* set is 802.11 Country Element is present */
#define PACK_ATTRIBUTE __attribute__ ((packed))
typedef struct {
wifi_interface_mode mode; /* interface mode */
uint8 mac_addr[6]; /* interface mac address (self) */
uint8 PAD[2];
wifi_connection_state state; /* connection state (valid for STA, CLI only) */
wifi_roam_state roaming; /* roaming state */
uint32 capabilities; /* WIFI_CAPABILITY_XXX (self) */
uint8 ssid[DOT11_MAX_SSID_LEN+1]; /* null terminated SSID */
uint8 bssid[ETHER_ADDR_LEN]; /* bssid */
uint8 PAD[1];
uint8 ap_country_str[3]; /* country string advertised by AP */
uint8 country_str[3]; /* country string for this association */
uint8 PAD[2];
} wifi_interface_info;
typedef wifi_interface_info *wifi_interface_handle;
/* channel information */
typedef struct {
wifi_channel_width_t width; /* channel width (20, 40, 80, 80+80, 160) */
wifi_channel center_freq; /* primary 20 MHz channel */
wifi_channel center_freq0; /* center frequency (MHz) first segment */
wifi_channel center_freq1; /* center frequency (MHz) second segment */
} wifi_channel_info;
/* wifi rate */
typedef struct {
uint32 preamble; /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */
uint32 nss; /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */
uint32 bw; /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */
uint32 rateMcsIdx; /* OFDM/CCK rate code would be as per ieee std
* in the units of 0.5mbps
*/
/* HT/VHT it would be mcs index */
uint32 reserved; /* reserved */
uint32 bitrate; /* units of 100 Kbps */
} wifi_rate;
typedef struct {
uint32 preamble :3; /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */
uint32 nss :2; /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */
uint32 bw :3; /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */
uint32 rateMcsIdx :8; /* OFDM/CCK rate code would be as per ieee std
* in the units of 0.5mbps HT/VHT it would be
* mcs index
*/
uint32 reserved :16; /* reserved */
uint32 bitrate; /* units of 100 Kbps */
} wifi_rate_v1;
/* channel statistics */
typedef struct {
wifi_channel_info channel; /* channel */
uint32 on_time; /* msecs the radio is awake (32 bits number
* accruing over time)
*/
uint32 cca_busy_time; /* msecs the CCA register is busy (32 bits number
* accruing over time)
*/
} wifi_channel_stat;
/* radio statistics */
typedef struct {
struct {
uint16 version;
uint16 length;
};
wifi_radio radio; /* wifi radio (if multiple radio supported) */
uint32 on_time; /* msecs the radio is awake (32 bits number
* accruing over time)
*/
uint32 tx_time; /* msecs the radio is transmitting (32 bits
* number accruing over time)
*/
uint32 rx_time; /* msecs the radio is in active receive (32 bits
* number accruing over time)
*/
uint32 on_time_scan; /* msecs the radio is awake due to all scan (32 bits
* number accruing over time)
*/
uint32 on_time_nbd; /* msecs the radio is awake due to NAN (32 bits
* number accruing over time)
*/
uint32 on_time_gscan; /* msecs the radio is awake due to G?scan (32 bits
* number accruing over time)
*/
uint32 on_time_roam_scan; /* msecs the radio is awake due to roam?scan (32 bits
* number accruing over time)
*/
uint32 on_time_pno_scan; /* msecs the radio is awake due to PNO scan (32 bits
* number accruing over time)
*/
uint32 on_time_hs20; /* msecs the radio is awake due to HS2.0 scans and
* GAS exchange (32 bits number accruing over time)
*/
uint32 num_channels; /* number of channels */
wifi_channel_stat channels[1]; /* channel statistics */
} wifi_radio_stat;
typedef struct {
wifi_radio radio;
uint32 on_time;
uint32 tx_time;
uint32 rx_time;
uint32 on_time_scan;
uint32 on_time_nbd;
uint32 on_time_gscan;
uint32 on_time_roam_scan;
uint32 on_time_pno_scan;
uint32 on_time_hs20;
uint32 num_channels;
} wifi_radio_stat_h;
/* per rate statistics */
typedef struct {
wifi_rate_v1 rate; /* rate information */
uint32 tx_mpdu; /* number of successfully transmitted data pkts (ACK rcvd) */
uint32 rx_mpdu; /* number of received data pkts */
uint32 mpdu_lost; /* number of data packet losses (no ACK) */
uint32 retries; /* total number of data pkt retries */
uint32 retries_short; /* number of short data pkt retries */
uint32 retries_long; /* number of long data pkt retries */
} wifi_rate_stat_v1;
typedef struct {
uint16 version;
uint16 length;
uint32 tx_mpdu; /* number of successfully transmitted data pkts (ACK rcvd) */
uint32 rx_mpdu; /* number of received data pkts */
uint32 mpdu_lost; /* number of data packet losses (no ACK) */
uint32 retries; /* total number of data pkt retries */
uint32 retries_short; /* number of short data pkt retries */
uint32 retries_long; /* number of long data pkt retries */
wifi_rate rate;
} wifi_rate_stat;
/* access categories */
typedef enum {
WIFI_AC_VO = 0,
WIFI_AC_VI = 1,
WIFI_AC_BE = 2,
WIFI_AC_BK = 3,
WIFI_AC_MAX = 4
} wifi_traffic_ac;
/* wifi peer type */
typedef enum
{
WIFI_PEER_STA,
WIFI_PEER_AP,
WIFI_PEER_P2P_GO,
WIFI_PEER_P2P_CLIENT,
WIFI_PEER_NAN,
WIFI_PEER_TDLS,
WIFI_PEER_INVALID
} wifi_peer_type;
/* per peer statistics */
typedef struct {
wifi_peer_type type; /* peer type (AP, TDLS, GO etc.) */
uint8 peer_mac_address[6]; /* mac address */
uint32 capabilities; /* peer WIFI_CAPABILITY_XXX */
uint32 num_rate; /* number of rates */
wifi_rate_stat rate_stats[1]; /* per rate statistics, number of entries = num_rate */
} wifi_peer_info;
/* per access category statistics */
typedef struct {
wifi_traffic_ac ac; /* access category (VI, VO, BE, BK) */
uint32 tx_mpdu; /* number of successfully transmitted unicast data pkts
* (ACK rcvd)
*/
uint32 rx_mpdu; /* number of received unicast mpdus */
uint32 tx_mcast; /* number of succesfully transmitted multicast
* data packets
*/
/* STA case: implies ACK received from AP for the
* unicast packet in which mcast pkt was sent
*/
uint32 rx_mcast; /* number of received multicast data packets */
uint32 rx_ampdu; /* number of received unicast a-mpdus */
uint32 tx_ampdu; /* number of transmitted unicast a-mpdus */
uint32 mpdu_lost; /* number of data pkt losses (no ACK) */
uint32 retries; /* total number of data pkt retries */
uint32 retries_short; /* number of short data pkt retries */
uint32 retries_long; /* number of long data pkt retries */
uint32 contention_time_min; /* data pkt min contention time (usecs) */
uint32 contention_time_max; /* data pkt max contention time (usecs) */
uint32 contention_time_avg; /* data pkt avg contention time (usecs) */
uint32 contention_num_samples; /* num of data pkts used for contention statistics */
} wifi_wmm_ac_stat;
/* interface statistics */
typedef struct {
wifi_interface_handle iface; /* wifi interface */
wifi_interface_info info; /* current state of the interface */
uint32 beacon_rx; /* access point beacon received count from
* connected AP
*/
uint64 average_tsf_offset; /* average beacon offset encountered (beacon_TSF - TBTT)
* The average_tsf_offset field is used so as to calculate
* the typical beacon contention time on the channel as well
* may be used to debug beacon synchronization and related
* power consumption issue
*/
uint32 leaky_ap_detected; /* indicate that this AP
* typically leaks packets beyond
* the driver guard time.
*/
uint32 leaky_ap_avg_num_frames_leaked; /* average number of frame leaked by AP after
* frame with PM bit set was ACK'ed by AP
*/
uint32 leaky_ap_guard_time; /* guard time currently in force
* (when implementing IEEE power management
* based on frame control PM bit), How long
* driver waits before shutting down the radio and after
* receiving an ACK for a data frame with PM bit set)
*/
uint32 mgmt_rx; /* access point mgmt frames received count from
* connected AP (including Beacon)
*/
uint32 mgmt_action_rx; /* action frames received count */
uint32 mgmt_action_tx; /* action frames transmit count */
wifi_rssi rssi_mgmt; /* access Point Beacon and Management frames RSSI
* (averaged)
*/
wifi_rssi rssi_data; /* access Point Data Frames RSSI (averaged) from
* connected AP
*/
wifi_rssi rssi_ack; /* access Point ACK RSSI (averaged) from
* connected AP
*/
wifi_wmm_ac_stat ac[WIFI_AC_MAX]; /* per ac data packet statistics */
uint32 num_peers; /* number of peers */
wifi_peer_info peer_info[1]; /* per peer statistics */
} wifi_iface_stat;
#ifdef CONFIG_COMPAT
/* interface statistics */
typedef struct {
compat_uptr_t iface; /* wifi interface */
wifi_interface_info info; /* current state of the interface */
uint32 beacon_rx; /* access point beacon received count from
* connected AP
*/
uint64 average_tsf_offset; /* average beacon offset encountered (beacon_TSF - TBTT)
* The average_tsf_offset field is used so as to calculate
* the typical beacon contention time on the channel as well
* may be used to debug beacon synchronization and related
* power consumption issue
*/
uint32 leaky_ap_detected; /* indicate that this AP
* typically leaks packets beyond
* the driver guard time.
*/
uint32 leaky_ap_avg_num_frames_leaked; /* average number of frame leaked by AP after
* frame with PM bit set was ACK'ed by AP
*/
uint32 leaky_ap_guard_time; /* guard time currently in force
* (when implementing IEEE power management
* based on frame control PM bit), How long
* driver waits before shutting down the radio and after
* receiving an ACK for a data frame with PM bit set)
*/
uint32 mgmt_rx; /* access point mgmt frames received count from
* connected AP (including Beacon)
*/
uint32 mgmt_action_rx; /* action frames received count */
uint32 mgmt_action_tx; /* action frames transmit count */
wifi_rssi rssi_mgmt; /* access Point Beacon and Management frames RSSI
* (averaged)
*/
wifi_rssi rssi_data; /* access Point Data Frames RSSI (averaged) from
* connected AP
*/
wifi_rssi rssi_ack; /* access Point ACK RSSI (averaged) from
* connected AP
*/
wifi_wmm_ac_stat ac[WIFI_AC_MAX]; /* per ac data packet statistics */
uint32 num_peers; /* number of peers */
wifi_peer_info peer_info[1]; /* per peer statistics */
} compat_wifi_iface_stat;
#endif /* CONFIG_COMPAT */
#endif /* _dngl_stats_h_ */

View File

@@ -0,0 +1,44 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Dongle WL Header definitions
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: dngl_wlhdr.h 514727 2014-11-12 03:02:48Z $
*/
#ifndef _dngl_wlhdr_h_
#define _dngl_wlhdr_h_
typedef struct wl_header {
uint8 type; /* Header type */
uint8 version; /* Header version */
int8 rssi; /* RSSI */
uint8 pad; /* Unused */
} wl_header_t;
#define WL_HEADER_LEN sizeof(wl_header_t)
#define WL_HEADER_TYPE 0
#define WL_HEADER_VER 1
#endif /* _dngl_wlhdr_h_ */

View File

@@ -0,0 +1,113 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* IE/TLV fragmentation/defragmentation support for
* Broadcom 802.11bang Networking Device Driver
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
* $Id$
*
* <<Broadcom-WL-IPTag/Open:>>
*/
#include <bcmutils.h>
#include <frag.h>
#include <802.11.h>
/* defrag a fragmented dot11 ie/tlv. if space does not permit, return the needed
* ie length to contain all the fragments with status BCME_BUFTOOSHORT.
* out_len is in/out parameter, max length on input, used/required length on output
*/
int
bcm_tlv_dot11_defrag(const void *buf, uint buf_len, uint8 id, bool id_ext,
uint8 *out, uint *out_len)
{
int err = BCME_OK;
const bcm_tlv_t *ie;
uint tot_len = 0;
uint out_left;
/* find the ie; includes validation */
ie = bcm_parse_tlvs_dot11(buf, buf_len, id, id_ext);
if (!ie) {
err = BCME_IE_NOTFOUND;
goto done;
}
out_left = (out && out_len) ? *out_len : 0;
/* first fragment */
tot_len = id_ext ? ie->len - 1 : ie->len;
/* copy out if output space permits */
if (out_left < tot_len) {
err = BCME_BUFTOOSHORT;
out_left = 0; /* prevent further copy */
} else {
memcpy(out, &ie->data[id_ext ? 1 : 0], tot_len);
out += tot_len;
out_left -= tot_len;
}
/* if not fragmened or not fragmentable per 802.11 table 9-77 11md0.1 bail
* we can introduce the latter check later
*/
if (ie->len != BCM_TLV_MAX_DATA_SIZE) {
goto done;
}
/* adjust buf_len to length after ie including it */
buf_len -= (uint)(((const uint8 *)ie - (const uint8 *)buf));
/* update length from fragments, okay if no next ie */
while ((ie = bcm_next_tlv(ie, &buf_len)) &&
(ie->id == DOT11_MNG_FRAGMENT_ID)) {
/* note: buf_len starts at next ie and last frag may be partial */
if (out_left < ie->len) {
err = BCME_BUFTOOSHORT;
out_left = 0;
} else {
memcpy(out, &ie->data[0], ie->len);
out += ie->len;
out_left -= ie->len;
}
tot_len += ie->len + BCM_TLV_HDR_SIZE;
/* all but last should be of max size */
if (ie->len < BCM_TLV_MAX_DATA_SIZE) {
break;
}
}
done:
if (out_len) {
*out_len = tot_len;
}
return err;
}
int
bcm_tlv_dot11_frag_tot_len(const void *buf, uint buf_len,
uint8 id, bool id_ext, uint *ie_len)
{
return bcm_tlv_dot11_defrag(buf, buf_len, id, id_ext, NULL, ie_len);
}

View File

@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* IE/TLV (de)fragmentation declarations/definitions for
* Broadcom 802.11abgn Networking Device Driver
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id$
*
*/
#ifndef __FRAG_H__
#define __FRAG_H__
int bcm_tlv_dot11_frag_tot_len(const void *buf, uint buf_len,
uint8 id, bool id_ext, uint *ie_len);
#endif /* __FRAG_H__ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,538 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Misc utility routines for accessing lhl specific features
* of the SiliconBackplane-based Broadcom chips.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: hndpmu.c 547757 2015-04-13 10:18:04Z $
*/
#include <hndpmu.h>
#include <hndlhl.h>
#include <sbchipc.h>
#include <hndsoc.h>
#include <bcmdevs.h>
#include <osl.h>
#include <sbgci.h>
#include <siutils.h>
#include <bcmutils.h>
#ifdef BCMULP
#include <ulp.h>
#endif // endif
#define SI_LHL_EXT_WAKE_REQ_MASK_MAGIC 0x7FBBF7FF /* magic number for LHL EXT */
/* PmuRev1 has a 24-bit PMU RsrcReq timer. However it pushes all other bits
* upward. To make the code to run for all revs we use a variable to tell how
* many bits we need to shift.
*/
#define FLAGS_SHIFT 14
#define LHL_ERROR(args) printf args
void
si_lhl_setup(si_t *sih, osl_t *osh)
{
if (CHIPID(sih->chip) == BCM43012_CHIP_ID) {
/* Enable PMU sleep mode0 */
LHL_REG(sih, lhl_top_pwrseq_ctl_adr, LHL_PWRSEQ_CTL, PMU_SLEEP_MODE_2);
/* Modify as per the
BCM43012/LHL#LHL-RecommendedsettingforvariousPMUSleepModes:
*/
LHL_REG(sih, lhl_top_pwrup_ctl_adr, LHL_PWRUP_CTL_MASK, LHL_PWRUP_CTL);
LHL_REG(sih, lhl_top_pwrup2_ctl_adr, LHL_PWRUP2_CTL_MASK, LHL_PWRUP2_CTL);
LHL_REG(sih, lhl_top_pwrdn_ctl_adr, LHL_PWRDN_CTL_MASK, LHL_PWRDN_SLEEP_CNT);
LHL_REG(sih, lhl_top_pwrdn2_ctl_adr, LHL_PWRDN2_CTL_MASK, LHL_PWRDN2_CTL);
} else if (BCM4347_CHIP(sih->chip)) {
if (LHL_IS_PSMODE_1(sih)) {
LHL_REG(sih, lhl_top_pwrseq_ctl_adr, LHL_PWRSEQ_CTL, PMU_SLEEP_MODE_1);
} else {
LHL_REG(sih, lhl_top_pwrseq_ctl_adr, LHL_PWRSEQ_CTL, PMU_SLEEP_MODE_0);
}
LHL_REG(sih, lhl_top_pwrup_ctl_adr, LHL_PWRUP_CTL_MASK, LHL_PWRUP_CTL_4347);
LHL_REG(sih, lhl_top_pwrup2_ctl_adr, LHL_PWRUP2_CTL_MASK, LHL_PWRUP2_CTL);
LHL_REG(sih, lhl_top_pwrdn_ctl_adr,
LHL_PWRDN_CTL_MASK, LHL_PWRDN_SLEEP_CNT);
LHL_REG(sih, lhl_top_pwrdn2_ctl_adr, LHL_PWRDN2_CTL_MASK, LHL_PWRDN2_CTL);
/*
* Enable wakeup on GPIO1, PCIE clkreq and perst signal,
* GPIO[0] is mapped to GPIO1
* GPIO[1] is mapped to PCIE perst
* GPIO[2] is mapped to PCIE clkreq
*/
/* GPIO1 */
/* Clear any old interrupt status */
LHL_REG(sih, gpio_int_st_port_adr[0],
1 << PCIE_GPIO1_GPIO_PIN, 1 << PCIE_GPIO1_GPIO_PIN);
/* active high level trigger */
LHL_REG(sih, gpio_ctrl_iocfg_p_adr[PCIE_GPIO1_GPIO_PIN], ~0,
1 << GCI_GPIO_STS_WL_DIN_SELECT);
LHL_REG(sih, gpio_int_en_port_adr[0],
1 << PCIE_GPIO1_GPIO_PIN, 1 << PCIE_GPIO1_GPIO_PIN);
LHL_REG(sih, gpio_int_st_port_adr[0],
1 << PCIE_GPIO1_GPIO_PIN, 1 << PCIE_GPIO1_GPIO_PIN);
#if !defined(_CFEZ_)
si_gci_set_functionsel(sih, 1, CC4347_FNSEL_SAMEASPIN);
#endif // endif
/* PCIE perst */
LHL_REG(sih, gpio_int_st_port_adr[0],
1 << PCIE_PERST_GPIO_PIN, 1 << PCIE_PERST_GPIO_PIN);
LHL_REG(sih, gpio_ctrl_iocfg_p_adr[PCIE_PERST_GPIO_PIN], ~0,
(1 << GCI_GPIO_STS_EDGE_TRIG_BIT |
1 << GCI_GPIO_STS_WL_DIN_SELECT));
LHL_REG(sih, gpio_int_en_port_adr[0],
1 << PCIE_PERST_GPIO_PIN, 1 << PCIE_PERST_GPIO_PIN);
LHL_REG(sih, gpio_int_st_port_adr[0],
1 << PCIE_PERST_GPIO_PIN, 1 << PCIE_PERST_GPIO_PIN);
/* PCIE clkreq */
LHL_REG(sih, gpio_int_st_port_adr[0],
1 << PCIE_CLKREQ_GPIO_PIN, 1 << PCIE_CLKREQ_GPIO_PIN);
LHL_REG(sih, gpio_ctrl_iocfg_p_adr[PCIE_CLKREQ_GPIO_PIN], ~0,
(1 << GCI_GPIO_STS_EDGE_TRIG_BIT |
1 << GCI_GPIO_STS_NEG_EDGE_TRIG_BIT |
1 << GCI_GPIO_STS_WL_DIN_SELECT));
LHL_REG(sih, gpio_int_en_port_adr[0],
1 << PCIE_CLKREQ_GPIO_PIN, 1 << PCIE_CLKREQ_GPIO_PIN);
LHL_REG(sih, gpio_int_st_port_adr[0],
1 << PCIE_CLKREQ_GPIO_PIN, 1 << PCIE_CLKREQ_GPIO_PIN);
}
}
/* To skip this function, specify a invalid "lpo_select" value in nvram */
int
si_lhl_set_lpoclk(si_t *sih, osl_t *osh, uint32 lpo_force)
{
gciregs_t *gciregs;
uint clk_det_cnt, status;
int lhl_wlclk_sel;
uint32 lpo = 0;
int timeout = 0;
gciregs = si_setcore(sih, GCI_CORE_ID, 0);
ASSERT(gciregs != NULL);
/* Apply nvram override to lpo */
if ((lpo_force == LHL_LPO_AUTO) && ((lpo = (uint32)getintvar(NULL, "lpo_select")) == 0)) {
lpo = LHL_OSC_32k_ENAB;
} else {
lpo = lpo_force;
}
/* Power up the desired LPO */
switch (lpo) {
case LHL_EXT_LPO_ENAB:
LHL_REG(sih, lhl_main_ctl_adr, EXTLPO_BUF_PD, 0);
lhl_wlclk_sel = LHL_EXT_SEL;
break;
case LHL_LPO1_ENAB:
LHL_REG(sih, lhl_main_ctl_adr, LPO1_PD_EN, 0);
lhl_wlclk_sel = LHL_LPO1_SEL;
break;
case LHL_LPO2_ENAB:
LHL_REG(sih, lhl_main_ctl_adr, LPO2_PD_EN, 0);
lhl_wlclk_sel = LHL_LPO2_SEL;
break;
case LHL_OSC_32k_ENAB:
LHL_REG(sih, lhl_main_ctl_adr, OSC_32k_PD, 0);
lhl_wlclk_sel = LHL_32k_SEL;
break;
default:
goto done;
}
LHL_REG(sih, lhl_clk_det_ctl_adr,
LHL_CLK_DET_CTL_AD_CNTR_CLK_SEL, lhl_wlclk_sel);
/* Detect the desired LPO */
LHL_REG(sih, lhl_clk_det_ctl_adr, LHL_CLK_DET_CTL_ADR_LHL_CNTR_EN, 0);
LHL_REG(sih, lhl_clk_det_ctl_adr,
LHL_CLK_DET_CTL_ADR_LHL_CNTR_CLR, LHL_CLK_DET_CTL_ADR_LHL_CNTR_CLR);
timeout = 0;
clk_det_cnt =
((R_REG(osh, &gciregs->lhl_clk_det_ctl_adr) & LHL_CLK_DET_CNT) >>
LHL_CLK_DET_CNT_SHIFT);
while (clk_det_cnt != 0 && timeout <= LPO_SEL_TIMEOUT) {
OSL_DELAY(10);
clk_det_cnt =
((R_REG(osh, &gciregs->lhl_clk_det_ctl_adr) & LHL_CLK_DET_CNT) >>
LHL_CLK_DET_CNT_SHIFT);
timeout++;
}
if (clk_det_cnt != 0) {
LHL_ERROR(("Clock not present as clear did not work timeout = %d\n", timeout));
goto error;
}
LHL_REG(sih, lhl_clk_det_ctl_adr, LHL_CLK_DET_CTL_ADR_LHL_CNTR_CLR, 0);
LHL_REG(sih, lhl_clk_det_ctl_adr, LHL_CLK_DET_CTL_ADR_LHL_CNTR_EN,
LHL_CLK_DET_CTL_ADR_LHL_CNTR_EN);
clk_det_cnt =
((R_REG(osh, &gciregs->lhl_clk_det_ctl_adr) & LHL_CLK_DET_CNT) >>
LHL_CLK_DET_CNT_SHIFT);
timeout = 0;
while (clk_det_cnt <= CLK_DET_CNT_THRESH && timeout <= LPO_SEL_TIMEOUT) {
OSL_DELAY(10);
clk_det_cnt =
((R_REG(osh, &gciregs->lhl_clk_det_ctl_adr) & LHL_CLK_DET_CNT) >>
LHL_CLK_DET_CNT_SHIFT);
timeout++;
}
if (timeout >= LPO_SEL_TIMEOUT) {
LHL_ERROR(("LPO is not available timeout = %u\n, timeout", timeout));
goto error;
}
/* Select the desired LPO */
LHL_REG(sih, lhl_main_ctl_adr,
LHL_MAIN_CTL_ADR_LHL_WLCLK_SEL, (lhl_wlclk_sel) << LPO_SEL_SHIFT);
status = ((R_REG(osh, &gciregs->lhl_clk_status_adr) & LHL_MAIN_CTL_ADR_FINAL_CLK_SEL) ==
(unsigned)(((1 << lhl_wlclk_sel) << LPO_FINAL_SEL_SHIFT))) ? 1 : 0;
timeout = 0;
while (!status && timeout <= LPO_SEL_TIMEOUT) {
OSL_DELAY(10);
status =
((R_REG(osh, &gciregs->lhl_clk_status_adr) & LHL_MAIN_CTL_ADR_FINAL_CLK_SEL) ==
(unsigned)(((1 << lhl_wlclk_sel) << LPO_FINAL_SEL_SHIFT))) ? 1 : 0;
timeout++;
}
if (timeout >= LPO_SEL_TIMEOUT) {
LHL_ERROR(("LPO is not available timeout = %u\n, timeout", timeout));
goto error;
}
/* Power down the rest of the LPOs */
if (lpo != LHL_EXT_LPO_ENAB) {
LHL_REG(sih, lhl_main_ctl_adr, EXTLPO_BUF_PD, EXTLPO_BUF_PD);
}
if (lpo != LHL_LPO1_ENAB) {
LHL_REG(sih, lhl_main_ctl_adr, LPO1_PD_EN, LPO1_PD_EN);
LHL_REG(sih, lhl_main_ctl_adr, LPO1_PD_SEL, LPO1_PD_SEL_VAL);
}
if (lpo != LHL_LPO2_ENAB) {
LHL_REG(sih, lhl_main_ctl_adr, LPO2_PD_EN, LPO2_PD_EN);
LHL_REG(sih, lhl_main_ctl_adr, LPO2_PD_SEL, LPO2_PD_SEL_VAL);
}
if (lpo != LHL_OSC_32k_ENAB) {
LHL_REG(sih, lhl_main_ctl_adr, OSC_32k_PD, OSC_32k_PD);
}
if (lpo != RADIO_LPO_ENAB) {
si_gci_chipcontrol(sih, CC_GCI_CHIPCTRL_06, LPO_SEL, 0);
}
done:
return BCME_OK;
error:
ROMMABLE_ASSERT(0);
return BCME_ERROR;
}
void
si_lhl_timer_config(si_t *sih, osl_t *osh, int timer_type)
{
uint origidx;
pmuregs_t *pmu = NULL;
/* Remember original core before switch to chipc/pmu */
origidx = si_coreidx(sih);
if (AOB_ENAB(sih)) {
pmu = si_setcore(sih, PMU_CORE_ID, 0);
} else {
pmu = si_setcoreidx(sih, SI_CC_IDX);
}
ASSERT(pmu != NULL);
switch (timer_type) {
case LHL_MAC_TIMER:
/* Enable MAC Timer interrupt */
LHL_REG(sih, lhl_wl_mactim0_intrp_adr,
(LHL_WL_MACTIM0_INTRP_EN | LHL_WL_MACTIM0_INTRP_EDGE_TRIGGER),
(LHL_WL_MACTIM0_INTRP_EN | LHL_WL_MACTIM0_INTRP_EDGE_TRIGGER));
/* Programs bits for MACPHY_CLK_AVAIL and all its dependent bits in
* MacResourceReqMask0.
*/
PMU_REG(sih, mac_res_req_mask, ~0, si_pmu_rsrc_macphy_clk_deps(sih, osh, 0));
/* One time init of mac_res_req_timer to enable interrupt and clock request */
HND_PMU_SYNC_WR(sih, pmu, pmu, osh,
PMUREGADDR(sih, pmu, pmu, mac_res_req_timer),
((PRRT_ALP_REQ | PRRT_HQ_REQ | PRRT_INTEN) << FLAGS_SHIFT));
if (si_numd11coreunits(sih) > 1) {
LHL_REG(sih, lhl_wl_mactim1_intrp_adr,
(LHL_WL_MACTIM0_INTRP_EN | LHL_WL_MACTIM0_INTRP_EDGE_TRIGGER),
(LHL_WL_MACTIM0_INTRP_EN | LHL_WL_MACTIM0_INTRP_EDGE_TRIGGER));
PMU_REG(sih, mac_res_req_mask1, ~0,
si_pmu_rsrc_macphy_clk_deps(sih, osh, 1));
HND_PMU_SYNC_WR(sih, pmu, pmu, osh,
PMUREGADDR(sih, pmu, pmu, mac_res_req_timer1),
((PRRT_ALP_REQ | PRRT_HQ_REQ | PRRT_INTEN) << FLAGS_SHIFT));
}
break;
case LHL_ARM_TIMER:
/* Enable ARM Timer interrupt */
LHL_REG(sih, lhl_wl_armtim0_intrp_adr,
(LHL_WL_ARMTIM0_INTRP_EN | LHL_WL_ARMTIM0_INTRP_EDGE_TRIGGER),
(LHL_WL_ARMTIM0_INTRP_EN | LHL_WL_ARMTIM0_INTRP_EDGE_TRIGGER));
/* Programs bits for HT_AVAIL and all its dependent bits in ResourceReqMask0 */
PMU_REG(sih, res_req_mask, ~0, si_pmu_rsrc_ht_avail_clk_deps(sih, osh));
/* One time init of res_req_timer to enable interrupt and clock request
* For low power request only ALP (HT_AVAIL is anyway requested by res_req_mask)
*/
HND_PMU_SYNC_WR(sih, pmu, pmu, osh,
PMUREGADDR(sih, pmu, pmu, res_req_timer),
((PRRT_ALP_REQ | PRRT_HQ_REQ | PRRT_INTEN) << FLAGS_SHIFT));
break;
}
/* Return to original core */
si_setcoreidx(sih, origidx);
}
void
si_lhl_timer_enable(si_t *sih)
{
/* Enable clks for pmu int propagation */
PMU_REG(sih, pmuintctrl0, PMU_INTC_ALP_REQ, PMU_INTC_ALP_REQ);
PMU_REG(sih, pmuintmask0, RSRC_INTR_MASK_TIMER_INT_0, RSRC_INTR_MASK_TIMER_INT_0);
LHL_REG(sih, lhl_main_ctl_adr, LHL_FAST_WRITE_EN, LHL_FAST_WRITE_EN);
PMU_REG(sih, pmucontrol_ext, PCTL_EXT_USE_LHL_TIMER, PCTL_EXT_USE_LHL_TIMER);
}
void
si_lhl_ilp_config(si_t *sih, osl_t *osh, uint32 ilp_period)
{
gciregs_t *gciregs;
if (CHIPID(sih->chip) == BCM43012_CHIP_ID) {
gciregs = si_setcore(sih, GCI_CORE_ID, 0);
ASSERT(gciregs != NULL);
W_REG(osh, &gciregs->lhl_wl_ilp_val_adr, ilp_period);
}
}
#ifdef BCMULP
void
si_lhl_disable_sdio_wakeup(si_t *sih)
{
/* Disable the interrupt */
LHL_REG(sih, gpio_int_en_port_adr[0], (1 << ULP_SDIO_CMD_PIN), 0);
/* Clear the pending interrupt status */
LHL_REG(sih, gpio_int_st_port_adr[0], (1 << ULP_SDIO_CMD_PIN), (1 << ULP_SDIO_CMD_PIN));
}
void
si_lhl_enable_sdio_wakeup(si_t *sih, osl_t *osh)
{
gciregs_t *gciregs;
pmuregs_t *pmu;
gciregs = si_setcore(sih, GCI_CORE_ID, 0);
ASSERT(gciregs != NULL);
if (CHIPID(sih->chip) == BCM43012_CHIP_ID) {
/* For SDIO_CMD configure P8 for wake on negedge
* LHL 0 -> edge trigger intr mode,
* 1 -> neg edge trigger intr mode ,
* 6 -> din from wl side enable
*/
OR_REG(osh, &gciregs->gpio_ctrl_iocfg_p_adr[ULP_SDIO_CMD_PIN],
(1 << GCI_GPIO_STS_EDGE_TRIG_BIT |
1 << GCI_GPIO_STS_NEG_EDGE_TRIG_BIT |
1 << GCI_GPIO_STS_WL_DIN_SELECT));
/* Clear any old interrupt status */
OR_REG(osh, &gciregs->gpio_int_st_port_adr[0], 1 << ULP_SDIO_CMD_PIN);
/* LHL GPIO[8] intr en , GPIO[8] is mapped to SDIO_CMD */
/* Enable P8 to generate interrupt */
OR_REG(osh, &gciregs->gpio_int_en_port_adr[0], 1 << ULP_SDIO_CMD_PIN);
/* Clear LHL GPIO status to trigger GCI Interrupt */
OR_REG(osh, &gciregs->gci_intstat, GCI_INTSTATUS_LHLWLWAKE);
/* Enable LHL GPIO Interrupt to trigger GCI Interrupt */
OR_REG(osh, &gciregs->gci_intmask, GCI_INTMASK_LHLWLWAKE);
OR_REG(osh, &gciregs->gci_wakemask, GCI_WAKEMASK_LHLWLWAKE);
/* Note ->Enable GCI interrupt to trigger Chipcommon interrupt
* Set EciGciIntEn in IntMask and will be done from FCBS saved tuple
*/
/* Enable LHL to trigger extWake upto HT_AVAIL */
/* LHL GPIO Interrupt is mapped to extWake[7] */
pmu = si_setcore(sih, PMU_CORE_ID, 0);
ASSERT(pmu != NULL);
/* Set bit 4 and 7 in ExtWakeMask */
W_REG(osh, &pmu->extwakemask[0], CI_ECI | CI_WECI);
/* Program bits for MACPHY_CLK_AVAIL rsrc in ExtWakeReqMaskN */
W_REG(osh, &pmu->extwakereqmask[0], SI_LHL_EXT_WAKE_REQ_MASK_MAGIC);
/* Program 0 (no need to request explicitly for any backplane clk) */
W_REG(osh, &pmu->extwakectrl, 0x0);
/* Note: Configure MAC/Ucode to receive interrupt
* it will be done from saved tuple using FCBS code
*/
}
}
#endif /* BCMULP */
lhl_reg_set_t lv_sleep_mode_4369_lhl_reg_set[] =
{
/* set wl_sleep_en */
{LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), (1 << 0), (1 << 0)},
/* set top_pwrsw_en, top_slb_en, top_iso_en */
{LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), BCM_MASK32(5, 3), (0x0 << 3)},
/* set VMUX_asr_sel_en */
{LHL_REG_OFF(lhl_top_pwrseq_ctl_adr), (1 << 8), (1 << 8)},
/* lhl_lp_main_ctl_adr, disable lp_mode_en, set CSR and ASR field enables for LV mode */
{LHL_REG_OFF(lhl_lp_main_ctl_adr), BCM_MASK32(21, 0), 0x3F89FF},
/* lhl_lp_main_ctl1_adr, set CSR field values - CSR_adj - 0.64V and trim_adj -5mV */
{LHL_REG_OFF(lhl_lp_main_ctl1_adr), BCM_MASK32(23, 0), 0x9E8F97},
/* lhl_lp_main_ctl2_adr, set ASR field values - ASR_adj - 0.76V and trim_adj +5mV */
{LHL_REG_OFF(lhl_lp_main_ctl2_adr), BCM_MASK32(13, 0), 0x07EE},
/* lhl_lp_dn_ctl_adr, set down count for CSR fields- adj, mode, overi_dis */
{LHL_REG_OFF(lhl_lp_dn_ctl_adr), ~0, ((LHL4369_CSR_OVERI_DIS_DWN_CNT << 16) |
(LHL4369_CSR_MODE_DWN_CNT << 8) | (LHL4369_CSR_ADJ_DWN_CNT << 0))},
/* lhl_lp_up_ctl_adr, set up count for CSR fields- adj, mode, overi_dis */
{LHL_REG_OFF(lhl_lp_up_ctl_adr), ~0, ((LHL4369_CSR_OVERI_DIS_UP_CNT << 16) |
(LHL4369_CSR_MODE_UP_CNT << 8) | (LHL4369_CSR_ADJ_UP_CNT << 0))},
/* lhl_lp_dn_ctl1_adr, set down count for hpbg_chop_dis, ASR_adj, vddc_sw_dis */
{LHL_REG_OFF(lhl_lp_dn_ctl1_adr), ~0, ((LHL4369_VDDC_SW_DIS_DWN_CNT << 24) |
(LHL4369_ASR_ADJ_DWN_CNT << 16) | (LHL4369_HPBG_CHOP_DIS_DWN_CNT << 0))},
/* lhl_lp_up_ctl1_adr, set up count for hpbg_chop_dis, ASR_adj, vddc_sw_dis */
{LHL_REG_OFF(lhl_lp_up_ctl1_adr), ~0, ((LHL4369_VDDC_SW_DIS_UP_CNT << 24) |
(LHL4369_ASR_ADJ_UP_CNT << 16) | (LHL4369_HPBG_CHOP_DIS_UP_CNT << 0))},
/* lhl_lp_dn_ctl4_adr, set down count for ASR fields -
* clk4m_dis, lppfm_mode, mode_sel, manual_mode
*/
{LHL_REG_OFF(lhl_lp_dn_ctl4_adr), ~0, ((LHL4369_ASR_MANUAL_MODE_DWN_CNT << 24) |
(LHL4369_ASR_MODE_SEL_DWN_CNT << 16) | (LHL4369_ASR_LPPFM_MODE_DWN_CNT << 8) |
(LHL4369_ASR_CLK4M_DIS_DWN_CNT << 0))},
/* lhl_lp_up_ctl4_adr, set up count for ASR fields -
* clk4m_dis, lppfm_mode, mode_sel, manual_mode
*/
{LHL_REG_OFF(lhl_lp_up_ctl4_adr), ~0, ((LHL4369_ASR_MANUAL_MODE_UP_CNT << 24) |
(LHL4369_ASR_MODE_SEL_UP_CNT << 16)| (LHL4369_ASR_LPPFM_MODE_UP_CNT << 8) |
(LHL4369_ASR_CLK4M_DIS_UP_CNT << 0))},
/* lhl_lp_dn_ctl3_adr, set down count for hpbg_pu, srbg_ref, ASR_overi_dis,
* CSR_pfm_pwr_slice_en
*/
{LHL_REG_OFF(lhl_lp_dn_ctl3_adr), ~0, ((LHL4369_PFM_PWR_SLICE_DWN_CNT << 24) |
(LHL4369_ASR_OVERI_DIS_DWN_CNT << 16) | (LHL4369_SRBG_REF_SEL_DWN_CNT << 8) |
(LHL4369_HPBG_PU_EN_DWN_CNT << 0))},
/* lhl_lp_up_ctl3_adr, set up count for hpbg_pu, srbg_ref, ASR_overi_dis,
* CSR_pfm_pwr_slice_en
*/
{LHL_REG_OFF(lhl_lp_up_ctl3_adr), ~0, ((LHL4369_PFM_PWR_SLICE_UP_CNT << 24) |
(LHL4369_ASR_OVERI_DIS_UP_CNT << 16) | (LHL4369_SRBG_REF_SEL_UP_CNT << 8) |
(LHL4369_HPBG_PU_EN_UP_CNT << 0))},
/* lhl_lp_dn_ctl2_adr, set down count for CSR_trim_adj */
{LHL_REG_OFF(lhl_lp_dn_ctl2_adr), ~0, (LHL4369_CSR_TRIM_ADJ_DWN_CNT << 16)},
/* lhl_lp_up_ctl2_adr, set up count for CSR_trim_adj */
{LHL_REG_OFF(lhl_lp_up_ctl2_adr), ~0, (LHL4369_CSR_TRIM_ADJ_UP_CNT << 16)},
/* lhl_lp_dn_ctl5_adr, set down count for ASR_trim_adj */
{LHL_REG_OFF(lhl_lp_dn_ctl5_adr), ~0, (LHL4369_ASR_TRIM_ADJ_DWN_CNT << 0)},
/* lhl_lp_up_ctl5_adr, set down count for ASR_trim_adj */
{LHL_REG_OFF(lhl_lp_up_ctl5_adr), ~0, (LHL4369_ASR_TRIM_ADJ_UP_CNT << 0)},
/* Change the default down count values for the resources */
/* lhl_top_pwrdn_ctl_adr, set down count for top_level_sleep, iso, slb and pwrsw */
{LHL_REG_OFF(lhl_top_pwrdn_ctl_adr), ~0, ((LHL4369_PWRSW_EN_DWN_CNT << 24) |
(LHL4369_SLB_EN_DWN_CNT << 16) | (LHL4369_ISO_EN_DWN_CNT << 8))},
/* lhl_top_pwrdn2_ctl_adr, set down count for VMUX_asr_sel */
{LHL_REG_OFF(lhl_top_pwrdn2_ctl_adr), ~0, (LHL4369_VMUX_ASR_SEL_DWN_CNT << 16)},
/* Change the default up count values for the resources */
/* lhl_top_pwrup_ctl_adr, set up count for top_level_sleep, iso, slb and pwrsw */
{LHL_REG_OFF(lhl_top_pwrup_ctl_adr), ~0, ((LHL4369_PWRSW_EN_UP_CNT << 24) |
(LHL4369_SLB_EN_UP_CNT << 16) | (LHL4369_ISO_EN_UP_CNT << 8))},
/* lhl_top_pwrdn2_ctl_adr, set down count for VMUX_asr_sel */
{LHL_REG_OFF(lhl_top_pwrup2_ctl_adr), ~0, ((LHL4369_VMUX_ASR_SEL_UP_CNT << 16))},
/* Enable lhl interrupt */
{LHL_REG_OFF(gci_intmask), (1 << 30), (1 << 30)},
/* Enable LHL Wake up */
{LHL_REG_OFF(gci_wakemask), (1 << 30), (1 << 30)},
/* Making forceOTPpwrOn 0 */
{LHL_REG_OFF(otpcontrol), (1 << 16), 0}
};
/* LV sleep mode summary:
* LV mode is where both ABUCK and CBUCK are programmed to low voltages during
* sleep, and VMUX selects ABUCK as VDDOUT_AON. LPLDO needs to power off.
* With ASR ON, LPLDO OFF
*/
void
si_set_lv_sleep_mode_lhl_config_4369(si_t *sih)
{
uint i;
uint coreidx = si_findcoreidx(sih, GCI_CORE_ID, 0);
lhl_reg_set_t *regs = lv_sleep_mode_4369_lhl_reg_set;
/* Enable LHL LV mode:
* lhl_top_pwrseq_ctl_adr, set wl_sleep_en, iso_en, slb_en, pwrsw_en,VMUX_asr_sel_en
*/
for (i = 0; i < ARRAYSIZE(lv_sleep_mode_4369_lhl_reg_set); i++) {
si_corereg(sih, coreidx, regs[i].offset, regs[i].mask, regs[i].val);
}
}

View File

@@ -0,0 +1,430 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Utility routines for configuring different memories in Broadcom chips.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: $
*/
#include <typedefs.h>
#include <sbchipc.h>
#include <hndsoc.h>
#include <bcmdevs.h>
#include <osl.h>
#include <sbgci.h>
#include <siutils.h>
#include <bcmutils.h>
#include <hndmem.h>
#define IS_MEMTYPE_VALID(mem) ((mem >= MEM_SOCRAM) && (mem < MEM_MAX))
#define IS_MEMCONFIG_VALID(cfg) ((cfg >= PDA_CONFIG_CLEAR) && (cfg < PDA_CONFIG_MAX))
/* Returns the number of banks in a given memory */
int
hndmem_num_banks(si_t *sih, int mem)
{
uint32 savecore, mem_info;
int num_banks = 0;
gciregs_t *gciregs;
osl_t *osh = si_osh(sih);
if (!IS_MEMTYPE_VALID(mem)) {
goto exit;
}
savecore = si_coreidx(sih);
/* TODO: Check whether SOCRAM core is present or not. If not, bail out */
/* In future we need to add code for TCM based chips as well */
if (!si_setcore(sih, SOCRAM_CORE_ID, 0)) {
goto exit;
}
if (sih->gcirev >= 9) {
gciregs = si_setcore(sih, GCI_CORE_ID, 0);
mem_info = R_REG(osh, &gciregs->wlan_mem_info);
switch (mem) {
case MEM_SOCRAM:
num_banks = (mem_info & WLAN_MEM_INFO_REG_NUMSOCRAMBANKS_MASK) >>
WLAN_MEM_INFO_REG_NUMSOCRAMBANKS_SHIFT;
break;
case MEM_BM:
num_banks = (mem_info & WLAN_MEM_INFO_REG_NUMD11MACBM_MASK) >>
WLAN_MEM_INFO_REG_NUMD11MACBM_SHIFT;
break;
case MEM_UCM:
num_banks = (mem_info & WLAN_MEM_INFO_REG_NUMD11MACUCM_MASK) >>
WLAN_MEM_INFO_REG_NUMD11MACUCM_SHIFT;
break;
case MEM_SHM:
num_banks = (mem_info & WLAN_MEM_INFO_REG_NUMD11MACSHM_MASK) >>
WLAN_MEM_INFO_REG_NUMD11MACSHM_SHIFT;
break;
default:
ASSERT(0);
break;
}
} else {
/* TODO: Figure out bank information using SOCRAM registers */
}
si_setcoreidx(sih, savecore);
exit:
return num_banks;
}
/* Returns the size of a give bank in a given memory */
int
hndmem_bank_size(si_t *sih, hndmem_type_t mem, int bank_num)
{
uint32 savecore, bank_info, reg_data;
int bank_sz = 0;
gciregs_t *gciregs;
osl_t *osh = si_osh(sih);
if (!IS_MEMTYPE_VALID(mem)) {
goto exit;
}
savecore = si_coreidx(sih);
/* TODO: Check whether SOCRAM core is present or not. If not, bail out */
/* In future we need to add code for TCM based chips as well */
if (!si_setcore(sih, SOCRAM_CORE_ID, 0)) {
goto exit;
}
if (sih->gcirev >= 9) {
gciregs = si_setcore(sih, GCI_CORE_ID, 0);
reg_data = ((mem &
GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_MASK) <<
GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_SHIFT) |
((bank_num & GCI_INDIRECT_ADDRESS_REG_REGINDEX_MASK)
<< GCI_INDIRECT_ADDRESS_REG_REGINDEX_SHIFT);
W_REG(osh, &gciregs->gci_indirect_addr, reg_data);
bank_info = R_REG(osh, &gciregs->wlan_bankxinfo);
bank_sz = (bank_info & WLAN_BANKXINFO_BANK_SIZE_MASK) >>
WLAN_BANKXINFO_BANK_SIZE_SHIFT;
} else {
/* TODO: Figure out bank size using SOCRAM registers */
}
si_setcoreidx(sih, savecore);
exit:
return bank_sz;
}
/* Returns the start address of given memory */
uint32
hndmem_mem_base(si_t *sih, hndmem_type_t mem)
{
uint32 savecore, base_addr = 0;
/* Currently only support of SOCRAM is available in hardware */
if (mem != MEM_SOCRAM) {
goto exit;
}
savecore = si_coreidx(sih);
if (si_setcore(sih, SOCRAM_CORE_ID, 0))
{
base_addr = si_get_slaveport_addr(sih, CORE_SLAVE_PORT_1,
CORE_BASE_ADDR_0, SOCRAM_CORE_ID, 0);
} else {
/* TODO: Add code to get the base address of TCM */
base_addr = 0;
}
si_setcoreidx(sih, savecore);
exit:
return base_addr;
}
#ifdef BCMDEBUG
char *hndmem_type_str[] =
{
"SOCRAM", /* 0 */
"BM", /* 1 */
"UCM", /* 2 */
"SHM", /* 3 */
};
/* Dumps the complete memory information */
void
hndmem_dump_meminfo_all(si_t *sih)
{
int mem, bank, bank_cnt, bank_sz;
for (mem = MEM_SOCRAM; mem < MEM_MAX; mem++) {
bank_cnt = hndmem_num_banks(sih, mem);
printf("\nMemtype: %s\n", hndmem_type_str[mem]);
for (bank = 0; bank < bank_cnt; bank++) {
bank_sz = hndmem_bank_size(sih, mem, bank);
printf("Bank-%d: %d KB\n", bank, bank_sz);
}
}
}
#endif /* BCMDEBUG */
/* Configures the Sleep PDA for a particular bank for a given memory type */
int
hndmem_sleeppda_bank_config(si_t *sih, hndmem_type_t mem, int bank_num,
hndmem_config_t config, uint32 pda)
{
uint32 savecore, reg_data;
gciregs_t *gciregs;
int err = BCME_OK;
osl_t *osh = si_osh(sih);
/* TODO: Check whether SOCRAM core is present or not. If not, bail out */
/* In future we need to add code for TCM based chips as well */
if (!si_setcore(sih, SOCRAM_CORE_ID, 0)) {
err = BCME_UNSUPPORTED;
goto exit;
}
/* Sleep PDA is supported only by GCI rev >= 9 */
if (sih->gcirev < 9) {
err = BCME_UNSUPPORTED;
goto exit;
}
if (!IS_MEMTYPE_VALID(mem)) {
err = BCME_BADOPTION;
goto exit;
}
if (!IS_MEMCONFIG_VALID(config)) {
err = BCME_BADOPTION;
goto exit;
}
savecore = si_coreidx(sih);
gciregs = si_setcore(sih, GCI_CORE_ID, 0);
reg_data = ((mem &
GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_MASK) <<
GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_SHIFT) |
((bank_num & GCI_INDIRECT_ADDRESS_REG_REGINDEX_MASK)
<< GCI_INDIRECT_ADDRESS_REG_REGINDEX_SHIFT);
W_REG(osh, &gciregs->gci_indirect_addr, reg_data);
if (config == PDA_CONFIG_SET_PARTIAL) {
W_REG(osh, &gciregs->wlan_bankxsleeppda, pda);
W_REG(osh, &gciregs->wlan_bankxkill, 0);
}
else if (config == PDA_CONFIG_SET_FULL) {
W_REG(osh, &gciregs->wlan_bankxsleeppda, WLAN_BANKX_SLEEPPDA_REG_SLEEPPDA_MASK);
W_REG(osh, &gciregs->wlan_bankxkill, WLAN_BANKX_PKILL_REG_SLEEPPDA_MASK);
} else {
W_REG(osh, &gciregs->wlan_bankxsleeppda, 0);
W_REG(osh, &gciregs->wlan_bankxkill, 0);
}
si_setcoreidx(sih, savecore);
exit:
return err;
}
/* Configures the Active PDA for a particular bank for a given memory type */
int
hndmem_activepda_bank_config(si_t *sih, hndmem_type_t mem,
int bank_num, hndmem_config_t config, uint32 pda)
{
uint32 savecore, reg_data;
gciregs_t *gciregs;
int err = BCME_OK;
osl_t *osh = si_osh(sih);
if (!IS_MEMTYPE_VALID(mem)) {
err = BCME_BADOPTION;
goto exit;
}
if (!IS_MEMCONFIG_VALID(config)) {
err = BCME_BADOPTION;
goto exit;
}
savecore = si_coreidx(sih);
/* TODO: Check whether SOCRAM core is present or not. If not, bail out */
/* In future we need to add code for TCM based chips as well */
if (!si_setcore(sih, SOCRAM_CORE_ID, 0)) {
err = BCME_UNSUPPORTED;
goto exit;
}
if (sih->gcirev >= 9) {
gciregs = si_setcore(sih, GCI_CORE_ID, 0);
reg_data = ((mem &
GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_MASK) <<
GCI_INDIRECT_ADDRESS_REG_GPIOINDEX_SHIFT) |
((bank_num & GCI_INDIRECT_ADDRESS_REG_REGINDEX_MASK)
<< GCI_INDIRECT_ADDRESS_REG_REGINDEX_SHIFT);
W_REG(osh, &gciregs->gci_indirect_addr, reg_data);
if (config == PDA_CONFIG_SET_PARTIAL) {
W_REG(osh, &gciregs->wlan_bankxactivepda, pda);
}
else if (config == PDA_CONFIG_SET_FULL) {
W_REG(osh, &gciregs->wlan_bankxactivepda,
WLAN_BANKX_SLEEPPDA_REG_SLEEPPDA_MASK);
} else {
W_REG(osh, &gciregs->wlan_bankxactivepda, 0);
}
} else {
/* TODO: Configure SOCRAM PDA using SOCRAM registers */
err = BCME_UNSUPPORTED;
}
si_setcoreidx(sih, savecore);
exit:
return err;
}
/* Configures the Sleep PDA for all the banks for a given memory type */
int
hndmem_sleeppda_config(si_t *sih, hndmem_type_t mem, hndmem_config_t config)
{
int bank;
int num_banks = hndmem_num_banks(sih, mem);
int err = BCME_OK;
/* Sleep PDA is supported only by GCI rev >= 9 */
if (sih->gcirev < 9) {
err = BCME_UNSUPPORTED;
goto exit;
}
if (!IS_MEMTYPE_VALID(mem)) {
err = BCME_BADOPTION;
goto exit;
}
if (!IS_MEMCONFIG_VALID(config)) {
err = BCME_BADOPTION;
goto exit;
}
for (bank = 0; bank < num_banks; bank++)
{
err = hndmem_sleeppda_bank_config(sih, mem, bank, config, 0);
}
exit:
return err;
}
/* Configures the Active PDA for all the banks for a given memory type */
int
hndmem_activepda_config(si_t *sih, hndmem_type_t mem, hndmem_config_t config)
{
int bank;
int num_banks = hndmem_num_banks(sih, mem);
int err = BCME_OK;
if (!IS_MEMTYPE_VALID(mem)) {
err = BCME_BADOPTION;
goto exit;
}
if (!IS_MEMCONFIG_VALID(config)) {
err = BCME_BADOPTION;
goto exit;
}
for (bank = 0; bank < num_banks; bank++)
{
err = hndmem_activepda_bank_config(sih, mem, bank, config, 0);
}
exit:
return err;
}
/* Turn off/on all the possible banks in a given memory range.
* Currently this works only for SOCRAM as this is restricted by HW.
*/
int
hndmem_activepda_mem_config(si_t *sih, hndmem_type_t mem, uint32 mem_start,
uint32 size, hndmem_config_t config)
{
int bank, bank_sz, num_banks;
int mem_end;
int bank_start_addr, bank_end_addr;
int err = BCME_OK;
/* We can get bank size for only SOCRAM/TCM only. Support is not avilable
* for other memories (BM, UCM and SHM)
*/
if (mem != MEM_SOCRAM) {
err = BCME_UNSUPPORTED;
goto exit;
}
num_banks = hndmem_num_banks(sih, mem);
bank_start_addr = hndmem_mem_base(sih, mem);
mem_end = mem_start + size - 1;
for (bank = 0; bank < num_banks; bank++)
{
/* Bank size is spcified in bankXinfo register in terms on KBs */
bank_sz = 1024 * hndmem_bank_size(sih, mem, bank);
bank_end_addr = bank_start_addr + bank_sz - 1;
if (config == PDA_CONFIG_SET_FULL) {
/* Check if the bank is completely overlapping with the given mem range */
if ((mem_start <= bank_start_addr) && (mem_end >= bank_end_addr)) {
err = hndmem_activepda_bank_config(sih, mem, bank, config, 0);
}
} else {
/* Check if the bank is completely overlaped with the given mem range */
if (((mem_start <= bank_start_addr) && (mem_end >= bank_end_addr)) ||
/* Check if the bank is partially overlaped with the given range */
((mem_start <= bank_end_addr) && (mem_end >= bank_start_addr))) {
err = hndmem_activepda_bank_config(sih, mem, bank, config, 0);
}
}
bank_start_addr += bank_sz;
}
exit:
return err;
}

View File

@@ -0,0 +1,789 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Misc utility routines for accessing PMU corerev specific features
* of the SiliconBackplane-based Broadcom chips.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: hndpmu.c 783841 2018-10-09 06:24:16Z $
*/
/**
* @file
* Note: this file contains PLL/FLL related functions. A chip can contain multiple PLLs/FLLs.
* However, in the context of this file the baseband ('BB') PLL/FLL is referred to.
*
* Throughout this code, the prefixes 'pmu1_' and 'pmu2_' are used.
* They refer to different revisions of the PMU (which is at revision 18 @ Apr 25, 2012)
* pmu1_ marks the transition from PLL to ADFLL (Digital Frequency Locked Loop). It supports
* fractional frequency generation. pmu2_ does not support fractional frequency generation.
*/
#include <bcm_cfg.h>
#include <typedefs.h>
#include <bcmdefs.h>
#include <osl.h>
#include <bcmutils.h>
#include <siutils.h>
#include <bcmdevs.h>
#include <hndsoc.h>
#include <sbchipc.h>
#include <hndchipc.h>
#include <hndpmu.h>
#include <hndlhl.h>
#if defined(BCMULP)
#include <ulp.h>
#endif /* defined(BCMULP) */
#include <sbgci.h>
#ifdef EVENT_LOG_COMPILE
#include <event_log.h>
#endif // endif
#include <sbgci.h>
#include <lpflags.h>
#define PMU_ERROR(args)
#define PMU_MSG(args)
/* To check in verbose debugging messages not intended
* to be on except on private builds.
*/
#define PMU_NONE(args)
#define flags_shift 14
/** contains resource bit positions for a specific chip */
struct rsc_per_chip_s {
uint8 ht_avail;
uint8 macphy_clkavail;
uint8 ht_start;
uint8 otp_pu;
uint8 macphy_aux_clkavail;
};
typedef struct rsc_per_chip_s rsc_per_chip_t;
#if defined(BCMPMU_STATS) && !defined(BCMPMU_STATS_DISABLED)
bool _pmustatsenab = TRUE;
#else
bool _pmustatsenab = FALSE;
#endif /* BCMPMU_STATS */
/**
* Balance between stable SDIO operation and power consumption is achieved using this function.
* Note that each drive strength table is for a specific VDDIO of the SDIO pads, ideally this
* function should read the VDDIO itself to select the correct table. For now it has been solved
* with the 'BCM_SDIO_VDDIO' preprocessor constant.
*
* 'drivestrength': desired pad drive strength in mA. Drive strength of 0 requests tri-state (if
* hardware supports this), if no hw support drive strength is not programmed.
*/
void
si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength)
{
/*
* Note:
* This function used to set the SDIO drive strength via PMU_CHIPCTL1 for the
* 43143, 4330, 4334, 4336, 43362 chips. These chips are now no longer supported, so
* the code has been deleted.
* Newer chips have the SDIO drive strength setting via a GCI Chip Control register,
* but the bit definitions are chip-specific. We are keeping this function available
* (accessed via DHD 'sdiod_drive' IOVar) in case these newer chips need to provide access.
*/
UNUSED_PARAMETER(sih);
UNUSED_PARAMETER(osh);
UNUSED_PARAMETER(drivestrength);
}
void
si_switch_pmu_dependency(si_t *sih, uint mode)
{
#ifdef DUAL_PMU_SEQUENCE
osl_t *osh = si_osh(sih);
uint32 current_res_state;
uint32 min_mask, max_mask;
const pmu_res_depend_t *pmu_res_depend_table = NULL;
uint pmu_res_depend_table_sz = 0;
uint origidx;
pmuregs_t *pmu;
chipcregs_t *cc;
BCM_REFERENCE(cc);
origidx = si_coreidx(sih);
if (AOB_ENAB(sih)) {
pmu = si_setcore(sih, PMU_CORE_ID, 0);
cc = si_setcore(sih, CC_CORE_ID, 0);
} else {
pmu = si_setcoreidx(sih, SI_CC_IDX);
cc = si_setcoreidx(sih, SI_CC_IDX);
}
ASSERT(pmu != NULL);
current_res_state = R_REG(osh, &pmu->res_state);
min_mask = R_REG(osh, &pmu->min_res_mask);
max_mask = R_REG(osh, &pmu->max_res_mask);
W_REG(osh, &pmu->min_res_mask, (min_mask | current_res_state));
switch (mode) {
case PMU_4364_1x1_MODE:
{
if (CHIPID(sih->chip) == BCM4364_CHIP_ID) {
pmu_res_depend_table = bcm4364a0_res_depend_1x1;
pmu_res_depend_table_sz =
ARRAYSIZE(bcm4364a0_res_depend_1x1);
max_mask = PMU_4364_MAX_MASK_1x1;
W_REG(osh, &pmu->res_table_sel, RES4364_SR_SAVE_RESTORE);
W_REG(osh, &pmu->res_updn_timer, PMU_4364_SAVE_RESTORE_UPDNTIME_1x1);
#if defined(SAVERESTORE)
if (SR_ENAB()) {
/* Disable 3x3 SR engine */
W_REG(osh, &cc->sr1_control0,
CC_SR0_4364_SR_ENG_CLK_EN |
CC_SR0_4364_SR_RSRC_TRIGGER |
CC_SR0_4364_SR_WD_MEM_MIN_DIV |
CC_SR0_4364_SR_INVERT_CLK |
CC_SR0_4364_SR_ENABLE_HT |
CC_SR0_4364_SR_ALLOW_PIC |
CC_SR0_4364_SR_PMU_MEM_DISABLE);
}
#endif /* SAVERESTORE */
}
break;
}
case PMU_4364_3x3_MODE:
{
if (CHIPID(sih->chip) == BCM4364_CHIP_ID) {
W_REG(osh, &pmu->res_table_sel, RES4364_SR_SAVE_RESTORE);
W_REG(osh, &pmu->res_updn_timer,
PMU_4364_SAVE_RESTORE_UPDNTIME_3x3);
/* Change the dependency table only if required */
if ((max_mask != PMU_4364_MAX_MASK_3x3) ||
(max_mask != PMU_4364_MAX_MASK_RSDB)) {
pmu_res_depend_table = bcm4364a0_res_depend_rsdb;
pmu_res_depend_table_sz =
ARRAYSIZE(bcm4364a0_res_depend_rsdb);
max_mask = PMU_4364_MAX_MASK_3x3;
}
#if defined(SAVERESTORE)
if (SR_ENAB()) {
/* Enable 3x3 SR engine */
W_REG(osh, &cc->sr1_control0,
CC_SR0_4364_SR_ENG_CLK_EN |
CC_SR0_4364_SR_RSRC_TRIGGER |
CC_SR0_4364_SR_WD_MEM_MIN_DIV |
CC_SR0_4364_SR_INVERT_CLK |
CC_SR0_4364_SR_ENABLE_HT |
CC_SR0_4364_SR_ALLOW_PIC |
CC_SR0_4364_SR_PMU_MEM_DISABLE |
CC_SR0_4364_SR_ENG_EN_MASK);
}
#endif /* SAVERESTORE */
}
break;
}
case PMU_4364_RSDB_MODE:
default:
{
if (CHIPID(sih->chip) == BCM4364_CHIP_ID) {
W_REG(osh, &pmu->res_table_sel, RES4364_SR_SAVE_RESTORE);
W_REG(osh, &pmu->res_updn_timer,
PMU_4364_SAVE_RESTORE_UPDNTIME_3x3);
/* Change the dependency table only if required */
if ((max_mask != PMU_4364_MAX_MASK_3x3) ||
(max_mask != PMU_4364_MAX_MASK_RSDB)) {
pmu_res_depend_table =
bcm4364a0_res_depend_rsdb;
pmu_res_depend_table_sz =
ARRAYSIZE(bcm4364a0_res_depend_rsdb);
max_mask = PMU_4364_MAX_MASK_RSDB;
}
#if defined(SAVERESTORE)
if (SR_ENAB()) {
/* Enable 3x3 SR engine */
W_REG(osh, &cc->sr1_control0,
CC_SR0_4364_SR_ENG_CLK_EN |
CC_SR0_4364_SR_RSRC_TRIGGER |
CC_SR0_4364_SR_WD_MEM_MIN_DIV |
CC_SR0_4364_SR_INVERT_CLK |
CC_SR0_4364_SR_ENABLE_HT |
CC_SR0_4364_SR_ALLOW_PIC |
CC_SR0_4364_SR_PMU_MEM_DISABLE |
CC_SR0_4364_SR_ENG_EN_MASK);
}
#endif /* SAVERESTORE */
}
break;
}
}
si_pmu_resdeptbl_upd(sih, osh, pmu, pmu_res_depend_table, pmu_res_depend_table_sz);
W_REG(osh, &pmu->max_res_mask, max_mask);
W_REG(osh, &pmu->min_res_mask, min_mask);
si_pmu_wait_for_steady_state(sih, osh, pmu);
/* Add some delay; allow resources to come up and settle. */
OSL_DELAY(200);
si_setcoreidx(sih, origidx);
#endif /* DUAL_PMU_SEQUENCE */
}
#if defined(BCMULP)
int
si_pmu_ulp_register(si_t *sih)
{
return ulp_p1_module_register(ULP_MODULE_ID_PMU, &ulp_pmu_ctx, (void *)sih);
}
static uint
si_pmu_ulp_get_retention_size_cb(void *handle, ulp_ext_info_t *einfo)
{
ULP_DBG(("%s: sz: %d\n", __FUNCTION__, sizeof(si_pmu_ulp_cr_dat_t)));
return sizeof(si_pmu_ulp_cr_dat_t);
}
static int
si_pmu_ulp_enter_cb(void *handle, ulp_ext_info_t *einfo, uint8 *cache_data)
{
si_pmu_ulp_cr_dat_t crinfo = {0};
crinfo.ilpcycles_per_sec = ilpcycles_per_sec;
ULP_DBG(("%s: ilpcycles_per_sec: %x\n", __FUNCTION__, ilpcycles_per_sec));
memcpy(cache_data, (void*)&crinfo, sizeof(crinfo));
return BCME_OK;
}
static int
si_pmu_ulp_exit_cb(void *handle, uint8 *cache_data,
uint8 *p2_cache_data)
{
si_pmu_ulp_cr_dat_t *crinfo = (si_pmu_ulp_cr_dat_t *)cache_data;
ilpcycles_per_sec = crinfo->ilpcycles_per_sec;
ULP_DBG(("%s: ilpcycles_per_sec: %x, cache_data: %p\n", __FUNCTION__,
ilpcycles_per_sec, cache_data));
return BCME_OK;
}
void
si_pmu_ulp_chipconfig(si_t *sih, osl_t *osh)
{
uint32 reg_val;
BCM_REFERENCE(reg_val);
if (CHIPID(sih->chip) == BCM43012_CHIP_ID) {
/* DS1 reset and clk enable init value config */
si_pmu_chipcontrol(sih, PMU_CHIPCTL14, ~0x0,
(PMUCCTL14_43012_ARMCM3_RESET_INITVAL |
PMUCCTL14_43012_DOT11MAC_CLKEN_INITVAL |
PMUCCTL14_43012_SDIOD_RESET_INIVAL |
PMUCCTL14_43012_SDIO_CLK_DMN_RESET_INITVAL |
PMUCCTL14_43012_SOCRAM_CLKEN_INITVAL |
PMUCCTL14_43012_M2MDMA_RESET_INITVAL |
PMUCCTL14_43012_DOT11MAC_PHY_CLK_EN_INITVAL |
PMUCCTL14_43012_DOT11MAC_PHY_CNTL_EN_INITVAL));
/* Clear SFlash clock request and enable High Quality clock */
CHIPC_REG(sih, clk_ctl_st, CCS_SFLASH_CLKREQ | CCS_HQCLKREQ, CCS_HQCLKREQ);
reg_val = PMU_REG(sih, min_res_mask, ~0x0, ULP_MIN_RES_MASK);
ULP_DBG(("si_pmu_ulp_chipconfig: min_res_mask: 0x%08x\n", reg_val));
/* Force power switch off */
si_pmu_chipcontrol(sih, PMU_CHIPCTL2,
(PMUCCTL02_43012_SUBCORE_PWRSW_FORCE_ON |
PMUCCTL02_43012_PHY_PWRSW_FORCE_ON), 0);
}
}
void
si_pmu_ulp_ilp_config(si_t *sih, osl_t *osh, uint32 ilp_period)
{
pmuregs_t *pmu;
pmu = si_setcoreidx(sih, si_findcoreidx(sih, PMU_CORE_ID, 0));
W_REG(osh, &pmu->ILPPeriod, ilp_period);
si_lhl_ilp_config(sih, osh, ilp_period);
}
/** Initialize DS1 PMU hardware resources */
void
si_pmu_ds1_res_init(si_t *sih, osl_t *osh)
{
pmuregs_t *pmu;
uint origidx;
const pmu_res_updown_t *pmu_res_updown_table = NULL;
uint pmu_res_updown_table_sz = 0;
/* Remember original core before switch to chipc/pmu */
origidx = si_coreidx(sih);
if (AOB_ENAB(sih)) {
pmu = si_setcore(sih, PMU_CORE_ID, 0);
} else {
pmu = si_setcoreidx(sih, SI_CC_IDX);
}
ASSERT(pmu != NULL);
switch (CHIPID(sih->chip)) {
case BCM43012_CHIP_ID:
pmu_res_updown_table = bcm43012a0_res_updown_ds1;
pmu_res_updown_table_sz = ARRAYSIZE(bcm43012a0_res_updown_ds1);
break;
default:
break;
}
/* Program up/down timers */
while (pmu_res_updown_table_sz--) {
ASSERT(pmu_res_updown_table != NULL);
PMU_MSG(("DS1: Changing rsrc %d res_updn_timer to 0x%x\n",
pmu_res_updown_table[pmu_res_updown_table_sz].resnum,
pmu_res_updown_table[pmu_res_updown_table_sz].updown));
W_REG(osh, &pmu->res_table_sel,
pmu_res_updown_table[pmu_res_updown_table_sz].resnum);
W_REG(osh, &pmu->res_updn_timer,
pmu_res_updown_table[pmu_res_updown_table_sz].updown);
}
/* Return to original core */
si_setcoreidx(sih, origidx);
}
#endif /* defined(BCMULP) */
uint32
si_pmu_wake_bit_offset(si_t *sih)
{
uint32 wakebit;
switch (CHIPID(sih->chip)) {
case BCM4347_CHIP_GRPID:
wakebit = CC2_4347_GCI2WAKE_MASK;
break;
default:
wakebit = 0;
ASSERT(0);
break;
}
return wakebit;
}
void si_pmu_set_min_res_mask(si_t *sih, osl_t *osh, uint min_res_mask)
{
pmuregs_t *pmu;
uint origidx;
/* Remember original core before switch to chipc/pmu */
origidx = si_coreidx(sih);
if (AOB_ENAB(sih)) {
pmu = si_setcore(sih, PMU_CORE_ID, 0);
}
else {
pmu = si_setcoreidx(sih, SI_CC_IDX);
}
ASSERT(pmu != NULL);
W_REG(osh, &pmu->min_res_mask, min_res_mask);
OSL_DELAY(100);
/* Return to original core */
si_setcoreidx(sih, origidx);
}
bool
si_pmu_cap_fast_lpo(si_t *sih)
{
return (PMU_REG(sih, core_cap_ext, 0, 0) & PCAP_EXT_USE_MUXED_ILP_CLK_MASK) ? TRUE : FALSE;
}
int
si_pmu_fast_lpo_disable(si_t *sih)
{
if (!si_pmu_cap_fast_lpo(sih)) {
PMU_ERROR(("%s: No Fast LPO capability\n", __FUNCTION__));
return BCME_ERROR;
}
PMU_REG(sih, pmucontrol_ext,
PCTL_EXT_FASTLPO_ENAB |
PCTL_EXT_FASTLPO_SWENAB |
PCTL_EXT_FASTLPO_PCIE_SWENAB,
0);
OSL_DELAY(1000);
return BCME_OK;
}
#ifdef BCMPMU_STATS
/*
* 8 pmu statistics timer default map
*
* for CORE_RDY_AUX measure, set as below for timer 6 and 7 instead of CORE_RDY_MAIN.
* //core-n active duration : pmu_rsrc_state(CORE_RDY_AUX)
* { SRC_CORE_RDY_AUX, FALSE, TRUE, LEVEL_HIGH},
* //core-n active duration : pmu_rsrc_state(CORE_RDY_AUX)
* { SRC_CORE_RDY_AUX, FALSE, TRUE, EDGE_RISE}
*/
static pmu_stats_timer_t pmustatstimer[] = {
{ SRC_LINK_IN_L12, FALSE, TRUE, PMU_STATS_LEVEL_HIGH}, //link_in_l12
{ SRC_LINK_IN_L23, FALSE, TRUE, PMU_STATS_LEVEL_HIGH}, //link_in_l23
{ SRC_PM_ST_IN_D0, FALSE, TRUE, PMU_STATS_LEVEL_HIGH}, //pm_st_in_d0
{ SRC_PM_ST_IN_D3, FALSE, TRUE, PMU_STATS_LEVEL_HIGH}, //pm_st_in_d3
//deep-sleep duration : pmu_rsrc_state(XTAL_PU)
{ SRC_XTAL_PU, FALSE, TRUE, PMU_STATS_LEVEL_LOW},
//deep-sleep entry count : pmu_rsrc_state(XTAL_PU)
{ SRC_XTAL_PU, FALSE, TRUE, PMU_STATS_EDGE_FALL},
//core-n active duration : pmu_rsrc_state(CORE_RDY_MAIN)
{ SRC_CORE_RDY_MAIN, FALSE, TRUE, PMU_STATS_LEVEL_HIGH},
//core-n active duration : pmu_rsrc_state(CORE_RDY_MAIN)
{ SRC_CORE_RDY_MAIN, FALSE, TRUE, PMU_STATS_EDGE_RISE}
};
static void
si_pmustatstimer_update(osl_t *osh, pmuregs_t *pmu, uint8 timerid)
{
uint32 stats_timer_ctrl;
W_REG(osh, &pmu->pmu_statstimer_addr, timerid);
stats_timer_ctrl =
((pmustatstimer[timerid].src_num << PMU_ST_SRC_SHIFT) &
PMU_ST_SRC_MASK) |
((pmustatstimer[timerid].cnt_mode << PMU_ST_CNT_MODE_SHIFT) &
PMU_ST_CNT_MODE_MASK) |
((pmustatstimer[timerid].enable << PMU_ST_EN_SHIFT) & PMU_ST_EN_MASK) |
((pmustatstimer[timerid].int_enable << PMU_ST_INT_EN_SHIFT) & PMU_ST_INT_EN_MASK);
W_REG(osh, &pmu->pmu_statstimer_ctrl, stats_timer_ctrl);
W_REG(osh, &pmu->pmu_statstimer_N, 0);
}
void
si_pmustatstimer_int_enable(si_t *sih)
{
pmuregs_t *pmu;
uint origidx;
osl_t *osh = si_osh(sih);
/* Remember original core before switch to chipc/pmu */
origidx = si_coreidx(sih);
if (AOB_ENAB(sih)) {
pmu = si_setcore(sih, PMU_CORE_ID, 0);
} else {
pmu = si_setcoreidx(sih, SI_CC_IDX);
}
ASSERT(pmu != NULL);
OR_REG(osh, &pmu->pmuintmask0, PMU_INT_STAT_TIMER_INT_MASK);
/* Return to original core */
si_setcoreidx(sih, origidx);
}
void
si_pmustatstimer_int_disable(si_t *sih)
{
pmuregs_t *pmu;
uint origidx;
osl_t *osh = si_osh(sih);
/* Remember original core before switch to chipc/pmu */
origidx = si_coreidx(sih);
if (AOB_ENAB(sih)) {
pmu = si_setcore(sih, PMU_CORE_ID, 0);
} else {
pmu = si_setcoreidx(sih, SI_CC_IDX);
}
ASSERT(pmu != NULL);
AND_REG(osh, &pmu->pmuintmask0, ~PMU_INT_STAT_TIMER_INT_MASK);
/* Return to original core */
si_setcoreidx(sih, origidx);
}
void
si_pmustatstimer_init(si_t *sih)
{
pmuregs_t *pmu;
uint origidx;
osl_t *osh = si_osh(sih);
uint32 core_cap_ext;
uint8 max_stats_timer_num;
int8 i;
/* Remember original core before switch to chipc/pmu */
origidx = si_coreidx(sih);
if (AOB_ENAB(sih)) {
pmu = si_setcore(sih, PMU_CORE_ID, 0);
} else {
pmu = si_setcoreidx(sih, SI_CC_IDX);
}
ASSERT(pmu != NULL);
core_cap_ext = R_REG(osh, &pmu->core_cap_ext);
max_stats_timer_num = ((core_cap_ext & PCAP_EXT_ST_NUM_MASK) >> PCAP_EXT_ST_NUM_SHIFT) + 1;
for (i = 0; i < max_stats_timer_num; i++) {
si_pmustatstimer_update(osh, pmu, i);
}
OR_REG(osh, &pmu->pmuintmask0, PMU_INT_STAT_TIMER_INT_MASK);
/* Return to original core */
si_setcoreidx(sih, origidx);
}
void
si_pmustatstimer_dump(si_t *sih)
{
pmuregs_t *pmu;
uint origidx;
osl_t *osh = si_osh(sih);
uint32 core_cap_ext, pmucapabilities, AlpPeriod, ILPPeriod, pmuintmask0, pmuintstatus;
uint8 max_stats_timer_num, max_stats_timer_src_num;
uint32 stat_timer_ctrl, stat_timer_N;
uint8 i;
uint32 current_time_ms = OSL_SYSUPTIME();
/* Remember original core before switch to chipc/pmu */
origidx = si_coreidx(sih);
if (AOB_ENAB(sih)) {
pmu = si_setcore(sih, PMU_CORE_ID, 0);
} else {
pmu = si_setcoreidx(sih, SI_CC_IDX);
}
ASSERT(pmu != NULL);
pmucapabilities = R_REG(osh, &pmu->pmucapabilities);
core_cap_ext = R_REG(osh, &pmu->core_cap_ext);
AlpPeriod = R_REG(osh, &pmu->slowclkperiod);
ILPPeriod = R_REG(osh, &pmu->ILPPeriod);
max_stats_timer_num = ((core_cap_ext & PCAP_EXT_ST_NUM_MASK) >>
PCAP_EXT_ST_NUM_SHIFT) + 1;
max_stats_timer_src_num = ((core_cap_ext & PCAP_EXT_ST_SRC_NUM_MASK) >>
PCAP_EXT_ST_SRC_NUM_SHIFT) + 1;
pmuintstatus = R_REG(osh, &pmu->pmuintstatus);
pmuintmask0 = R_REG(osh, &pmu->pmuintmask0);
PMU_ERROR(("%s : TIME %d\n", __FUNCTION__, current_time_ms));
PMU_ERROR(("\tMAX Timer Num %d, MAX Source Num %d\n",
max_stats_timer_num, max_stats_timer_src_num));
PMU_ERROR(("\tpmucapabilities 0x%8x, core_cap_ext 0x%8x, AlpPeriod 0x%8x, ILPPeriod 0x%8x, "
"pmuintmask0 0x%8x, pmuintstatus 0x%8x, pmurev %d\n",
pmucapabilities, core_cap_ext, AlpPeriod, ILPPeriod,
pmuintmask0, pmuintstatus, PMUREV(sih->pmurev)));
for (i = 0; i < max_stats_timer_num; i++) {
W_REG(osh, &pmu->pmu_statstimer_addr, i);
stat_timer_ctrl = R_REG(osh, &pmu->pmu_statstimer_ctrl);
stat_timer_N = R_REG(osh, &pmu->pmu_statstimer_N);
PMU_ERROR(("\t Timer %d : control 0x%8x, %d\n",
i, stat_timer_ctrl, stat_timer_N));
}
/* Return to original core */
si_setcoreidx(sih, origidx);
}
void
si_pmustatstimer_start(si_t *sih, uint8 timerid)
{
pmuregs_t *pmu;
uint origidx;
osl_t *osh = si_osh(sih);
/* Remember original core before switch to chipc/pmu */
origidx = si_coreidx(sih);
if (AOB_ENAB(sih)) {
pmu = si_setcore(sih, PMU_CORE_ID, 0);
} else {
pmu = si_setcoreidx(sih, SI_CC_IDX);
}
ASSERT(pmu != NULL);
pmustatstimer[timerid].enable = TRUE;
W_REG(osh, &pmu->pmu_statstimer_addr, timerid);
OR_REG(osh, &pmu->pmu_statstimer_ctrl, PMU_ST_ENAB << PMU_ST_EN_SHIFT);
/* Return to original core */
si_setcoreidx(sih, origidx);
}
void
si_pmustatstimer_stop(si_t *sih, uint8 timerid)
{
pmuregs_t *pmu;
uint origidx;
osl_t *osh = si_osh(sih);
/* Remember original core before switch to chipc/pmu */
origidx = si_coreidx(sih);
if (AOB_ENAB(sih)) {
pmu = si_setcore(sih, PMU_CORE_ID, 0);
} else {
pmu = si_setcoreidx(sih, SI_CC_IDX);
}
ASSERT(pmu != NULL);
pmustatstimer[timerid].enable = FALSE;
W_REG(osh, &pmu->pmu_statstimer_addr, timerid);
AND_REG(osh, &pmu->pmu_statstimer_ctrl, ~(PMU_ST_ENAB << PMU_ST_EN_SHIFT));
/* Return to original core */
si_setcoreidx(sih, origidx);
}
void
si_pmustatstimer_clear(si_t *sih, uint8 timerid)
{
pmuregs_t *pmu;
uint origidx;
osl_t *osh = si_osh(sih);
/* Remember original core before switch to chipc/pmu */
origidx = si_coreidx(sih);
if (AOB_ENAB(sih)) {
pmu = si_setcore(sih, PMU_CORE_ID, 0);
} else {
pmu = si_setcoreidx(sih, SI_CC_IDX);
}
ASSERT(pmu != NULL);
W_REG(osh, &pmu->pmu_statstimer_addr, timerid);
W_REG(osh, &pmu->pmu_statstimer_N, 0);
/* Return to original core */
si_setcoreidx(sih, origidx);
}
void
si_pmustatstimer_clear_overflow(si_t *sih)
{
uint8 i;
uint32 core_cap_ext;
uint8 max_stats_timer_num;
uint32 timerN;
pmuregs_t *pmu;
uint origidx;
osl_t *osh = si_osh(sih);
/* Remember original core before switch to chipc/pmu */
origidx = si_coreidx(sih);
if (AOB_ENAB(sih)) {
pmu = si_setcore(sih, PMU_CORE_ID, 0);
} else {
pmu = si_setcoreidx(sih, SI_CC_IDX);
}
ASSERT(pmu != NULL);
core_cap_ext = R_REG(osh, &pmu->core_cap_ext);
max_stats_timer_num = ((core_cap_ext & PCAP_EXT_ST_NUM_MASK) >> PCAP_EXT_ST_NUM_SHIFT) + 1;
for (i = 0; i < max_stats_timer_num; i++) {
W_REG(osh, &pmu->pmu_statstimer_addr, i);
timerN = R_REG(osh, &pmu->pmu_statstimer_N);
if (timerN == 0xFFFFFFFF) {
PMU_ERROR(("pmustatstimer overflow clear - timerid : %d\n", i));
si_pmustatstimer_clear(sih, i);
}
}
/* Return to original core */
si_setcoreidx(sih, origidx);
}
uint32
si_pmustatstimer_read(si_t *sih, uint8 timerid)
{
pmuregs_t *pmu;
uint origidx;
osl_t *osh = si_osh(sih);
uint32 stats_timer_N;
/* Remember original core before switch to chipc/pmu */
origidx = si_coreidx(sih);
if (AOB_ENAB(sih)) {
pmu = si_setcore(sih, PMU_CORE_ID, 0);
} else {
pmu = si_setcoreidx(sih, SI_CC_IDX);
}
ASSERT(pmu != NULL);
W_REG(osh, &pmu->pmu_statstimer_addr, timerid);
stats_timer_N = R_REG(osh, &pmu->pmu_statstimer_N);
/* Return to original core */
si_setcoreidx(sih, origidx);
return stats_timer_N;
}
void
si_pmustatstimer_cfg_src_num(si_t *sih, uint8 src_num, uint8 timerid)
{
pmuregs_t *pmu;
uint origidx;
osl_t *osh = si_osh(sih);
/* Remember original core before switch to chipc/pmu */
origidx = si_coreidx(sih);
if (AOB_ENAB(sih)) {
pmu = si_setcore(sih, PMU_CORE_ID, 0);
} else {
pmu = si_setcoreidx(sih, SI_CC_IDX);
}
ASSERT(pmu != NULL);
pmustatstimer[timerid].src_num = src_num;
si_pmustatstimer_update(osh, pmu, timerid);
/* Return to original core */
si_setcoreidx(sih, origidx);
}
void
si_pmustatstimer_cfg_cnt_mode(si_t *sih, uint8 cnt_mode, uint8 timerid)
{
pmuregs_t *pmu;
uint origidx;
osl_t *osh = si_osh(sih);
/* Remember original core before switch to chipc/pmu */
origidx = si_coreidx(sih);
if (AOB_ENAB(sih)) {
pmu = si_setcore(sih, PMU_CORE_ID, 0);
} else {
pmu = si_setcoreidx(sih, SI_CC_IDX);
}
ASSERT(pmu != NULL);
pmustatstimer[timerid].cnt_mode = cnt_mode;
si_pmustatstimer_update(osh, pmu, timerid);
/* Return to original core */
si_setcoreidx(sih, origidx);
}
#endif /* BCMPMU_STATS */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,140 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* 802.11e protocol header file
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: 802.11e.h 785355 2018-10-18 05:32:56Z $
*/
#ifndef _802_11e_H_
#define _802_11e_H_
#ifndef _TYPEDEFS_H_
#include <typedefs.h>
#endif // endif
/* This marks the start of a packed structure section. */
#include <packed_section_start.h>
/* WME Traffic Specification (TSPEC) element */
#define WME_TSPEC_HDR_LEN 2 /* WME TSPEC header length */
#define WME_TSPEC_BODY_OFF 2 /* WME TSPEC body offset */
#define WME_CATEGORY_CODE_OFFSET 0 /* WME Category code offset */
#define WME_ACTION_CODE_OFFSET 1 /* WME Action code offset */
#define WME_TOKEN_CODE_OFFSET 2 /* WME Token code offset */
#define WME_STATUS_CODE_OFFSET 3 /* WME Status code offset */
BWL_PRE_PACKED_STRUCT struct tsinfo {
uint8 octets[3];
} BWL_POST_PACKED_STRUCT;
typedef struct tsinfo tsinfo_t;
/* 802.11e TSPEC IE */
typedef BWL_PRE_PACKED_STRUCT struct tspec {
uint8 oui[DOT11_OUI_LEN]; /* WME_OUI */
uint8 type; /* WME_TYPE */
uint8 subtype; /* WME_SUBTYPE_TSPEC */
uint8 version; /* WME_VERSION */
tsinfo_t tsinfo; /* TS Info bit field */
uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */
uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */
uint32 min_srv_interval; /* Minimum Service Interval (us) */
uint32 max_srv_interval; /* Maximum Service Interval (us) */
uint32 inactivity_interval; /* Inactivity Interval (us) */
uint32 suspension_interval; /* Suspension Interval (us) */
uint32 srv_start_time; /* Service Start Time (us) */
uint32 min_data_rate; /* Minimum Data Rate (bps) */
uint32 mean_data_rate; /* Mean Data Rate (bps) */
uint32 peak_data_rate; /* Peak Data Rate (bps) */
uint32 max_burst_size; /* Maximum Burst Size (bytes) */
uint32 delay_bound; /* Delay Bound (us) */
uint32 min_phy_rate; /* Minimum PHY Rate (bps) */
uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0-8.0) */
uint16 medium_time; /* Medium Time (32 us/s periods) */
} BWL_POST_PACKED_STRUCT tspec_t;
#define WME_TSPEC_LEN (sizeof(tspec_t)) /* not including 2-bytes of header */
/* ts_info */
/* 802.1D priority is duplicated - bits 13-11 AND bits 3-1 */
#define TS_INFO_TID_SHIFT 1 /* TS info. TID shift */
#define TS_INFO_TID_MASK (0xf << TS_INFO_TID_SHIFT) /* TS info. TID mask */
#define TS_INFO_CONTENTION_SHIFT 7 /* TS info. contention shift */
#define TS_INFO_CONTENTION_MASK (0x1 << TS_INFO_CONTENTION_SHIFT) /* TS info. contention mask */
#define TS_INFO_DIRECTION_SHIFT 5 /* TS info. direction shift */
#define TS_INFO_DIRECTION_MASK (0x3 << TS_INFO_DIRECTION_SHIFT) /* TS info. direction mask */
#define TS_INFO_PSB_SHIFT 2 /* TS info. PSB bit Shift */
#define TS_INFO_PSB_MASK (1 << TS_INFO_PSB_SHIFT) /* TS info. PSB mask */
#define TS_INFO_UPLINK (0 << TS_INFO_DIRECTION_SHIFT) /* TS info. uplink */
#define TS_INFO_DOWNLINK (1 << TS_INFO_DIRECTION_SHIFT) /* TS info. downlink */
#define TS_INFO_BIDIRECTIONAL (3 << TS_INFO_DIRECTION_SHIFT) /* TS info. bidirectional */
#define TS_INFO_USER_PRIO_SHIFT 3 /* TS info. user priority shift */
/* TS info. user priority mask */
#define TS_INFO_USER_PRIO_MASK (0x7 << TS_INFO_USER_PRIO_SHIFT)
/* Macro to get/set bit(s) field in TSINFO */
#define WLC_CAC_GET_TID(pt) ((((pt).octets[0]) & TS_INFO_TID_MASK) >> TS_INFO_TID_SHIFT)
#define WLC_CAC_GET_DIR(pt) ((((pt).octets[0]) & \
TS_INFO_DIRECTION_MASK) >> TS_INFO_DIRECTION_SHIFT)
#define WLC_CAC_GET_PSB(pt) ((((pt).octets[1]) & TS_INFO_PSB_MASK) >> TS_INFO_PSB_SHIFT)
#define WLC_CAC_GET_USER_PRIO(pt) ((((pt).octets[1]) & \
TS_INFO_USER_PRIO_MASK) >> TS_INFO_USER_PRIO_SHIFT)
#define WLC_CAC_SET_TID(pt, id) ((((pt).octets[0]) & (~TS_INFO_TID_MASK)) | \
((id) << TS_INFO_TID_SHIFT))
#define WLC_CAC_SET_USER_PRIO(pt, prio) ((((pt).octets[0]) & (~TS_INFO_USER_PRIO_MASK)) | \
((prio) << TS_INFO_USER_PRIO_SHIFT))
/* 802.11e QBSS Load IE */
#define QBSS_LOAD_IE_LEN 5 /* QBSS Load IE length */
#define QBSS_LOAD_AAC_OFF 3 /* AAC offset in IE */
#define CAC_ADDTS_RESP_TIMEOUT 1000 /* default ADDTS response timeout in ms */
/* DEFVAL dot11ADDTSResponseTimeout = 1s */
/* 802.11e ADDTS status code */
#define DOT11E_STATUS_ADMISSION_ACCEPTED 0 /* TSPEC Admission accepted status */
#define DOT11E_STATUS_ADDTS_INVALID_PARAM 1 /* TSPEC invalid parameter status */
#define DOT11E_STATUS_ADDTS_REFUSED_NSBW 3 /* ADDTS refused (non-sufficient BW) */
#define DOT11E_STATUS_ADDTS_REFUSED_AWHILE 47 /* ADDTS refused but could retry later */
#ifdef BCMCCX
#define CCX_STATUS_ASSOC_DENIED_UNKNOWN 0xc8 /* unspecified QoS related failure */
#define CCX_STATUS_ASSOC_DENIED_AP_POLICY 0xc9 /* TSPEC refused due to AP policy */
#define CCX_STATUS_ASSOC_DENIED_NO_BW 0xca /* Assoc denied due to AP insufficient BW */
#define CCX_STATUS_ASSOC_DENIED_BAD_PARAM 0xcb /* one or more TSPEC with invalid parameter */
#endif /* BCMCCX */
/* 802.11e DELTS status code */
#define DOT11E_STATUS_QSTA_LEAVE_QBSS 36 /* STA leave QBSS */
#define DOT11E_STATUS_END_TS 37 /* END TS */
#define DOT11E_STATUS_UNKNOWN_TS 38 /* UNKNOWN TS */
#define DOT11E_STATUS_QSTA_REQ_TIMEOUT 39 /* STA ADDTS request timeout */
/* This marks the end of a packed structure section. */
#include <packed_section_end.h>
#endif /* _802_11e_CAC_H_ */

View File

@@ -0,0 +1,335 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Fundamental types and constants relating to 802.11s Mesh
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: 802.11s.h 700076 2017-05-17 14:42:22Z $
*/
#ifndef _802_11s_h_
#define _802_11s_h_
/* This marks the start of a packed structure section. */
#include <packed_section_start.h>
#define DOT11_MESH_FLAGS_AE_MASK 0x3
#define DOT11_MESH_FLAGS_AE_SHIFT 0
#define DOT11_MESH_CONNECTED_AS_SET 7
#define DOT11_MESH_NUMBER_PEERING_SET 1
#define DOT11_MESH_MESH_GWSET 0
#define DOT11_MESH_ACTION_LINK_MET_REP 0
#define DOT11_MESH_ACTION_PATH_SEL 1
#define DOT11_MESH_ACTION_GATE_ANN 2
#define DOT11_MESH_ACTION_CONG_CONT_NOTIF 3
#define DOT11_MESH_ACTION_MCCA_SETUP_REQ 4
#define DOT11_MESH_ACTION_MCCA_SETUP_REP 5
#define DOT11_MESH_ACTION_MCCA_ADVT_REQ 6
#define DOT11_MESH_ACTION_MCCA_ADVT 7
#define DOT11_MESH_ACTION_MCCA_TEARDOWN 8
#define DOT11_MESH_ACTION_TBTT_ADJ_REQ 9
#define DOT11_MESH_ACTION_TBTT_ADJ_RESP 10
/* self-protected action field values: 7-57v24 */
#define DOT11_SELFPROT_ACTION_MESH_PEER_OPEN 1
#define DOT11_SELFPROT_ACTION_MESH_PEER_CONFM 2
#define DOT11_SELFPROT_ACTION_MESH_PEER_CLOSE 3
#define DOT11_SELFPROT_ACTION_MESH_PEER_GK_INF 4
#define DOT11_SELFPROT_ACTION_MESH_PEER_GK_ACK 5
#define DOT11_MESH_AUTH_PROTO_NONE 0
#define DOT11_MESH_AUTH_PROTO_SAE 1
#define DOT11_MESH_AUTH_PROTO_8021X 2
#define DOT11_MESH_AUTH_PROTO_VS 255
#define DOT11_MESH_PATHSEL_LEN 2
#define DOT11_MESH_PERR_LEN1 2 /* Least PERR length fixed */
#define DOT11_MESH_PERR_LEN2 13 /* Least PERR length variable */
#define DOT11_MESH_PREP_LEN 31 /* Least PREP length */
#define DOT11_MESH_PREQ_LEN 37 /* Least PREQ length */
#define DOT11_MESH_PATHSEL_PROTID_HWMP 1
#define DOT11_MESH_PATHSEL_METRICID_ALM 1 /* Air link metric */
#define DOT11_MESH_CONGESTCTRL_NONE 0
#define DOT11_MESH_CONGESTCTRL_SP 1
#define DOT11_MESH_SYNCMETHOD_NOFFSET 1
BWL_PRE_PACKED_STRUCT struct dot11_meshctrl_hdr {
uint8 flags; /* flag bits such as ae etc */
uint8 ttl; /* time to live */
uint32 seq; /* sequence control */
struct ether_addr a5; /* optional address 5 */
struct ether_addr a6; /* optional address 6 */
} BWL_POST_PACKED_STRUCT;
/* Mesh Path Selection Action Frame */
BWL_PRE_PACKED_STRUCT struct dot11_mesh_pathsel {
uint8 category;
uint8 meshaction;
uint8 data[];
} BWL_POST_PACKED_STRUCT;
typedef struct dot11_mesh_pathsel dot11_mesh_pathsel_t;
/* Mesh PREQ IE */
BWL_PRE_PACKED_STRUCT struct mesh_preq_ie {
uint8 id;
uint8 len;
uint8 flags;
uint8 hop_count;
uint8 ttl;
uint32 pathdis_id;
struct ether_addr originator_addr;
uint32 originator_seq;
union {
BWL_PRE_PACKED_STRUCT struct {
struct ether_addr target_ext_add;
uint32 lifetime;
uint32 metric;
uint8 target_count;
uint8 data[];
} BWL_POST_PACKED_STRUCT oea;
BWL_PRE_PACKED_STRUCT struct {
uint32 lifetime;
uint32 metric;
uint8 target_count;
uint8 data[];
} BWL_POST_PACKED_STRUCT noea;
} u;
} BWL_POST_PACKED_STRUCT;
typedef struct mesh_preq_ie mesh_preq_ie_t;
/* Target info (part of Mesh PREQ IE) */
BWL_PRE_PACKED_STRUCT struct mesh_targetinfo {
uint8 target_flag;
struct ether_addr target_addr;
uint32 target_seq;
} BWL_POST_PACKED_STRUCT;
typedef struct mesh_targetinfo mesh_targetinfo_t;
/* Mesh PREP IE */
BWL_PRE_PACKED_STRUCT struct mesh_prep_ie {
uint8 id;
uint8 len;
uint8 flags;
uint8 hop_count;
uint8 ttl;
struct ether_addr target_addr;
uint32 target_seq;
union {
BWL_PRE_PACKED_STRUCT struct {
struct ether_addr target_ext_add;
uint32 lifetime;
uint32 metric;
uint8 target_count;
struct ether_addr originator_addr;
uint32 originator_seq;
} BWL_POST_PACKED_STRUCT oea;
BWL_PRE_PACKED_STRUCT struct {
uint32 lifetime;
uint32 metric;
uint8 target_count;
struct ether_addr originator_addr;
uint32 originator_seq;
} BWL_POST_PACKED_STRUCT noea;
} u;
} BWL_POST_PACKED_STRUCT;
typedef struct mesh_prep_ie mesh_prep_ie_t;
/* Mesh PERR IE */
struct mesh_perr_ie {
uint8 id;
uint8 len;
uint8 ttl;
uint8 num_dest;
uint8 data[];
};
typedef struct mesh_perr_ie mesh_perr_ie_t;
/* Destination info is part of PERR IE */
BWL_PRE_PACKED_STRUCT struct mesh_perr_destinfo {
uint8 flags;
struct ether_addr destination_addr;
uint32 dest_seq;
union {
BWL_PRE_PACKED_STRUCT struct {
struct ether_addr dest_ext_addr;
} BWL_POST_PACKED_STRUCT dea;
BWL_PRE_PACKED_STRUCT struct {
/* 1 byte reason code to be populated manually in software */
uint16 reason_code;
} BWL_POST_PACKED_STRUCT nodea;
} u;
} BWL_POST_PACKED_STRUCT;
typedef struct mesh_perr_destinfo mesh_perr_destinfo_t;
/* Mesh peering action frame hdr */
BWL_PRE_PACKED_STRUCT struct mesh_peering_frmhdr {
uint8 category;
uint8 action;
union {
struct {
uint16 capability;
} open;
struct {
uint16 capability;
uint16 AID;
} confirm;
uint8 data[1];
} u;
} BWL_POST_PACKED_STRUCT;
typedef struct mesh_peering_frmhdr mesh_peering_frmhdr_t;
/* Mesh peering mgmt IE */
BWL_PRE_PACKED_STRUCT struct mesh_peer_mgmt_ie_common {
uint16 mesh_peer_prot_id;
uint16 local_link_id;
} BWL_POST_PACKED_STRUCT;
typedef struct mesh_peer_mgmt_ie_common mesh_peer_mgmt_ie_common_t;
#define MESH_PEER_MGMT_IE_OPEN_LEN (4)
BWL_PRE_PACKED_STRUCT struct mesh_peer_mgmt_ie_cfm {
mesh_peer_mgmt_ie_common_t common;
uint16 peer_link_id;
} BWL_POST_PACKED_STRUCT;
typedef struct mesh_peer_mgmt_ie_cfm mesh_peer_mgmt_ie_cfm_t;
#define MESH_PEER_MGMT_IE_CONF_LEN (6)
BWL_PRE_PACKED_STRUCT struct mesh_peer_mgmt_ie_close {
mesh_peer_mgmt_ie_common_t common;
/* uint16 peer_link_id;
* simplicity: not supported, TODO for future
*/
uint16 reason_code;
} BWL_POST_PACKED_STRUCT;
typedef struct mesh_peer_mgmt_ie_close mesh_peer_mgmt_ie_close_t;
#define MESH_PEER_MGMT_IE_CLOSE_LEN (6)
struct mesh_config_ie {
uint8 activ_path_sel_prot_id;
uint8 activ_path_sel_metric_id;
uint8 cong_ctl_mode_id;
uint8 sync_method_id;
uint8 auth_prot_id;
uint8 mesh_formation_info;
uint8 mesh_cap;
};
typedef struct mesh_config_ie mesh_config_ie_t;
#define MESH_CONFIG_IE_LEN (7)
/* Mesh peering states */
#define MESH_PEERING_IDLE 0
#define MESH_PEERING_OPEN_SNT 1
#define MESH_PEERING_CNF_RCVD 2
#define MESH_PEERING_OPEN_RCVD 3
#define MESH_PEERING_ESTAB 4
#define MESH_PEERING_HOLDING 5
#define MESH_PEERING_LAST_STATE 6
/* for debugging: mapping strings */
#define MESH_PEERING_STATE_STRINGS \
{"IDLE ", "OPNSNT", "CNFRCV", "OPNRCV", "ESTAB ", "HOLDNG"}
#ifdef WLMESH
typedef BWL_PRE_PACKED_STRUCT struct mesh_peer_info {
/* mesh_peer_instance as given in the spec. Note that, peer address
* is stored in scb
*/
uint16 mesh_peer_prot_id;
uint16 local_link_id;
uint16 peer_link_id;
/* AID generated by *peer* to self & received in peer_confirm */
uint16 peer_aid;
/* TODO: no mention in spec? possibly used in PS case. Note that aid generated
* from self to peer is stored in scb.
*/
uint8 state;
/* TODO: struct mesh_peer_info *next; this field is required
* if multiple peerings per same src is allowed, which is
* true as per spec.
*/
} BWL_POST_PACKED_STRUCT mesh_peer_info_t;
typedef BWL_PRE_PACKED_STRUCT struct mesh_peer_info_ext {
mesh_peer_info_t peer_info;
uint16 local_aid; /* AID generated by *local* to peer */
struct ether_addr ea; /* peer ea */
uint32 entry_state; /* see MESH_PEER_ENTRY_STATE_ACTIVE etc; valid
* ONLY for internal peering requests
*/
int rssi;
} BWL_POST_PACKED_STRUCT mesh_peer_info_ext_t;
/* #ifdef WLMESH */
typedef BWL_PRE_PACKED_STRUCT struct mesh_peer_info_dump {
uint32 buflen;
uint32 version;
uint32 count; /* number of results */
mesh_peer_info_ext_t mpi_ext[1];
} BWL_POST_PACKED_STRUCT mesh_peer_info_dump_t;
#define WL_MESH_PEER_RES_FIXED_SIZE (sizeof(mesh_peer_info_dump_t) - sizeof(mesh_peer_info_ext_t))
#endif /* WLMESH */
/* once an entry is added into mesh_peer_list, if peering is lost, it will
* get retried for peering, MAX_MESH_PEER_ENTRY_RETRIES times. after wards, it
* wont get retried and will be moved to MESH_PEER_ENTRY_STATE_TIMEDOUT state,
* until user adds it again explicitely, when its entry_state is changed
* to MESH_PEER_ENTRY_STATE_ACTIVE and tried again.
*/
#define MAX_MESH_SELF_PEER_ENTRY_RETRIES 3
#define MESH_SELF_PEER_ENTRY_STATE_ACTIVE 1
#define MESH_SELF_PEER_ENTRY_STATE_TIMEDOUT 2
/** Mesh Channel Switch Parameter IE data structure */
BWL_PRE_PACKED_STRUCT struct dot11_mcsp_body {
uint8 ttl; /* remaining number of hops allowed for this element. */
uint8 flags; /* attributes of this channel switch attempt */
uint8 reason; /* reason for the mesh channel switch */
uint16 precedence; /* random value in the range 0 to 65535 */
} BWL_POST_PACKED_STRUCT;
#define DOT11_MCSP_TTL_DEFAULT 1
#define DOT11_MCSP_FLAG_TRANS_RESTRICT 0x1 /* no transmit except frames with mcsp */
#define DOT11_MCSP_FLAG_INIT 0x2 /* initiates the channel switch attempt */
#define DOT11_MCSP_FLAG_REASON 0x4 /* validity of reason code field */
#define DOT11_MCSP_REASON_REGULATORY 0 /* meet regulatory requirements */
#define DOT11_MCSP_REASON_UNSPECIFIED 1 /* unspecified reason */
BWL_PRE_PACKED_STRUCT struct dot11_mesh_csp {
uint8 id; /* id DOT11_MNG_MESH_CSP_ID */
uint8 len; /* length of IE */
struct dot11_mcsp_body body; /* body of the ie */
} BWL_POST_PACKED_STRUCT;
typedef struct dot11_mesh_csp dot11_mesh_csp_ie_t;
#define DOT11_MESH_CSP_IE_LEN 5 /* length of mesh channel switch parameter IE body */
/* This marks the end of a packed structure section. */
#include <packed_section_end.h>
#endif /* #ifndef _802_11s_H_ */

View File

@@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Fundamental types and constants relating to 802.1D
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: 802.1d.h 700076 2017-05-17 14:42:22Z $
*/
#ifndef _802_1_D_
#define _802_1_D_
/* 802.1D priority defines */
#define PRIO_8021D_NONE 2 /* None = - */
#define PRIO_8021D_BK 1 /* BK - Background */
#define PRIO_8021D_BE 0 /* BE - Best-effort */
#define PRIO_8021D_EE 3 /* EE - Excellent-effort */
#define PRIO_8021D_CL 4 /* CL - Controlled Load */
#define PRIO_8021D_VI 5 /* Vi - Video */
#define PRIO_8021D_VO 6 /* Vo - Voice */
#define PRIO_8021D_NC 7 /* NC - Network Control */
#define MAXPRIO 7 /* 0-7 */
#define NUMPRIO (MAXPRIO + 1)
#define ALLPRIO -1 /* All prioirty */
/* Converts prio to precedence since the numerical value of
* PRIO_8021D_BE and PRIO_8021D_NONE are swapped.
*/
#define PRIO2PREC(prio) \
(((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? ((prio^2)) : (prio))
#endif /* _802_1_D__ */

View File

@@ -0,0 +1,56 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Fundamental constants relating to 802.3
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: 802.3.h 700076 2017-05-17 14:42:22Z $
*/
#ifndef _802_3_h_
#define _802_3_h_
/* This marks the start of a packed structure section. */
#include <packed_section_start.h>
#define SNAP_HDR_LEN 6 /* 802.3 SNAP header length */
#define DOT3_OUI_LEN 3 /* 802.3 oui length */
BWL_PRE_PACKED_STRUCT struct dot3_mac_llc_snap_header {
uint8 ether_dhost[ETHER_ADDR_LEN]; /* dest mac */
uint8 ether_shost[ETHER_ADDR_LEN]; /* src mac */
uint16 length; /* frame length incl header */
uint8 dsap; /* always 0xAA */
uint8 ssap; /* always 0xAA */
uint8 ctl; /* always 0x03 */
uint8 oui[DOT3_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00
* Bridge-Tunnel: 0x00 0x00 0xF8
*/
uint16 type; /* ethertype */
} BWL_POST_PACKED_STRUCT;
/* This marks the end of a packed structure section. */
#include <packed_section_end.h>
#endif /* #ifndef _802_3_h_ */

View File

@@ -0,0 +1,430 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Broadcom AMBA Interconnect definitions.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: aidmp.h 617751 2016-02-08 09:04:22Z $
*/
#ifndef _AIDMP_H
#define _AIDMP_H
/* Manufacturer Ids */
#define MFGID_ARM 0x43b
#define MFGID_BRCM 0x4bf
#define MFGID_MIPS 0x4a7
/* Component Classes */
#define CC_SIM 0
#define CC_EROM 1
#define CC_CORESIGHT 9
#define CC_VERIF 0xb
#define CC_OPTIMO 0xd
#define CC_GEN 0xe
#define CC_PRIMECELL 0xf
/* Enumeration ROM registers */
#define ER_EROMENTRY 0x000
#define ER_REMAPCONTROL 0xe00
#define ER_REMAPSELECT 0xe04
#define ER_MASTERSELECT 0xe10
#define ER_ITCR 0xf00
#define ER_ITIP 0xf04
/* Erom entries */
#define ER_TAG 0xe
#define ER_TAG1 0x6
#define ER_VALID 1
#define ER_CI 0
#define ER_MP 2
#define ER_ADD 4
#define ER_END 0xe
#define ER_BAD 0xffffffff
#define ER_SZ_MAX 4096 /* 4KB */
/* EROM CompIdentA */
#define CIA_MFG_MASK 0xfff00000
#define CIA_MFG_SHIFT 20
#define CIA_CID_MASK 0x000fff00
#define CIA_CID_SHIFT 8
#define CIA_CCL_MASK 0x000000f0
#define CIA_CCL_SHIFT 4
/* EROM CompIdentB */
#define CIB_REV_MASK 0xff000000
#define CIB_REV_SHIFT 24
#define CIB_NSW_MASK 0x00f80000
#define CIB_NSW_SHIFT 19
#define CIB_NMW_MASK 0x0007c000
#define CIB_NMW_SHIFT 14
#define CIB_NSP_MASK 0x00003e00
#define CIB_NSP_SHIFT 9
#define CIB_NMP_MASK 0x000001f0
#define CIB_NMP_SHIFT 4
/* EROM MasterPortDesc */
#define MPD_MUI_MASK 0x0000ff00
#define MPD_MUI_SHIFT 8
#define MPD_MP_MASK 0x000000f0
#define MPD_MP_SHIFT 4
/* EROM AddrDesc */
#define AD_ADDR_MASK 0xfffff000
#define AD_SP_MASK 0x00000f00
#define AD_SP_SHIFT 8
#define AD_ST_MASK 0x000000c0
#define AD_ST_SHIFT 6
#define AD_ST_SLAVE 0x00000000
#define AD_ST_BRIDGE 0x00000040
#define AD_ST_SWRAP 0x00000080
#define AD_ST_MWRAP 0x000000c0
#define AD_SZ_MASK 0x00000030
#define AD_SZ_SHIFT 4
#define AD_SZ_4K 0x00000000
#define AD_SZ_8K 0x00000010
#define AD_SZ_16K 0x00000020
#define AD_SZ_SZD 0x00000030
#define AD_AG32 0x00000008
#define AD_ADDR_ALIGN 0x00000fff
#define AD_SZ_BASE 0x00001000 /* 4KB */
/* EROM SizeDesc */
#define SD_SZ_MASK 0xfffff000
#define SD_SG32 0x00000008
#define SD_SZ_ALIGN 0x00000fff
#if !defined(_LANGUAGE_ASSEMBLY) && !defined(__ASSEMBLY__)
typedef volatile struct _aidmp {
uint32 oobselina30; /* 0x000 */
uint32 oobselina74; /* 0x004 */
uint32 PAD[6];
uint32 oobselinb30; /* 0x020 */
uint32 oobselinb74; /* 0x024 */
uint32 PAD[6];
uint32 oobselinc30; /* 0x040 */
uint32 oobselinc74; /* 0x044 */
uint32 PAD[6];
uint32 oobselind30; /* 0x060 */
uint32 oobselind74; /* 0x064 */
uint32 PAD[38];
uint32 oobselouta30; /* 0x100 */
uint32 oobselouta74; /* 0x104 */
uint32 PAD[6];
uint32 oobseloutb30; /* 0x120 */
uint32 oobseloutb74; /* 0x124 */
uint32 PAD[6];
uint32 oobseloutc30; /* 0x140 */
uint32 oobseloutc74; /* 0x144 */
uint32 PAD[6];
uint32 oobseloutd30; /* 0x160 */
uint32 oobseloutd74; /* 0x164 */
uint32 PAD[38];
uint32 oobsynca; /* 0x200 */
uint32 oobseloutaen; /* 0x204 */
uint32 PAD[6];
uint32 oobsyncb; /* 0x220 */
uint32 oobseloutben; /* 0x224 */
uint32 PAD[6];
uint32 oobsyncc; /* 0x240 */
uint32 oobseloutcen; /* 0x244 */
uint32 PAD[6];
uint32 oobsyncd; /* 0x260 */
uint32 oobseloutden; /* 0x264 */
uint32 PAD[38];
uint32 oobaextwidth; /* 0x300 */
uint32 oobainwidth; /* 0x304 */
uint32 oobaoutwidth; /* 0x308 */
uint32 PAD[5];
uint32 oobbextwidth; /* 0x320 */
uint32 oobbinwidth; /* 0x324 */
uint32 oobboutwidth; /* 0x328 */
uint32 PAD[5];
uint32 oobcextwidth; /* 0x340 */
uint32 oobcinwidth; /* 0x344 */
uint32 oobcoutwidth; /* 0x348 */
uint32 PAD[5];
uint32 oobdextwidth; /* 0x360 */
uint32 oobdinwidth; /* 0x364 */
uint32 oobdoutwidth; /* 0x368 */
uint32 PAD[37];
uint32 ioctrlset; /* 0x400 */
uint32 ioctrlclear; /* 0x404 */
uint32 ioctrl; /* 0x408 */
uint32 PAD[61];
uint32 iostatus; /* 0x500 */
uint32 PAD[127];
uint32 ioctrlwidth; /* 0x700 */
uint32 iostatuswidth; /* 0x704 */
uint32 PAD[62];
uint32 resetctrl; /* 0x800 */
uint32 resetstatus; /* 0x804 */
uint32 resetreadid; /* 0x808 */
uint32 resetwriteid; /* 0x80c */
uint32 PAD[60];
uint32 errlogctrl; /* 0x900 */
uint32 errlogdone; /* 0x904 */
uint32 errlogstatus; /* 0x908 */
uint32 errlogaddrlo; /* 0x90c */
uint32 errlogaddrhi; /* 0x910 */
uint32 errlogid; /* 0x914 */
uint32 errloguser; /* 0x918 */
uint32 errlogflags; /* 0x91c */
uint32 PAD[56];
uint32 intstatus; /* 0xa00 */
uint32 PAD[255];
uint32 config; /* 0xe00 */
uint32 PAD[63];
uint32 itcr; /* 0xf00 */
uint32 PAD[3];
uint32 itipooba; /* 0xf10 */
uint32 itipoobb; /* 0xf14 */
uint32 itipoobc; /* 0xf18 */
uint32 itipoobd; /* 0xf1c */
uint32 PAD[4];
uint32 itipoobaout; /* 0xf30 */
uint32 itipoobbout; /* 0xf34 */
uint32 itipoobcout; /* 0xf38 */
uint32 itipoobdout; /* 0xf3c */
uint32 PAD[4];
uint32 itopooba; /* 0xf50 */
uint32 itopoobb; /* 0xf54 */
uint32 itopoobc; /* 0xf58 */
uint32 itopoobd; /* 0xf5c */
uint32 PAD[4];
uint32 itopoobain; /* 0xf70 */
uint32 itopoobbin; /* 0xf74 */
uint32 itopoobcin; /* 0xf78 */
uint32 itopoobdin; /* 0xf7c */
uint32 PAD[4];
uint32 itopreset; /* 0xf90 */
uint32 PAD[15];
uint32 peripherialid4; /* 0xfd0 */
uint32 peripherialid5; /* 0xfd4 */
uint32 peripherialid6; /* 0xfd8 */
uint32 peripherialid7; /* 0xfdc */
uint32 peripherialid0; /* 0xfe0 */
uint32 peripherialid1; /* 0xfe4 */
uint32 peripherialid2; /* 0xfe8 */
uint32 peripherialid3; /* 0xfec */
uint32 componentid0; /* 0xff0 */
uint32 componentid1; /* 0xff4 */
uint32 componentid2; /* 0xff8 */
uint32 componentid3; /* 0xffc */
} aidmp_t;
#endif /* !_LANGUAGE_ASSEMBLY && !__ASSEMBLY__ */
/* Out-of-band Router registers */
#define OOB_BUSCONFIG 0x020
#define OOB_STATUSA 0x100
#define OOB_STATUSB 0x104
#define OOB_STATUSC 0x108
#define OOB_STATUSD 0x10c
#define OOB_ENABLEA0 0x200
#define OOB_ENABLEA1 0x204
#define OOB_ENABLEA2 0x208
#define OOB_ENABLEA3 0x20c
#define OOB_ENABLEB0 0x280
#define OOB_ENABLEB1 0x284
#define OOB_ENABLEB2 0x288
#define OOB_ENABLEB3 0x28c
#define OOB_ENABLEC0 0x300
#define OOB_ENABLEC1 0x304
#define OOB_ENABLEC2 0x308
#define OOB_ENABLEC3 0x30c
#define OOB_ENABLED0 0x380
#define OOB_ENABLED1 0x384
#define OOB_ENABLED2 0x388
#define OOB_ENABLED3 0x38c
#define OOB_ITCR 0xf00
#define OOB_ITIPOOBA 0xf10
#define OOB_ITIPOOBB 0xf14
#define OOB_ITIPOOBC 0xf18
#define OOB_ITIPOOBD 0xf1c
#define OOB_ITOPOOBA 0xf30
#define OOB_ITOPOOBB 0xf34
#define OOB_ITOPOOBC 0xf38
#define OOB_ITOPOOBD 0xf3c
/* DMP wrapper registers */
#define AI_OOBSELINA30 0x000
#define AI_OOBSELINA74 0x004
#define AI_OOBSELINB30 0x020
#define AI_OOBSELINB74 0x024
#define AI_OOBSELINC30 0x040
#define AI_OOBSELINC74 0x044
#define AI_OOBSELIND30 0x060
#define AI_OOBSELIND74 0x064
#define AI_OOBSELOUTA30 0x100
#define AI_OOBSELOUTA74 0x104
#define AI_OOBSELOUTB30 0x120
#define AI_OOBSELOUTB74 0x124
#define AI_OOBSELOUTC30 0x140
#define AI_OOBSELOUTC74 0x144
#define AI_OOBSELOUTD30 0x160
#define AI_OOBSELOUTD74 0x164
#define AI_OOBSYNCA 0x200
#define AI_OOBSELOUTAEN 0x204
#define AI_OOBSYNCB 0x220
#define AI_OOBSELOUTBEN 0x224
#define AI_OOBSYNCC 0x240
#define AI_OOBSELOUTCEN 0x244
#define AI_OOBSYNCD 0x260
#define AI_OOBSELOUTDEN 0x264
#define AI_OOBAEXTWIDTH 0x300
#define AI_OOBAINWIDTH 0x304
#define AI_OOBAOUTWIDTH 0x308
#define AI_OOBBEXTWIDTH 0x320
#define AI_OOBBINWIDTH 0x324
#define AI_OOBBOUTWIDTH 0x328
#define AI_OOBCEXTWIDTH 0x340
#define AI_OOBCINWIDTH 0x344
#define AI_OOBCOUTWIDTH 0x348
#define AI_OOBDEXTWIDTH 0x360
#define AI_OOBDINWIDTH 0x364
#define AI_OOBDOUTWIDTH 0x368
#define AI_IOCTRLSET 0x400
#define AI_IOCTRLCLEAR 0x404
#define AI_IOCTRL 0x408
#define AI_IOSTATUS 0x500
#define AI_RESETCTRL 0x800
#define AI_RESETSTATUS 0x804
#define AI_IOCTRLWIDTH 0x700
#define AI_IOSTATUSWIDTH 0x704
#define AI_RESETREADID 0x808
#define AI_RESETWRITEID 0x80c
#define AI_ERRLOGCTRL 0x900
#define AI_ERRLOGDONE 0x904
#define AI_ERRLOGSTATUS 0x908
#define AI_ERRLOGADDRLO 0x90c
#define AI_ERRLOGADDRHI 0x910
#define AI_ERRLOGID 0x914
#define AI_ERRLOGUSER 0x918
#define AI_ERRLOGFLAGS 0x91c
#define AI_INTSTATUS 0xa00
#define AI_CONFIG 0xe00
#define AI_ITCR 0xf00
#define AI_ITIPOOBA 0xf10
#define AI_ITIPOOBB 0xf14
#define AI_ITIPOOBC 0xf18
#define AI_ITIPOOBD 0xf1c
#define AI_ITIPOOBAOUT 0xf30
#define AI_ITIPOOBBOUT 0xf34
#define AI_ITIPOOBCOUT 0xf38
#define AI_ITIPOOBDOUT 0xf3c
#define AI_ITOPOOBA 0xf50
#define AI_ITOPOOBB 0xf54
#define AI_ITOPOOBC 0xf58
#define AI_ITOPOOBD 0xf5c
#define AI_ITOPOOBAIN 0xf70
#define AI_ITOPOOBBIN 0xf74
#define AI_ITOPOOBCIN 0xf78
#define AI_ITOPOOBDIN 0xf7c
#define AI_ITOPRESET 0xf90
#define AI_PERIPHERIALID4 0xfd0
#define AI_PERIPHERIALID5 0xfd4
#define AI_PERIPHERIALID6 0xfd8
#define AI_PERIPHERIALID7 0xfdc
#define AI_PERIPHERIALID0 0xfe0
#define AI_PERIPHERIALID1 0xfe4
#define AI_PERIPHERIALID2 0xfe8
#define AI_PERIPHERIALID3 0xfec
#define AI_COMPONENTID0 0xff0
#define AI_COMPONENTID1 0xff4
#define AI_COMPONENTID2 0xff8
#define AI_COMPONENTID3 0xffc
/* resetctrl */
#define AIRC_RESET 1
/* errlogctrl */
#define AIELC_TO_EXP_MASK 0x0000001f0 /* backplane timeout exponent */
#define AIELC_TO_EXP_SHIFT 4
#define AIELC_TO_ENAB_SHIFT 9 /* backplane timeout enable */
/* errlogdone */
#define AIELD_ERRDONE_MASK 0x3
/* errlogstatus */
#define AIELS_SLAVE_ERR 0x1
#define AIELS_TIMEOUT 0x2
#define AIELS_DECODE 0x3
#define AIELS_TIMEOUT_MASK 0x3
/* errorlog status bit map, for SW use */
#define AXI_WRAP_STS_NONE (0)
#define AXI_WRAP_STS_TIMEOUT (1<<0)
#define AXI_WRAP_STS_SLAVE_ERR (1<<1)
#define AXI_WRAP_STS_DECODE_ERR (1<<2)
#define AXI_WRAP_STS_PCI_RD_ERR (1<<3)
#define AXI_WRAP_STS_WRAP_RD_ERR (1<<4)
#define AXI_WRAP_STS_SET_CORE_FAIL (1<<5)
/* errlogFrags */
#define AXI_ERRLOG_FLAGS_WRITE_REQ (1<<24)
/* config */
#define AICFG_OOB 0x00000020
#define AICFG_IOS 0x00000010
#define AICFG_IOC 0x00000008
#define AICFG_TO 0x00000004
#define AICFG_ERRL 0x00000002
#define AICFG_RST 0x00000001
/* bit defines for AI_OOBSELOUTB74 reg */
#define OOB_SEL_OUTEN_B_5 15
#define OOB_SEL_OUTEN_B_6 23
/* AI_OOBSEL for A/B/C/D, 0-7 */
#define AI_OOBSEL_MASK 0x1F
#define AI_OOBSEL_0_SHIFT 0
#define AI_OOBSEL_1_SHIFT 8
#define AI_OOBSEL_2_SHIFT 16
#define AI_OOBSEL_3_SHIFT 24
#define AI_OOBSEL_4_SHIFT 0
#define AI_OOBSEL_5_SHIFT 8
#define AI_OOBSEL_6_SHIFT 16
#define AI_OOBSEL_7_SHIFT 24
#define AI_IOCTRL_ENABLE_D11_PME (1 << 14)
/* bit Specific for AI_OOBSELOUTB30 */
#define OOB_B_ALP_REQUEST 0
#define OOB_B_HT_REQUEST 1
#define OOB_B_ILP_REQUEST 2
#define OOB_B_ALP_AVAIL_REQUEST 3
#define OOB_B_HT_AVAIL_REQUEST 4
/* mask for interrupts from each core to wrapper */
#define AI_OOBSELINA74_CORE_MASK 0x80808080
#define AI_OOBSELINA30_CORE_MASK 0x80808080
/* axi id mask in the error log id */
#define AI_ERRLOGID_AXI_ID_MASK 0x07
#endif /* _AIDMP_H */

View File

@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* BCM common config options
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcm_cfg.h 672943 2016-11-30 08:54:06Z $
*/
#ifndef _bcm_cfg_h_
#define _bcm_cfg_h_
#endif /* _bcm_cfg_h_ */

View File

@@ -0,0 +1,351 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Memory pools library, Public interface
*
* API Overview
*
* This package provides a memory allocation subsystem based on pools of
* homogenous objects.
*
* Instrumentation is available for reporting memory utilization both
* on a per-data-structure basis and system wide.
*
* There are two main types defined in this API.
*
* pool manager: A singleton object that acts as a factory for
* pool allocators. It also is used for global
* instrumentation, such as reporting all blocks
* in use across all data structures. The pool manager
* creates and provides individual memory pools
* upon request to application code.
*
* memory pool: An object for allocating homogenous memory blocks.
*
* Global identifiers in this module use the following prefixes:
* bcm_mpm_* Memory pool manager
* bcm_mp_* Memory pool
*
* There are two main types of memory pools:
*
* prealloc: The contiguous memory block of objects can either be supplied
* by the client or malloc'ed by the memory manager. The objects are
* allocated out of a block of memory and freed back to the block.
*
* heap: The memory pool allocator uses the heap (malloc/free) for memory.
* In this case, the pool allocator is just providing statistics
* and instrumentation on top of the heap, without modifying the heap
* allocation implementation.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcm_mpool_pub.h 535090 2015-02-17 04:49:01Z $
*/
#ifndef _BCM_MPOOL_PUB_H
#define _BCM_MPOOL_PUB_H 1
#include <typedefs.h> /* needed for uint16 */
/*
**************************************************************************
*
* Type definitions, handles
*
**************************************************************************
*/
/* Forward declaration of OSL handle. */
struct osl_info;
/* Forward declaration of string buffer. */
struct bcmstrbuf;
/*
* Opaque type definition for the pool manager handle. This object is used for global
* memory pool operations such as obtaining a new pool, deleting a pool, iterating and
* instrumentation/debugging.
*/
struct bcm_mpm_mgr;
typedef struct bcm_mpm_mgr *bcm_mpm_mgr_h;
/*
* Opaque type definition for an instance of a pool. This handle is used for allocating
* and freeing memory through the pool, as well as management/instrumentation on this
* specific pool.
*/
struct bcm_mp_pool;
typedef struct bcm_mp_pool *bcm_mp_pool_h;
/*
* To make instrumentation more readable, every memory
* pool must have a readable name. Pool names are up to
* 8 bytes including '\0' termination. (7 printable characters.)
*/
#define BCM_MP_NAMELEN 8
/*
* Type definition for pool statistics.
*/
typedef struct bcm_mp_stats {
char name[BCM_MP_NAMELEN]; /* Name of this pool. */
unsigned int objsz; /* Object size allocated in this pool */
uint16 nobj; /* Total number of objects in this pool */
uint16 num_alloc; /* Number of objects currently allocated */
uint16 high_water; /* Max number of allocated objects. */
uint16 failed_alloc; /* Failed allocations. */
} bcm_mp_stats_t;
/*
**************************************************************************
*
* API Routines on the pool manager.
*
**************************************************************************
*/
/*
* bcm_mpm_init() - initialize the whole memory pool system.
*
* Parameters:
* osh: INPUT Operating system handle. Needed for heap memory allocation.
* max_pools: INPUT Maximum number of mempools supported.
* mgr: OUTPUT The handle is written with the new pools manager object/handle.
*
* Returns:
* BCME_OK Object initialized successfully. May be used.
* BCME_NOMEM Initialization failed due to no memory. Object must not be used.
*/
int bcm_mpm_init(struct osl_info *osh, int max_pools, bcm_mpm_mgr_h *mgrp);
/*
* bcm_mpm_deinit() - de-initialize the whole memory pool system.
*
* Parameters:
* mgr: INPUT Pointer to pool manager handle.
*
* Returns:
* BCME_OK Memory pool manager successfully de-initialized.
* other Indicated error occured during de-initialization.
*/
int bcm_mpm_deinit(bcm_mpm_mgr_h *mgrp);
/*
* bcm_mpm_create_prealloc_pool() - Create a new pool for fixed size objects. The
* pool uses a contiguous block of pre-alloced
* memory. The memory block may either be provided
* by the client or dynamically allocated by the
* pool manager.
*
* Parameters:
* mgr: INPUT The handle to the pool manager
* obj_sz: INPUT Size of objects that will be allocated by the new pool
* Must be >= sizeof(void *).
* nobj: INPUT Maximum number of concurrently existing objects to support
* memstart INPUT Pointer to the memory to use, or NULL to malloc()
* memsize INPUT Number of bytes referenced from memstart (for error checking).
* Must be 0 if 'memstart' is NULL.
* poolname INPUT For instrumentation, the name of the pool
* newp: OUTPUT The handle for the new pool, if creation is successful
*
* Returns:
* BCME_OK Pool created ok.
* other Pool not created due to indicated error. newpoolp set to NULL.
*
*
*/
int bcm_mpm_create_prealloc_pool(bcm_mpm_mgr_h mgr,
unsigned int obj_sz,
int nobj,
void *memstart,
unsigned int memsize,
const char poolname[BCM_MP_NAMELEN],
bcm_mp_pool_h *newp);
/*
* bcm_mpm_delete_prealloc_pool() - Delete a memory pool. This should only be called after
* all memory objects have been freed back to the pool.
*
* Parameters:
* mgr: INPUT The handle to the pools manager
* pool: INPUT The handle of the pool to delete
*
* Returns:
* BCME_OK Pool deleted ok.
* other Pool not deleted due to indicated error.
*
*/
int bcm_mpm_delete_prealloc_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp);
/*
* bcm_mpm_create_heap_pool() - Create a new pool for fixed size objects. The memory
* pool allocator uses the heap (malloc/free) for memory.
* In this case, the pool allocator is just providing
* statistics and instrumentation on top of the heap,
* without modifying the heap allocation implementation.
*
* Parameters:
* mgr: INPUT The handle to the pool manager
* obj_sz: INPUT Size of objects that will be allocated by the new pool
* poolname INPUT For instrumentation, the name of the pool
* newp: OUTPUT The handle for the new pool, if creation is successful
*
* Returns:
* BCME_OK Pool created ok.
* other Pool not created due to indicated error. newpoolp set to NULL.
*
*
*/
int bcm_mpm_create_heap_pool(bcm_mpm_mgr_h mgr, unsigned int obj_sz,
const char poolname[BCM_MP_NAMELEN],
bcm_mp_pool_h *newp);
/*
* bcm_mpm_delete_heap_pool() - Delete a memory pool. This should only be called after
* all memory objects have been freed back to the pool.
*
* Parameters:
* mgr: INPUT The handle to the pools manager
* pool: INPUT The handle of the pool to delete
*
* Returns:
* BCME_OK Pool deleted ok.
* other Pool not deleted due to indicated error.
*
*/
int bcm_mpm_delete_heap_pool(bcm_mpm_mgr_h mgr, bcm_mp_pool_h *poolp);
/*
* bcm_mpm_stats() - Return stats for all pools
*
* Parameters:
* mgr: INPUT The handle to the pools manager
* stats: OUTPUT Array of pool statistics.
* nentries: MOD Max elements in 'stats' array on INPUT. Actual number
* of array elements copied to 'stats' on OUTPUT.
*
* Returns:
* BCME_OK Ok
* other Error getting stats.
*
*/
int bcm_mpm_stats(bcm_mpm_mgr_h mgr, bcm_mp_stats_t *stats, int *nentries);
/*
* bcm_mpm_dump() - Display statistics on all pools
*
* Parameters:
* mgr: INPUT The handle to the pools manager
* b: OUTPUT Output buffer.
*
* Returns:
* BCME_OK Ok
* other Error during dump.
*
*/
int bcm_mpm_dump(bcm_mpm_mgr_h mgr, struct bcmstrbuf *b);
/*
* bcm_mpm_get_obj_size() - The size of memory objects may need to be padded to
* compensate for alignment requirements of the objects.
* This function provides the padded object size. If clients
* pre-allocate a memory slab for a memory pool, the
* padded object size should be used by the client to allocate
* the memory slab (in order to provide sufficent space for
* the maximum number of objects).
*
* Parameters:
* mgr: INPUT The handle to the pools manager.
* obj_sz: INPUT Input object size.
* padded_obj_sz: OUTPUT Padded object size.
*
* Returns:
* BCME_OK Ok
* BCME_BADARG Bad arguments.
*
*/
int bcm_mpm_get_obj_size(bcm_mpm_mgr_h mgr, unsigned int obj_sz, unsigned int *padded_obj_sz);
/*
***************************************************************************
*
* API Routines on a specific pool.
*
***************************************************************************
*/
/*
* bcm_mp_alloc() - Allocate a memory pool object.
*
* Parameters:
* pool: INPUT The handle to the pool.
*
* Returns:
* A pointer to the new object. NULL on error.
*
*/
void* bcm_mp_alloc(bcm_mp_pool_h pool);
/*
* bcm_mp_free() - Free a memory pool object.
*
* Parameters:
* pool: INPUT The handle to the pool.
* objp: INPUT A pointer to the object to free.
*
* Returns:
* BCME_OK Ok
* other Error during free.
*
*/
int bcm_mp_free(bcm_mp_pool_h pool, void *objp);
/*
* bcm_mp_stats() - Return stats for this pool
*
* Parameters:
* pool: INPUT The handle to the pool
* stats: OUTPUT Pool statistics
*
* Returns:
* BCME_OK Ok
* other Error getting statistics.
*
*/
void bcm_mp_stats(bcm_mp_pool_h pool, bcm_mp_stats_t *stats);
/*
* bcm_mp_dump() - Dump a pool
*
* Parameters:
* pool: INPUT The handle to the pool
* b OUTPUT Output buffer
*
* Returns:
* BCME_OK Ok
* other Error during dump.
*
*/
int bcm_mp_dump(bcm_mp_pool_h pool, struct bcmstrbuf *b);
#endif /* _BCM_MPOOL_PUB_H */

View File

@@ -0,0 +1,614 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* bcm_ring.h : Ring context abstraction
* The ring context tracks the WRITE and READ indices where elements may be
* produced and consumed respectively. All elements in the ring need to be
* fixed size.
*
* NOTE: A ring of size N, may only hold N-1 elements.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcm_ring.h 700321 2017-05-18 16:09:07Z $
*/
#ifndef __bcm_ring_included__
#define __bcm_ring_included__
/*
* API Notes:
*
* Ring manipulation API allows for:
* Pending operations: Often before some work can be completed, it may be
* desired that several resources are available, e.g. space for production in
* a ring. Approaches such as, #1) reserve resources one by one and return them
* if another required resource is not available, or #2) employ a two pass
* algorithm of first testing whether all resources are available, have a
* an impact on performance critical code. The approach taken here is more akin
* to approach #2, where a test for resource availability essentially also
* provides the index for production in an un-committed state.
* The same approach is taken for the consumer side.
*
* - Pending production: Fetch the next index where a ring element may be
* produced. The caller may not commit the WRITE of the element.
* - Pending consumption: Fetch the next index where a ring element may be
* consumed. The caller may not commut the READ of the element.
*
* Producer side API:
* - bcm_ring_is_full : Test whether ring is full
* - bcm_ring_prod : Fetch index where an element may be produced (commit)
* - bcm_ring_prod_pend: Fetch index where an element may be produced (pending)
* - bcm_ring_prod_done: Commit a previous pending produce fetch
* - bcm_ring_prod_avail: Fetch total number free slots eligible for production
*
* Consumer side API:
* - bcm_ring_is_empty : Test whether ring is empty
* - bcm_ring_cons : Fetch index where an element may be consumed (commit)
* - bcm_ring_cons_pend: Fetch index where an element may be consumed (pending)
* - bcm_ring_cons_done: Commit a previous pending consume fetch
* - bcm_ring_cons_avail: Fetch total number elements eligible for consumption
*
* - bcm_ring_sync_read: Sync read offset in peer ring, from local ring
* - bcm_ring_sync_write: Sync write offset in peer ring, from local ring
*
* +----------------------------------------------------------------------------
*
* Design Notes:
* Following items are not tracked in a ring context (design decision)
* - width of a ring element.
* - depth of the ring.
* - base of the buffer, where the elements are stored.
* - count of number of free slots in the ring
*
* Implementation Notes:
* - When BCM_RING_DEBUG is enabled, need explicit bcm_ring_init().
* - BCM_RING_EMPTY and BCM_RING_FULL are (-1)
*
* +----------------------------------------------------------------------------
*
* Usage Notes:
* An application may incarnate a ring of some fixed sized elements, by defining
* - a ring data buffer to store the ring elements.
* - depth of the ring (max number of elements managed by ring context).
* Preferrably, depth may be represented as a constant.
* - width of a ring element: to be used in pointer arithmetic with the ring's
* data buffer base and an index to fetch the ring element.
*
* Use bcm_workq_t to instantiate a pair of workq constructs, one for the
* producer and the other for the consumer, both pointing to the same circular
* buffer. The producer may operate on it's own local workq and flush the write
* index to the consumer. Likewise the consumer may use its local workq and
* flush the read index to the producer. This way we do not repeatedly access
* the peer's context. The two peers may reside on different CPU cores with a
* private L1 data cache.
* +----------------------------------------------------------------------------
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: bcm_ring.h 700321 2017-05-18 16:09:07Z $
*
* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
* vim: set ts=4 noet sw=4 tw=80:
*
* +----------------------------------------------------------------------------
*/
#ifdef ____cacheline_aligned
#define __ring_aligned ____cacheline_aligned
#else
#define __ring_aligned
#endif // endif
/* Conditional compile for debug */
/* #define BCM_RING_DEBUG */
#define BCM_RING_EMPTY (-1)
#define BCM_RING_FULL (-1)
#define BCM_RING_NULL ((bcm_ring_t *)NULL)
#if defined(BCM_RING_DEBUG)
#define RING_ASSERT(exp) ASSERT(exp)
#define BCM_RING_IS_VALID(ring) (((ring) != BCM_RING_NULL) && \
((ring)->self == (ring)))
#else /* ! BCM_RING_DEBUG */
#define RING_ASSERT(exp) do {} while (0)
#define BCM_RING_IS_VALID(ring) ((ring) != BCM_RING_NULL)
#endif /* ! BCM_RING_DEBUG */
#define BCM_RING_SIZE_IS_VALID(ring_size) ((ring_size) > 0)
/*
* +----------------------------------------------------------------------------
* Ring Context
* +----------------------------------------------------------------------------
*/
typedef struct bcm_ring { /* Ring context */
#if defined(BCM_RING_DEBUG)
struct bcm_ring *self; /* ptr to self for IS VALID test */
#endif /* BCM_RING_DEBUG */
int write __ring_aligned; /* WRITE index in a circular ring */
int read __ring_aligned; /* READ index in a circular ring */
} bcm_ring_t;
static INLINE void bcm_ring_init(bcm_ring_t *ring);
static INLINE void bcm_ring_copy(bcm_ring_t *to, bcm_ring_t *from);
static INLINE bool bcm_ring_is_empty(bcm_ring_t *ring);
static INLINE int __bcm_ring_next_write(bcm_ring_t *ring, const int ring_size);
static INLINE bool __bcm_ring_full(bcm_ring_t *ring, int next_write);
static INLINE bool bcm_ring_is_full(bcm_ring_t *ring, const int ring_size);
static INLINE void bcm_ring_prod_done(bcm_ring_t *ring, int write);
static INLINE int bcm_ring_prod_pend(bcm_ring_t *ring, int *pend_write,
const int ring_size);
static INLINE int bcm_ring_prod(bcm_ring_t *ring, const int ring_size);
static INLINE void bcm_ring_cons_done(bcm_ring_t *ring, int read);
static INLINE int bcm_ring_cons_pend(bcm_ring_t *ring, int *pend_read,
const int ring_size);
static INLINE int bcm_ring_cons(bcm_ring_t *ring, const int ring_size);
static INLINE void bcm_ring_sync_read(bcm_ring_t *peer, const bcm_ring_t *self);
static INLINE void bcm_ring_sync_write(bcm_ring_t *peer, const bcm_ring_t *self);
static INLINE int bcm_ring_prod_avail(const bcm_ring_t *ring,
const int ring_size);
static INLINE int bcm_ring_cons_avail(const bcm_ring_t *ring,
const int ring_size);
static INLINE void bcm_ring_cons_all(bcm_ring_t *ring);
/**
* bcm_ring_init - initialize a ring context.
* @ring: pointer to a ring context
*/
static INLINE void
bcm_ring_init(bcm_ring_t *ring)
{
ASSERT(ring != (bcm_ring_t *)NULL);
#if defined(BCM_RING_DEBUG)
ring->self = ring;
#endif /* BCM_RING_DEBUG */
ring->write = 0;
ring->read = 0;
}
/**
* bcm_ring_copy - copy construct a ring
* @to: pointer to the new ring context
* @from: pointer to orig ring context
*/
static INLINE void
bcm_ring_copy(bcm_ring_t *to, bcm_ring_t *from)
{
bcm_ring_init(to);
to->write = from->write;
to->read = from->read;
}
/**
* bcm_ring_is_empty - "Boolean" test whether ring is empty.
* @ring: pointer to a ring context
*
* PS. does not return BCM_RING_EMPTY value.
*/
static INLINE bool
bcm_ring_is_empty(bcm_ring_t *ring)
{
RING_ASSERT(BCM_RING_IS_VALID(ring));
return (ring->read == ring->write);
}
/**
* __bcm_ring_next_write - determine the index where the next write may occur
* (with wrap-around).
* @ring: pointer to a ring context
* @ring_size: size of the ring
*
* PRIVATE INTERNAL USE ONLY.
*/
static INLINE int
__bcm_ring_next_write(bcm_ring_t *ring, const int ring_size)
{
RING_ASSERT(BCM_RING_IS_VALID(ring) && BCM_RING_SIZE_IS_VALID(ring_size));
return ((ring->write + 1) % ring_size);
}
/**
* __bcm_ring_full - support function for ring full test.
* @ring: pointer to a ring context
* @next_write: next location in ring where an element is to be produced
*
* PRIVATE INTERNAL USE ONLY.
*/
static INLINE bool
__bcm_ring_full(bcm_ring_t *ring, int next_write)
{
return (next_write == ring->read);
}
/**
* bcm_ring_is_full - "Boolean" test whether a ring is full.
* @ring: pointer to a ring context
* @ring_size: size of the ring
*
* PS. does not return BCM_RING_FULL value.
*/
static INLINE bool
bcm_ring_is_full(bcm_ring_t *ring, const int ring_size)
{
int next_write;
RING_ASSERT(BCM_RING_IS_VALID(ring) && BCM_RING_SIZE_IS_VALID(ring_size));
next_write = __bcm_ring_next_write(ring, ring_size);
return __bcm_ring_full(ring, next_write);
}
/**
* bcm_ring_prod_done - commit a previously pending index where production
* was requested.
* @ring: pointer to a ring context
* @write: index into ring upto where production was done.
* +----------------------------------------------------------------------------
*/
static INLINE void
bcm_ring_prod_done(bcm_ring_t *ring, int write)
{
RING_ASSERT(BCM_RING_IS_VALID(ring));
ring->write = write;
}
/**
* bcm_ring_prod_pend - Fetch in "pend" mode, the index where an element may be
* produced.
* @ring: pointer to a ring context
* @pend_write: next index, after the returned index
* @ring_size: size of the ring
*/
static INLINE int
bcm_ring_prod_pend(bcm_ring_t *ring, int *pend_write, const int ring_size)
{
int rtn;
RING_ASSERT(BCM_RING_IS_VALID(ring) && BCM_RING_SIZE_IS_VALID(ring_size));
*pend_write = __bcm_ring_next_write(ring, ring_size);
if (__bcm_ring_full(ring, *pend_write)) {
*pend_write = BCM_RING_FULL;
rtn = BCM_RING_FULL;
} else {
/* production is not committed, caller needs to explicitly commit */
rtn = ring->write;
}
return rtn;
}
/**
* bcm_ring_prod - Fetch and "commit" the next index where a ring element may
* be produced.
* @ring: pointer to a ring context
* @ring_size: size of the ring
*/
static INLINE int
bcm_ring_prod(bcm_ring_t *ring, const int ring_size)
{
int next_write, prod_write;
RING_ASSERT(BCM_RING_IS_VALID(ring) && BCM_RING_SIZE_IS_VALID(ring_size));
next_write = __bcm_ring_next_write(ring, ring_size);
if (__bcm_ring_full(ring, next_write)) {
prod_write = BCM_RING_FULL;
} else {
prod_write = ring->write;
bcm_ring_prod_done(ring, next_write); /* "commit" production */
}
return prod_write;
}
/**
* bcm_ring_cons_done - commit a previously pending read
* @ring: pointer to a ring context
* @read: index upto which elements have been consumed.
*/
static INLINE void
bcm_ring_cons_done(bcm_ring_t *ring, int read)
{
RING_ASSERT(BCM_RING_IS_VALID(ring));
ring->read = read;
}
/**
* bcm_ring_cons_pend - fetch in "pend" mode, the next index where a ring
* element may be consumed.
* @ring: pointer to a ring context
* @pend_read: index into ring upto which elements may be consumed.
* @ring_size: size of the ring
*/
static INLINE int
bcm_ring_cons_pend(bcm_ring_t *ring, int *pend_read, const int ring_size)
{
int rtn;
RING_ASSERT(BCM_RING_IS_VALID(ring) && BCM_RING_SIZE_IS_VALID(ring_size));
if (bcm_ring_is_empty(ring)) {
*pend_read = BCM_RING_EMPTY;
rtn = BCM_RING_EMPTY;
} else {
*pend_read = (ring->read + 1) % ring_size;
/* production is not committed, caller needs to explicitly commit */
rtn = ring->read;
}
return rtn;
}
/**
* bcm_ring_cons - fetch and "commit" the next index where a ring element may
* be consumed.
* @ring: pointer to a ring context
* @ring_size: size of the ring
*/
static INLINE int
bcm_ring_cons(bcm_ring_t *ring, const int ring_size)
{
int cons_read;
RING_ASSERT(BCM_RING_IS_VALID(ring) && BCM_RING_SIZE_IS_VALID(ring_size));
if (bcm_ring_is_empty(ring)) {
cons_read = BCM_RING_EMPTY;
} else {
cons_read = ring->read;
ring->read = (ring->read + 1) % ring_size; /* read is committed */
}
return cons_read;
}
/**
* bcm_ring_sync_read - on consumption, update peer's read index.
* @peer: pointer to peer's producer ring context
* @self: pointer to consumer's ring context
*/
static INLINE void
bcm_ring_sync_read(bcm_ring_t *peer, const bcm_ring_t *self)
{
RING_ASSERT(BCM_RING_IS_VALID(peer));
RING_ASSERT(BCM_RING_IS_VALID(self));
peer->read = self->read; /* flush read update to peer producer */
}
/**
* bcm_ring_sync_write - on consumption, update peer's write index.
* @peer: pointer to peer's consumer ring context
* @self: pointer to producer's ring context
*/
static INLINE void
bcm_ring_sync_write(bcm_ring_t *peer, const bcm_ring_t *self)
{
RING_ASSERT(BCM_RING_IS_VALID(peer));
RING_ASSERT(BCM_RING_IS_VALID(self));
peer->write = self->write; /* flush write update to peer consumer */
}
/**
* bcm_ring_prod_avail - fetch total number of available empty slots in the
* ring for production.
* @ring: pointer to a ring context
* @ring_size: size of the ring
*/
static INLINE int
bcm_ring_prod_avail(const bcm_ring_t *ring, const int ring_size)
{
int prod_avail;
RING_ASSERT(BCM_RING_IS_VALID(ring) && BCM_RING_SIZE_IS_VALID(ring_size));
if (ring->write >= ring->read) {
prod_avail = (ring_size - (ring->write - ring->read) - 1);
} else {
prod_avail = (ring->read - (ring->write + 1));
}
ASSERT(prod_avail < ring_size);
return prod_avail;
}
/**
* bcm_ring_cons_avail - fetch total number of available elements for consumption.
* @ring: pointer to a ring context
* @ring_size: size of the ring
*/
static INLINE int
bcm_ring_cons_avail(const bcm_ring_t *ring, const int ring_size)
{
int cons_avail;
RING_ASSERT(BCM_RING_IS_VALID(ring) && BCM_RING_SIZE_IS_VALID(ring_size));
if (ring->read == ring->write) {
cons_avail = 0;
} else if (ring->read > ring->write) {
cons_avail = ((ring_size - ring->read) + ring->write);
} else {
cons_avail = ring->write - ring->read;
}
ASSERT(cons_avail < ring_size);
return cons_avail;
}
/**
* bcm_ring_cons_all - set ring in state where all elements are consumed.
* @ring: pointer to a ring context
*/
static INLINE void
bcm_ring_cons_all(bcm_ring_t *ring)
{
ring->read = ring->write;
}
/**
* Work Queue
* A work Queue is composed of a ring of work items, of a specified depth.
* It HAS-A bcm_ring object, comprising of a RD and WR offset, to implement a
* producer/consumer circular ring.
*/
struct bcm_workq {
bcm_ring_t ring; /* Ring context abstraction */
struct bcm_workq *peer; /* Peer workq context */
void *buffer; /* Buffer storage for work items in workQ */
int ring_size; /* Depth of workQ */
} __ring_aligned;
typedef struct bcm_workq bcm_workq_t;
/* #define BCM_WORKQ_DEBUG */
#if defined(BCM_WORKQ_DEBUG)
#define WORKQ_ASSERT(exp) ASSERT(exp)
#else /* ! BCM_WORKQ_DEBUG */
#define WORKQ_ASSERT(exp) do {} while (0)
#endif /* ! BCM_WORKQ_DEBUG */
#define WORKQ_AUDIT(workq) \
WORKQ_ASSERT((workq) != BCM_WORKQ_NULL); \
WORKQ_ASSERT(WORKQ_PEER(workq) != BCM_WORKQ_NULL); \
WORKQ_ASSERT((workq)->buffer == WORKQ_PEER(workq)->buffer); \
WORKQ_ASSERT((workq)->ring_size == WORKQ_PEER(workq)->ring_size);
#define BCM_WORKQ_NULL ((bcm_workq_t *)NULL)
#define WORKQ_PEER(workq) ((workq)->peer)
#define WORKQ_RING(workq) (&((workq)->ring))
#define WORKQ_PEER_RING(workq) (&((workq)->peer->ring))
#define WORKQ_ELEMENT(__elem_type, __workq, __index) ({ \
WORKQ_ASSERT((__workq) != BCM_WORKQ_NULL); \
WORKQ_ASSERT((__index) < ((__workq)->ring_size)); \
((__elem_type *)((__workq)->buffer)) + (__index); \
})
static INLINE void bcm_workq_init(bcm_workq_t *workq, bcm_workq_t *workq_peer,
void *buffer, int ring_size);
static INLINE bool bcm_workq_is_empty(bcm_workq_t *workq_prod);
static INLINE void bcm_workq_prod_sync(bcm_workq_t *workq_prod);
static INLINE void bcm_workq_cons_sync(bcm_workq_t *workq_cons);
static INLINE void bcm_workq_prod_refresh(bcm_workq_t *workq_prod);
static INLINE void bcm_workq_cons_refresh(bcm_workq_t *workq_cons);
/**
* bcm_workq_init - initialize a workq
* @workq: pointer to a workq context
* @buffer: pointer to a pre-allocated circular buffer to serve as a ring
* @ring_size: size of the ring in terms of max number of elements.
*/
static INLINE void
bcm_workq_init(bcm_workq_t *workq, bcm_workq_t *workq_peer,
void *buffer, int ring_size)
{
ASSERT(workq != BCM_WORKQ_NULL);
ASSERT(workq_peer != BCM_WORKQ_NULL);
ASSERT(buffer != NULL);
ASSERT(ring_size > 0);
WORKQ_PEER(workq) = workq_peer;
WORKQ_PEER(workq_peer) = workq;
bcm_ring_init(WORKQ_RING(workq));
bcm_ring_init(WORKQ_RING(workq_peer));
workq->buffer = workq_peer->buffer = buffer;
workq->ring_size = workq_peer->ring_size = ring_size;
}
/**
* bcm_workq_empty - test whether there is work
* @workq_prod: producer's workq
*/
static INLINE bool
bcm_workq_is_empty(bcm_workq_t *workq_prod)
{
return bcm_ring_is_empty(WORKQ_RING(workq_prod));
}
/**
* bcm_workq_prod_sync - Commit the producer write index to peer workq's ring
* @workq_prod: producer's workq whose write index must be synced to peer
*/
static INLINE void
bcm_workq_prod_sync(bcm_workq_t *workq_prod)
{
WORKQ_AUDIT(workq_prod);
/* cons::write <--- prod::write */
bcm_ring_sync_write(WORKQ_PEER_RING(workq_prod), WORKQ_RING(workq_prod));
}
/**
* bcm_workq_cons_sync - Commit the consumer read index to the peer workq's ring
* @workq_cons: consumer's workq whose read index must be synced to peer
*/
static INLINE void
bcm_workq_cons_sync(bcm_workq_t *workq_cons)
{
WORKQ_AUDIT(workq_cons);
/* prod::read <--- cons::read */
bcm_ring_sync_read(WORKQ_PEER_RING(workq_cons), WORKQ_RING(workq_cons));
}
/**
* bcm_workq_prod_refresh - Fetch the updated consumer's read index
* @workq_prod: producer's workq whose read index must be refreshed from peer
*/
static INLINE void
bcm_workq_prod_refresh(bcm_workq_t *workq_prod)
{
WORKQ_AUDIT(workq_prod);
/* prod::read <--- cons::read */
bcm_ring_sync_read(WORKQ_RING(workq_prod), WORKQ_PEER_RING(workq_prod));
}
/**
* bcm_workq_cons_refresh - Fetch the updated producer's write index
* @workq_cons: consumer's workq whose write index must be refreshed from peer
*/
static INLINE void
bcm_workq_cons_refresh(bcm_workq_t *workq_cons)
{
WORKQ_AUDIT(workq_cons);
/* cons::write <--- prod::write */
bcm_ring_sync_write(WORKQ_RING(workq_cons), WORKQ_PEER_RING(workq_cons));
}
#endif /* ! __bcm_ring_h_included__ */

View File

@@ -0,0 +1,91 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Fundamental constants relating to ARP Protocol
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmarp.h 701633 2017-05-25 23:07:17Z $
*/
#ifndef _bcmarp_h_
#define _bcmarp_h_
#ifndef _TYPEDEFS_H_
#include <typedefs.h>
#endif // endif
#include <bcmip.h>
/* This marks the start of a packed structure section. */
#include <packed_section_start.h>
#define ARP_OPC_OFFSET 6 /* option code offset */
#define ARP_SRC_ETH_OFFSET 8 /* src h/w address offset */
#define ARP_SRC_IP_OFFSET 14 /* src IP address offset */
#define ARP_TGT_ETH_OFFSET 18 /* target h/w address offset */
#define ARP_TGT_IP_OFFSET 24 /* target IP address offset */
#define ARP_OPC_REQUEST 1 /* ARP request */
#define ARP_OPC_REPLY 2 /* ARP reply */
#define ARP_DATA_LEN 28 /* ARP data length */
#define HTYPE_ETHERNET 1 /* htype for ethernet */
BWL_PRE_PACKED_STRUCT struct bcmarp {
uint16 htype; /* Header type (1 = ethernet) */
uint16 ptype; /* Protocol type (0x800 = IP) */
uint8 hlen; /* Hardware address length (Eth = 6) */
uint8 plen; /* Protocol address length (IP = 4) */
uint16 oper; /* ARP_OPC_... */
uint8 src_eth[ETHER_ADDR_LEN]; /* Source hardware address */
uint8 src_ip[IPV4_ADDR_LEN]; /* Source protocol address (not aligned) */
uint8 dst_eth[ETHER_ADDR_LEN]; /* Destination hardware address */
uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination protocol address */
} BWL_POST_PACKED_STRUCT;
/* Ethernet header + Arp message */
BWL_PRE_PACKED_STRUCT struct bcmetharp {
struct ether_header eh;
struct bcmarp arp;
} BWL_POST_PACKED_STRUCT;
/* IPv6 Neighbor Advertisement */
#define NEIGHBOR_ADVERTISE_SRC_IPV6_OFFSET 8 /* src IPv6 address offset */
#define NEIGHBOR_ADVERTISE_TYPE_OFFSET 40 /* type offset */
#define NEIGHBOR_ADVERTISE_CHECKSUM_OFFSET 42 /* check sum offset */
#define NEIGHBOR_ADVERTISE_FLAGS_OFFSET 44 /* R,S and O flags offset */
#define NEIGHBOR_ADVERTISE_TGT_IPV6_OFFSET 48 /* target IPv6 address offset */
#define NEIGHBOR_ADVERTISE_OPTION_OFFSET 64 /* options offset */
#define NEIGHBOR_ADVERTISE_TYPE 136
#define NEIGHBOR_SOLICITATION_TYPE 135
#define OPT_TYPE_SRC_LINK_ADDR 1
#define OPT_TYPE_TGT_LINK_ADDR 2
#define NEIGHBOR_ADVERTISE_DATA_LEN 72 /* neighbor advertisement data length */
#define NEIGHBOR_ADVERTISE_FLAGS_VALUE 0x60 /* R=0, S=1 and O=1 */
/* This marks the end of a packed structure section. */
#include <packed_section_end.h>
#endif /* !defined(_bcmarp_h_) */

View File

@@ -0,0 +1,80 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Bloom filter support
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmbloom.h 714397 2017-08-04 08:24:38Z $
*/
#ifndef _bcmbloom_h_
#define _bcmbloom_h_
#include <typedefs.h>
#ifdef BCMDRIVER
#include <osl.h>
#else
#include <stddef.h> /* For size_t */
#endif // endif
struct bcm_bloom_filter;
typedef struct bcm_bloom_filter bcm_bloom_filter_t;
typedef void* (*bcm_bloom_alloc_t)(void *ctx, uint size);
typedef void (*bcm_bloom_free_t)(void *ctx, void *buf, uint size);
typedef uint (*bcm_bloom_hash_t)(void* ctx, uint idx, const uint8 *tag, uint len);
/* create/allocate a bloom filter. filter size can be 0 for validate only filters */
int bcm_bloom_create(bcm_bloom_alloc_t alloc_cb,
bcm_bloom_free_t free_cb, void *callback_ctx, uint max_hash,
uint filter_size /* bytes */, bcm_bloom_filter_t **bloom);
/* destroy bloom filter */
int bcm_bloom_destroy(bcm_bloom_filter_t **bloom, bcm_bloom_free_t free_cb);
/* add a hash function to filter, return an index */
int bcm_bloom_add_hash(bcm_bloom_filter_t *filter, bcm_bloom_hash_t hash, uint *idx);
/* remove the hash function at index from filter */
int bcm_bloom_remove_hash(bcm_bloom_filter_t *filter, uint idx);
/* check if given tag is member of the filter. If buf is NULL and/or buf_len is 0
* then use the internal state. BCME_OK if member, BCME_NOTFOUND if not,
* or other error (e.g. BADARG)
*/
bool bcm_bloom_is_member(bcm_bloom_filter_t *filter,
const uint8 *tag, uint tag_len, const uint8 *buf, uint buf_len);
/* add a member to the filter. invalid for validate_only filters */
int bcm_bloom_add_member(bcm_bloom_filter_t *filter, const uint8 *tag, uint tag_len);
/* no support for remove member */
/* get the filter data from state. BCME_BUFTOOSHORT w/ required length in buf_len
* if supplied size is insufficient
*/
int bcm_bloom_get_filter_data(bcm_bloom_filter_t *filter,
uint buf_size, uint8 *buf, uint *buf_len);
#endif /* _bcmbloom_h_ */

View File

@@ -0,0 +1,122 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* CDC network driver ioctl/indication encoding
* Broadcom 802.11abg Networking Device Driver
*
* Definitions subject to change without notice.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmcdc.h 700076 2017-05-17 14:42:22Z $
*/
#ifndef _bcmcdc_h_
#define _bcmcdc_h_
#include <ethernet.h>
typedef struct cdc_ioctl {
uint32 cmd; /* ioctl command value */
uint32 len; /* lower 16: output buflen; upper 16: input buflen (excludes header) */
uint32 flags; /* flag defns given below */
uint32 status; /* status code returned from the device */
} cdc_ioctl_t;
/* Max valid buffer size that can be sent to the dongle */
#define CDC_MAX_MSG_SIZE ETHER_MAX_LEN
/* len field is divided into input and output buffer lengths */
#define CDCL_IOC_OUTLEN_MASK 0x0000FFFF /* maximum or expected response length, */
/* excluding IOCTL header */
#define CDCL_IOC_OUTLEN_SHIFT 0
#define CDCL_IOC_INLEN_MASK 0xFFFF0000 /* input buffer length, excluding IOCTL header */
#define CDCL_IOC_INLEN_SHIFT 16
/* CDC flag definitions */
#define CDCF_IOC_ERROR 0x01 /* 0=success, 1=ioctl cmd failed */
#define CDCF_IOC_SET 0x02 /* 0=get, 1=set cmd */
#define CDCF_IOC_OVL_IDX_MASK 0x3c /* overlay region index mask */
#define CDCF_IOC_OVL_RSV 0x40 /* 1=reserve this overlay region */
#define CDCF_IOC_OVL 0x80 /* 1=this ioctl corresponds to an overlay */
#define CDCF_IOC_ACTION_MASK 0xfe /* SET/GET, OVL_IDX, OVL_RSV, OVL mask */
#define CDCF_IOC_ACTION_SHIFT 1 /* SET/GET, OVL_IDX, OVL_RSV, OVL shift */
#define CDCF_IOC_IF_MASK 0xF000 /* I/F index */
#define CDCF_IOC_IF_SHIFT 12
#define CDCF_IOC_ID_MASK 0xFFFF0000 /* used to uniquely id an ioctl req/resp pairing */
#define CDCF_IOC_ID_SHIFT 16 /* # of bits of shift for ID Mask */
#define CDC_IOC_IF_IDX(flags) (((flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT)
#define CDC_IOC_ID(flags) (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT)
#define CDC_GET_IF_IDX(hdr) \
((int)((((hdr)->flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT))
#define CDC_SET_IF_IDX(hdr, idx) \
((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | ((idx) << CDCF_IOC_IF_SHIFT)))
/*
* BDC header
*
* The BDC header is used on data packets to convey priority across USB.
*/
struct bdc_header {
uint8 flags; /* Flags */
uint8 priority; /* 802.1d Priority 0:2 bits, 4:7 USB flow control info */
uint8 flags2;
uint8 dataOffset; /* Offset from end of BDC header to packet data, in
* 4-byte words. Leaves room for optional headers.
*/
};
#define BDC_HEADER_LEN 4
/* flags field bitmap */
#define BDC_FLAG_EXEMPT 0x03 /* EXT_STA: encryption exemption (host -> dongle?) */
#define BDC_FLAG_80211_PKT 0x01 /* Packet is in 802.11 format (dongle -> host) */
#define BDC_FLAG_SUM_GOOD 0x04 /* Dongle has verified good RX checksums */
#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums: host->device */
#define BDC_FLAG_EVENT_MSG 0x08 /* Payload contains an event msg: device->host */
#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */
#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */
/* priority field bitmap */
#define BDC_PRIORITY_MASK 0x07
#define BDC_PRIORITY_FC_MASK 0xf0 /* flow control info mask */
#define BDC_PRIORITY_FC_SHIFT 4 /* flow control info shift */
/* flags2 field bitmap */
#define BDC_FLAG2_IF_MASK 0x0f /* interface index (host <-> dongle) */
#define BDC_FLAG2_IF_SHIFT 0
#define BDC_FLAG2_FC_FLAG 0x10 /* flag to indicate if pkt contains */
/* FLOW CONTROL info only */
/* version numbers */
#define BDC_PROTO_VER_1 1 /* Old Protocol version */
#define BDC_PROTO_VER 2 /* Protocol version */
/* flags2.if field access macros */
#define BDC_GET_IF_IDX(hdr) \
((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT))
#define BDC_SET_IF_IDX(hdr, idx) \
((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | ((idx) << BDC_FLAG2_IF_SHIFT)))
#endif /* _bcmcdc_h_ */

View File

@@ -0,0 +1,616 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Misc system wide definitions
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmdefs.h 788740 2018-11-13 21:45:01Z $
*/
#ifndef _bcmdefs_h_
#define _bcmdefs_h_
/*
* One doesn't need to include this file explicitly, gets included automatically if
* typedefs.h is included.
*/
/* Use BCM_REFERENCE to suppress warnings about intentionally-unused function
* arguments or local variables.
*/
#define BCM_REFERENCE(data) ((void)(data))
/* Allow for suppressing unused variable warnings. */
#ifdef __GNUC__
#define UNUSED_VAR __attribute__ ((unused))
#else
#define UNUSED_VAR
#endif // endif
/* GNU GCC 4.6+ supports selectively turning off a warning.
* Define these diagnostic macros to help suppress cast-qual warning
* until all the work can be done to fix the casting issues.
*/
#if (defined(__GNUC__) && defined(STRICT_GCC_WARNINGS) && (__GNUC__ > 4 || (__GNUC__ == \
4 && __GNUC_MINOR__ >= 6)))
#define GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST() \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
#define GCC_DIAGNOSTIC_POP() \
_Pragma("GCC diagnostic pop")
#else
#define GCC_DIAGNOSTIC_PUSH_SUPPRESS_CAST()
#define GCC_DIAGNOSTIC_POP()
#endif /* Diagnostic macros not defined */
/* Support clang for MACOSX compiler */
#ifdef __clang__
#define CLANG_DIAGNOSTIC_PUSH_SUPPRESS_CAST() \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wcast-qual\"")
#define CLANG_DIAGNOSTIC_PUSH_SUPPRESS_FORMAT() \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wformat-nonliteral\"")
#define CLANG_DIAGNOSTIC_POP() \
_Pragma("clang diagnostic pop")
#else
#define CLANG_DIAGNOSTIC_PUSH_SUPPRESS_CAST()
#define CLANG_DIAGNOSTIC_PUSH_SUPPRESS_FORMAT()
#define CLANG_DIAGNOSTIC_POP()
#endif // endif
/* Compile-time assert can be used in place of ASSERT if the expression evaluates
* to a constant at compile time.
*/
#define STATIC_ASSERT(expr) { \
/* Make sure the expression is constant. */ \
typedef enum { _STATIC_ASSERT_NOT_CONSTANT = (expr) } _static_assert_e UNUSED_VAR; \
/* Make sure the expression is true. */ \
typedef char STATIC_ASSERT_FAIL[(expr) ? 1 : -1] UNUSED_VAR; \
}
/* Reclaiming text and data :
* The following macros specify special linker sections that can be reclaimed
* after a system is considered 'up'.
* BCMATTACHFN is also used for detach functions (it's not worth having a BCMDETACHFN,
* as in most cases, the attach function calls the detach function to clean up on error).
*/
#if defined(BCM_RECLAIM)
extern bool bcm_reclaimed;
extern bool bcm_attach_part_reclaimed;
extern bool bcm_preattach_part_reclaimed;
extern bool bcm_postattach_part_reclaimed;
#define RECLAIMED() (bcm_reclaimed)
#define ATTACH_PART_RECLAIMED() (bcm_attach_part_reclaimed)
#define PREATTACH_PART_RECLAIMED() (bcm_preattach_part_reclaimed)
#define POSTATTACH_PART_RECLAIMED() (bcm_postattach_part_reclaimed)
#if defined(BCM_RECLAIM_ATTACH_FN_DATA)
#define _data __attribute__ ((__section__ (".dataini2." #_data))) _data
#define _fn __attribute__ ((__section__ (".textini2." #_fn), noinline)) _fn
/* Relocate attach symbols to save-restore region to increase pre-reclaim heap size. */
#define BCM_SRM_ATTACH_DATA(_data) __attribute__ ((__section__ (".datasrm." #_data))) _data
#define BCM_SRM_ATTACH_FN(_fn) __attribute__ ((__section__ (".textsrm." #_fn), noinline)) _fn
#ifndef PREATTACH_NORECLAIM
#define BCMPREATTACHDATA(_data) __attribute__ ((__section__ (".dataini3." #_data))) _data
#define BCMPREATTACHFN(_fn) __attribute__ ((__section__ (".textini3." #_fn), noinline)) _fn
#else
#define BCMPREATTACHDATA(_data) __attribute__ ((__section__ (".dataini2." #_data))) _data
#define BCMPREATTACHFN(_fn) __attribute__ ((__section__ (".textini2." #_fn), noinline)) _fn
#endif /* PREATTACH_NORECLAIM */
#define BCMPOSTATTACHDATA(_data) __attribute__ ((__section__ (".dataini5." #_data))) _data
#define BCMPOSTATTACHFN(_fn) __attribute__ ((__section__ (".textini5." #_fn), noinline)) _fn
#else /* BCM_RECLAIM_ATTACH_FN_DATA */
#define _data _data
#define _fn _fn
#define BCMPREATTACHDATA(_data) _data
#define BCMPREATTACHFN(_fn) _fn
#define BCMPOSTATTACHDATA(_data) _data
#define BCMPOSTATTACHFN(_fn) _fn
#endif /* BCM_RECLAIM_ATTACH_FN_DATA */
#ifdef BCMDBG_SR
/*
* Don't reclaim so we can compare SR ASM
*/
#define BCMPREATTACHDATASR(_data) _data
#define BCMPREATTACHFNSR(_fn) _fn
#define BCMATTACHDATASR(_data) _data
#define BCMATTACHFNSR(_fn) _fn
#else
#define BCMPREATTACHDATASR(_data) BCMPREATTACHDATA(_data)
#define BCMPREATTACHFNSR(_fn) BCMPREATTACHFN(_fn)
#define BCMATTACHDATASR(_data) _data
#define BCMATTACHFNSR(_fn) _fn
#endif // endif
#if defined(BCM_RECLAIM_INIT_FN_DATA)
#define _data __attribute__ ((__section__ (".dataini1." #_data))) _data
#define _fn __attribute__ ((__section__ (".textini1." #_fn), noinline)) _fn
#define CONST
#else /* BCM_RECLAIM_INIT_FN_DATA */
#define _data _data
#define _fn _fn
#ifndef CONST
#define CONST const
#endif // endif
#endif /* BCM_RECLAIM_INIT_FN_DATA */
/* Non-manufacture or internal attach function/dat */
#define BCMNMIATTACHFN(_fn) _fn
#define BCMNMIATTACHDATA(_data) _data
#if defined(BCM_CISDUMP_NO_RECLAIM)
#define BCMCISDUMPATTACHFN(_fn) _fn
#define BCMCISDUMPATTACHDATA(_data) _data
#else
#define BCMCISDUMPATTACHFN(_fn) BCMNMIATTACHFN(_fn)
#define BCMCISDUMPATTACHDATA(_data) BCMNMIATTACHDATA(_data)
#endif // endif
/* SROM with OTP support */
#if defined(BCMOTPSROM)
#define BCMSROMATTACHFN(_fn) _fn
#define BCMSROMATTACHDATA(_data) _data
#else
#define BCMSROMATTACHFN(_fn) BCMNMIATTACHFN(_fn)
#define BCMSROMATTACHDATA(_data) BCMNMIATTACHFN(_data)
#endif /* BCMOTPSROM */
#if defined(BCM_CISDUMP_NO_RECLAIM)
#define BCMSROMCISDUMPATTACHFN(_fn) _fn
#define BCMSROMCISDUMPATTACHDATA(_data) _data
#else
#define BCMSROMCISDUMPATTACHFN(_fn) BCMSROMATTACHFN(_fn)
#define BCMSROMCISDUMPATTACHDATA(_data) BCMSROMATTACHDATA(_data)
#endif /* BCM_CISDUMP_NO_RECLAIM */
#ifdef BCMNODOWN
#define _fn _fn
#else
#define _fn _fn
#endif // endif
#else /* BCM_RECLAIM */
#define bcm_reclaimed (1)
#define bcm_attach_part_reclaimed (1)
#define bcm_preattach_part_reclaimed (1)
#define bcm_postattach_part_reclaimed (1)
#define _data _data
#define _fn _fn
#define BCM_SRM_ATTACH_DATA(_data) _data
#define BCM_SRM_ATTACH_FN(_fn) _fn
#define BCMPREATTACHDATA(_data) _data
#define BCMPREATTACHFN(_fn) _fn
#define BCMPOSTATTACHDATA(_data) _data
#define BCMPOSTATTACHFN(_fn) _fn
#define _data _data
#define _fn _fn
#define _fn _fn
#define BCMNMIATTACHFN(_fn) _fn
#define BCMNMIATTACHDATA(_data) _data
#define BCMSROMATTACHFN(_fn) _fn
#define BCMSROMATTACHDATA(_data) _data
#define BCMPREATTACHFNSR(_fn) _fn
#define BCMPREATTACHDATASR(_data) _data
#define BCMATTACHFNSR(_fn) _fn
#define BCMATTACHDATASR(_data) _data
#define BCMSROMATTACHFN(_fn) _fn
#define BCMSROMATTACHDATA(_data) _data
#define BCMCISDUMPATTACHFN(_fn) _fn
#define BCMCISDUMPATTACHDATA(_data) _data
#define BCMSROMCISDUMPATTACHFN(_fn) _fn
#define BCMSROMCISDUMPATTACHDATA(_data) _data
#define CONST const
#define RECLAIMED() (bcm_reclaimed)
#define ATTACH_PART_RECLAIMED() (bcm_attach_part_reclaimed)
#define PREATTACH_PART_RECLAIMED() (bcm_preattach_part_reclaimed)
#define POSTATTACH_PART_RECLAIMED() (bcm_postattach_part_reclaimed)
#endif /* BCM_RECLAIM */
#define BCMUCODEDATA(_data) _data
#if defined(BCM_DMA_CT) && !defined(BCM_DMA_CT_DISABLED)
#define BCMUCODEFN(_fn) _fn
#else
#define BCMUCODEFN(_fn) _fn
#endif /* BCM_DMA_CT */
#if !defined STB
#undef BCM47XX_CA9
#endif /* STB */
/* BCMFASTPATH Related Macro defines
*/
#ifndef BCMFASTPATH
#if defined(STB)
#define BCMFASTPATH __attribute__ ((__section__ (".text.fastpath")))
#define BCMFASTPATH_HOST __attribute__ ((__section__ (".text.fastpath_host")))
#else /* mips || BCM47XX_CA9 || STB */
#define BCMFASTPATH
#define BCMFASTPATH_HOST
#endif // endif
#endif /* BCMFASTPATH */
/* Use the BCMRAMFN() macro to tag functions in source that must be included in RAM (excluded from
* ROM). This should eliminate the need to manually specify these functions in the ROM config file.
* It should only be used in special cases where the function must be in RAM for *all* ROM-based
* chips.
*/
#define BCMRAMFN(_fn) _fn
/* Use BCMSPECSYM() macro to tag symbols going to a special output section in the binary. */
#define BCMSPECSYM(_sym) __attribute__ ((__section__ (".special." #_sym))) _sym
#define STATIC static
/* Bus types */
#define SI_BUS 0 /* SOC Interconnect */
#define PCI_BUS 1 /* PCI target */
#define PCMCIA_BUS 2 /* PCMCIA target */
#define SDIO_BUS 3 /* SDIO target */
#define JTAG_BUS 4 /* JTAG */
#define USB_BUS 5 /* USB (does not support R/W REG) */
#define SPI_BUS 6 /* gSPI target */
#define RPC_BUS 7 /* RPC target */
/* Allows size optimization for single-bus image */
#ifdef BCMBUSTYPE
#define BUSTYPE(bus) (BCMBUSTYPE)
#else
#define BUSTYPE(bus) (bus)
#endif // endif
#ifdef BCMBUSCORETYPE
#define BUSCORETYPE(ct) (BCMBUSCORETYPE)
#else
#define BUSCORETYPE(ct) (ct)
#endif // endif
/* Allows size optimization for single-backplane image */
#ifdef BCMCHIPTYPE
#define CHIPTYPE(bus) (BCMCHIPTYPE)
#else
#define CHIPTYPE(bus) (bus)
#endif // endif
/* Allows size optimization for SPROM support */
#if defined(BCMSPROMBUS)
#define SPROMBUS (BCMSPROMBUS)
#elif defined(SI_PCMCIA_SROM)
#define SPROMBUS (PCMCIA_BUS)
#else
#define SPROMBUS (PCI_BUS)
#endif // endif
/* Allows size optimization for single-chip image */
#ifdef BCMCHIPID
#define CHIPID(chip) (BCMCHIPID)
#else
#define CHIPID(chip) (chip)
#endif // endif
#ifdef BCMCHIPREV
#define CHIPREV(rev) (BCMCHIPREV)
#else
#define CHIPREV(rev) (rev)
#endif // endif
#ifdef BCMPCIEREV
#define PCIECOREREV(rev) (BCMPCIEREV)
#else
#define PCIECOREREV(rev) (rev)
#endif // endif
#ifdef BCMPMUREV
#define PMUREV(rev) (BCMPMUREV)
#else
#define PMUREV(rev) (rev)
#endif // endif
#ifdef BCMCCREV
#define CCREV(rev) (BCMCCREV)
#else
#define CCREV(rev) (rev)
#endif // endif
#ifdef BCMGCIREV
#define GCIREV(rev) (BCMGCIREV)
#else
#define GCIREV(rev) (rev)
#endif // endif
#ifdef BCMCR4REV
#define CR4REV (BCMCR4REV)
#endif // endif
/* Defines for DMA Address Width - Shared between OSL and HNDDMA */
#define DMADDR_MASK_32 0x0 /* Address mask for 32-bits */
#define DMADDR_MASK_30 0xc0000000 /* Address mask for 30-bits */
#define DMADDR_MASK_26 0xFC000000 /* Address maks for 26-bits */
#define DMADDR_MASK_0 0xffffffff /* Address mask for 0-bits (hi-part) */
#define DMADDRWIDTH_26 26 /* 26-bit addressing capability */
#define DMADDRWIDTH_30 30 /* 30-bit addressing capability */
#define DMADDRWIDTH_32 32 /* 32-bit addressing capability */
#define DMADDRWIDTH_63 63 /* 64-bit addressing capability */
#define DMADDRWIDTH_64 64 /* 64-bit addressing capability */
typedef struct {
uint32 loaddr;
uint32 hiaddr;
} dma64addr_t;
#define PHYSADDR64HI(_pa) ((_pa).hiaddr)
#define PHYSADDR64HISET(_pa, _val) \
do { \
(_pa).hiaddr = (_val); \
} while (0)
#define PHYSADDR64LO(_pa) ((_pa).loaddr)
#define PHYSADDR64LOSET(_pa, _val) \
do { \
(_pa).loaddr = (_val); \
} while (0)
#ifdef BCMDMA64OSL
typedef dma64addr_t dmaaddr_t;
#define PHYSADDRHI(_pa) PHYSADDR64HI(_pa)
#define PHYSADDRHISET(_pa, _val) PHYSADDR64HISET(_pa, _val)
#define PHYSADDRLO(_pa) PHYSADDR64LO(_pa)
#define PHYSADDRLOSET(_pa, _val) PHYSADDR64LOSET(_pa, _val)
#define PHYSADDRTOULONG(_pa, _ulong) \
do { \
_ulong = ((unsigned long long)(_pa).hiaddr << 32) | ((_pa).loaddr); \
} while (0)
#else
typedef unsigned long dmaaddr_t;
#define PHYSADDRHI(_pa) (0)
#define PHYSADDRHISET(_pa, _val)
#define PHYSADDRLO(_pa) ((_pa))
#define PHYSADDRLOSET(_pa, _val) \
do { \
(_pa) = (_val); \
} while (0)
#endif /* BCMDMA64OSL */
#define PHYSADDRISZERO(_pa) (PHYSADDRLO(_pa) == 0 && PHYSADDRHI(_pa) == 0)
/* One physical DMA segment */
typedef struct {
dmaaddr_t addr;
uint32 length;
} hnddma_seg_t;
#define MAX_DMA_SEGS 8
typedef struct {
void *oshdmah; /* Opaque handle for OSL to store its information */
uint origsize; /* Size of the virtual packet */
uint nsegs;
hnddma_seg_t segs[MAX_DMA_SEGS];
} hnddma_seg_map_t;
/* packet headroom necessary to accommodate the largest header in the system, (i.e TXOFF).
* By doing, we avoid the need to allocate an extra buffer for the header when bridging to WL.
* There is a compile time check in wlc.c which ensure that this value is at least as big
* as TXOFF. This value is used in dma_rxfill (hnddma.c).
*/
#if defined(BCM_RPC_NOCOPY) || defined(BCM_RCP_TXNOCOPY)
/* add 40 bytes to allow for extra RPC header and info */
#define BCMEXTRAHDROOM 260
#else /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */
#if defined(STB)
#define BCMEXTRAHDROOM 224
#else
#define BCMEXTRAHDROOM 204
#endif // endif
#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY */
/* Packet alignment for most efficient SDIO (can change based on platform) */
#ifndef SDALIGN
#define SDALIGN 32
#endif // endif
/* Headroom required for dongle-to-host communication. Packets allocated
* locally in the dongle (e.g. for CDC ioctls or RNDIS messages) should
* leave this much room in front for low-level message headers which may
* be needed to get across the dongle bus to the host. (These messages
* don't go over the network, so room for the full WL header above would
* be a waste.).
*/
#define BCMDONGLEHDRSZ 12
#define BCMDONGLEPADSZ 16
#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ)
#if defined(NO_BCMDBG_ASSERT)
# undef BCMDBG_ASSERT
# undef BCMASSERT_LOG
#endif // endif
#if defined(BCMASSERT_LOG)
#define BCMASSERT_SUPPORT
#endif // endif
/* Macros for doing definition and get/set of bitfields
* Usage example, e.g. a three-bit field (bits 4-6):
* #define <NAME>_M BITFIELD_MASK(3)
* #define <NAME>_S 4
* ...
* regval = R_REG(osh, &regs->regfoo);
* field = GFIELD(regval, <NAME>);
* regval = SFIELD(regval, <NAME>, 1);
* W_REG(osh, &regs->regfoo, regval);
*/
#define BITFIELD_MASK(width) \
(((unsigned)1 << (width)) - 1)
#define GFIELD(val, field) \
(((val) >> field ## _S) & field ## _M)
#define SFIELD(val, field, bits) \
(((val) & (~(field ## _M << field ## _S))) | \
((unsigned)(bits) << field ## _S))
/* define BCMSMALL to remove misc features for memory-constrained environments */
#ifdef BCMSMALL
#undef BCMSPACE
#define bcmspace FALSE /* if (bcmspace) code is discarded */
#else
#define BCMSPACE
#define bcmspace TRUE /* if (bcmspace) code is retained */
#endif // endif
/* Max. nvram variable table size */
#ifndef MAXSZ_NVRAM_VARS
#ifdef LARGE_NVRAM_MAXSZ
#define MAXSZ_NVRAM_VARS (LARGE_NVRAM_MAXSZ * 2)
#else
#define LARGE_NVRAM_MAXSZ 8192
#define MAXSZ_NVRAM_VARS (LARGE_NVRAM_MAXSZ * 2)
#endif /* LARGE_NVRAM_MAXSZ */
#endif /* !MAXSZ_NVRAM_VARS */
/* ROM_ENAB_RUNTIME_CHECK may be set based upon the #define below (for ROM builds). It may also
* be defined via makefiles (e.g. ROM auto abandon unoptimized compiles).
*/
#ifdef BCMLFRAG /* BCMLFRAG support enab macros */
extern bool _bcmlfrag;
#if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD)
#define BCMLFRAG_ENAB() (_bcmlfrag)
#elif defined(BCMLFRAG_DISABLED)
#define BCMLFRAG_ENAB() (0)
#else
#define BCMLFRAG_ENAB() (1)
#endif
#else
#define BCMLFRAG_ENAB() (0)
#endif /* BCMLFRAG_ENAB */
#ifdef BCMPCIEDEV /* BCMPCIEDEV support enab macros */
extern bool _pciedevenab;
#if defined(ROM_ENAB_RUNTIME_CHECK)
#define BCMPCIEDEV_ENAB() (_pciedevenab)
#elif defined(BCMPCIEDEV_ENABLED)
#define BCMPCIEDEV_ENAB() 1
#else
#define BCMPCIEDEV_ENAB() 0
#endif
#else
#define BCMPCIEDEV_ENAB() 0
#endif /* BCMPCIEDEV */
#ifdef BCMRESVFRAGPOOL /* BCMRESVFRAGPOOL support enab macros */
extern bool _resvfragpool_enab;
#if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD)
#define BCMRESVFRAGPOOL_ENAB() (_resvfragpool_enab)
#elif defined(BCMRESVFRAGPOOL_ENABLED)
#define BCMRESVFRAGPOOL_ENAB() 1
#else
#define BCMRESVFRAGPOOL_ENAB() 0
#endif
#else
#define BCMRESVFRAGPOOL_ENAB() 0
#endif /* BCMPCIEDEV */
#define BCMSDIODEV_ENAB() 0
/* Max size for reclaimable NVRAM array */
#ifdef DL_NVRAM
#define NVRAM_ARRAY_MAXSIZE DL_NVRAM
#else
#define NVRAM_ARRAY_MAXSIZE MAXSZ_NVRAM_VARS
#endif /* DL_NVRAM */
extern uint32 gFWID;
#ifdef BCMFRWDPOOLREORG /* BCMFRWDPOOLREORG support enab macros */
extern bool _bcmfrwdpoolreorg;
#if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD)
#define BCMFRWDPOOLREORG_ENAB() (_bcmfrwdpoolreorg)
#elif defined(BCMFRWDPOOLREORG_DISABLED)
#define BCMFRWDPOOLREORG_ENAB() (0)
#else
#define BCMFRWDPOOLREORG_ENAB() (1)
#endif
#else
#define BCMFRWDPOOLREORG_ENAB() (0)
#endif /* BCMFRWDPOOLREORG */
#ifdef BCMPOOLRECLAIM /* BCMPOOLRECLAIM support enab macros */
extern bool _bcmpoolreclaim;
#if defined(ROM_ENAB_RUNTIME_CHECK) || !defined(DONGLEBUILD)
#define BCMPOOLRECLAIM_ENAB() (_bcmpoolreclaim)
#elif defined(BCMPOOLRECLAIM_DISABLED)
#define BCMPOOLRECLAIM_ENAB() (0)
#else
#define BCMPOOLRECLAIM_ENAB() (1)
#endif
#else
#define BCMPOOLRECLAIM_ENAB() (0)
#endif /* BCMPOOLRECLAIM */
/* Chip related low power flags (lpflags) */
#ifndef PAD
#define _PADLINE(line) pad ## line
#define _XSTR(line) _PADLINE(line)
#define PAD _XSTR(__LINE__)
#endif // endif
#ifndef FRAG_HEADROOM
#define FRAG_HEADROOM 224 /* In absence of SFD, use default headroom of 224 */
#endif // endif
#define MODULE_DETACH(var, detach_func)\
if (var) { \
detach_func(var); \
(var) = NULL; \
}
#define MODULE_DETACH_2(var1, var2, detach_func) detach_func(var1, var2)
#define MODULE_DETACH_TYPECASTED(var, detach_func) detach_func(var)
/* When building ROML image use runtime conditional to cause the compiler
* to compile everything but not to complain "defined but not used"
* as #ifdef would cause at the callsites.
* In the end functions called under if (0) {} will not be linked
* into the final binary if they're not called from other places either.
*/
#define BCM_ATTACH_REF_DECL()
#define BCM_ATTACH_REF() (1)
/* Const in ROM else normal data in RAM */
#if defined(ROM_ENAB_RUNTIME_CHECK)
#define ROMCONST CONST
#else
#define ROMCONST
#endif // endif
#endif /* _bcmdefs_h_ */

View File

@@ -0,0 +1,945 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Broadcom device-specific manifest constants.
*
* Copyright (C) 1999-2019, Broadcom.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
*
* <<Broadcom-WL-IPTag/Open:>>
*
* $Id: bcmdevs.h 825481 2019-06-14 10:06:03Z $
*/
#ifndef _BCMDEVS_H
#define _BCMDEVS_H
/* PCI vendor IDs */
#define VENDOR_EPIGRAM 0xfeda
#define VENDOR_BROADCOM 0x14e4
#define VENDOR_3COM 0x10b7
#define VENDOR_NETGEAR 0x1385
#define VENDOR_DIAMOND 0x1092
#define VENDOR_INTEL 0x8086
#define VENDOR_DELL 0x1028
#define VENDOR_HP 0x103c
#define VENDOR_HP_COMPAQ 0x0e11
#define VENDOR_APPLE 0x106b
#define VENDOR_SI_IMAGE 0x1095 /* Silicon Image, used by Arasan SDIO Host */
#define VENDOR_BUFFALO 0x1154 /* Buffalo vendor id */
#define VENDOR_TI 0x104c /* Texas Instruments */
#define VENDOR_RICOH 0x1180 /* Ricoh */
#define VENDOR_JMICRON 0x197b
/* PCMCIA vendor IDs */
#define VENDOR_BROADCOM_PCMCIA 0x02d0
/* SDIO vendor IDs */
#define VENDOR_BROADCOM_SDIO 0x00BF
/* DONGLE VID/PIDs */
#define BCM_DNGL_VID 0x0a5c
#define BCM_DNGL_BL_PID_4328 0xbd12
#define BCM_DNGL_BL_PID_4322 0xbd13
#define BCM_DNGL_BL_PID_4319 0xbd16
#define BCM_DNGL_BL_PID_43236 0xbd17
#define BCM_DNGL_BL_PID_4332 0xbd18
#define BCM_DNGL_BL_PID_4360 0xbd1d
#define BCM_DNGL_BL_PID_43143 0xbd1e
#define BCM_DNGL_BL_PID_43242 0xbd1f
#define BCM_DNGL_BL_PID_4335 0xbd20
#define BCM_DNGL_BL_PID_4350 0xbd23
#define BCM_DNGL_BL_PID_4345 0xbd24
#define BCM_DNGL_BL_PID_4349 0xbd25
#define BCM_DNGL_BL_PID_4354 0xbd26
#define BCM_DNGL_BL_PID_43569 0xbd27
#define BCM_DNGL_BL_PID_4373 0xbd29
#define BCM_DNGL_BDC_PID 0x0bdc
#define BCM_DNGL_JTAG_PID 0x4a44
#ifdef DEPRECATED
#define BCM_DNGL_BL_PID_43239 0xbd1b
#define BCM_DNGL_BL_PID_4324 0xbd1c
#define BCM_DNGL_BL_PID_43242 0xbd1f
#define BCM_DNGL_BL_PID_43909 0xbd28
#endif // endif
/* PCI Device IDs */
#ifdef DEPRECATED /* These products have been deprecated */
#define BCM4210_DEVICE_ID 0x1072 /* never used */
#define BCM4230_DEVICE_ID 0x1086 /* never used */
#define BCM4401_ENET_ID 0x170c /* 4401b0 production enet cards */
#define BCM3352_DEVICE_ID 0x3352 /* bcm3352 device id */
#define BCM3360_DEVICE_ID 0x3360 /* bcm3360 device id */
#define BCM4211_DEVICE_ID 0x4211
#define BCM4231_DEVICE_ID 0x4231
#define BCM4303_D11B_ID 0x4303 /* 4303 802.11b */
#define BCM4311_D11G_ID 0x4311 /* 4311 802.11b/g id */
#define BCM4311_D11DUAL_ID 0x4312 /* 4311 802.11a/b/g id */
#define BCM4311_D11A_ID 0x4313 /* 4311 802.11a id */
#define BCM4328_D11DUAL_ID 0x4314 /* 4328/4312 802.11a/g id */
#define BCM4328_D11G_ID 0x4315 /* 4328/4312 802.11g id */
#define BCM4328_D11A_ID 0x4316 /* 4328/4312 802.11a id */
#define BCM4318_D11A_ID 0x431a /* 4318 802.11a id */
#define BCM4325_D11DUAL_ID 0x431b /* 4325 802.11a/g id */
#define BCM4325_D11G_ID 0x431c /* 4325 802.11g id */
#define BCM4325_D11A_ID 0x431d /* 4325 802.11a id */
#define BCM4306_UART_ID 0x4322 /* 4306 uart */
#define BCM4306_V90_ID 0x4323 /* 4306 v90 codec */
#define BCM4306_D11G_ID2 0x4325 /* BCM4306_D11G_ID; INF w/loose binding war */
#define BCM4321_D11N_ID 0x4328 /* 4321 802.11n dualband id */
#define BCM4321_D11N2G_ID 0x4329 /* 4321 802.11n 2.4Ghz band id */
#define BCM4321_D11N5G_ID 0x432a /* 4321 802.11n 5Ghz band id */
#define BCM4322_D11N_ID 0x432b /* 4322 802.11n dualband device */
#define BCM4322_D11N2G_ID 0x432c /* 4322 802.11n 2.4GHz device */
#define BCM4322_D11N5G_ID 0x432d /* 4322 802.11n 5GHz device */
#define BCM4329_D11N_ID 0x432e /* 4329 802.11n dualband device */
#define BCM4329_D11N2G_ID 0x432f /* 4329 802.11n 2.4G device */
#define BCM4329_D11N5G_ID 0x4330 /* 4329 802.11n 5G device */
#define BCM4314_D11N2G_ID 0x4364 /* 4314 802.11n 2.4G device */
#define BCM43143_D11N2G_ID 0x4366 /* 43143 802.11n 2.4G device */
#define BCM4315_D11DUAL_ID 0x4334 /* 4315 802.11a/g id */
#define BCM4315_D11G_ID 0x4335 /* 4315 802.11g id */
#define BCM4315_D11A_ID 0x4336 /* 4315 802.11a id */
#define BCM4319_D11N_ID 0x4337 /* 4319 802.11n dualband device */
#define BCM4319_D11N2G_ID 0x4338 /* 4319 802.11n 2.4G device */
#define BCM4319_D11N5G_ID 0x4339 /* 4319 802.11n 5G device */
#define BCM43221_D11N2G_ID 0x4341 /* 43221 802.11n 2.4GHz device */
#define BCM43222_D11N_ID 0x4350 /* 43222 802.11n dualband device */
#define BCM43222_D11N2G_ID 0x4351 /* 43222 802.11n 2.4GHz device */
#define BCM43222_D11N5G_ID 0x4352 /* 43222 802.11n 5GHz device */
#define BCM43225_D11N2G_ID 0x4357 /* 43225 802.11n 2.4GHz device */
#define BCM43226_D11N_ID 0x4354 /* 43226 802.11n dualband device */
#define BCM43228_D11N5G_ID 0x435a /* 43228 802.11n 5GHz device */
#define BCM43231_D11N2G_ID 0x4340 /* 43231 802.11n 2.4GHz device */
#define BCM43237_D11N_ID 0x4355 /* 43237 802.11n dualband device */
#define BCM43237_D11N5G_ID 0x4356 /* 43237 802.11n 5GHz device */
#define BCM43239_D11N_ID 0x4370 /* 43239 802.11n dualband device */
#define BCM4324_D11N_ID 0x4374 /* 4324 802.11n dualband device */
#define BCM43242_D11N_ID 0x4367 /* 43242 802.11n dualband device */
#define BCM43242_D11N2G_ID 0x4368 /* 43242 802.11n 2.4G device */
#define BCM43242_D11N5G_ID 0x4369 /* 43242 802.11n 5G device */
#define BCM4330_D11N_ID 0x4360 /* 4330 802.11n dualband device */
#define BCM4330_D11N2G_ID 0x4361 /* 4330 802.11n 2.4G device */
#define BCM4330_D11N5G_ID 0x4362 /* 4330 802.11n 5G device */
#define BCM4334_D11N_ID 0x4380 /* 4334 802.11n dualband device */
#define BCM4334_D11N2G_ID 0x4381 /* 4334 802.11n 2.4G device */
#define BCM4334_D11N5G_ID 0x4382 /* 4334 802.11n 5G device */
#define BCM43342_D11N_ID 0x4383 /* 43342 802.11n dualband device */
#define BCM43342_D11N2G_ID 0x4384 /* 43342 802.11n 2.4G device */
#define BCM43342_D11N5G_ID 0x4385 /* 43342 802.11n 5G device */
#define BCM43341_D11N_ID 0x4386 /* 43341 802.11n dualband device */
#define BCM43341_D11N2G_ID 0x4387 /* 43341 802.11n 2.4G device */
#define BCM43341_D11N5G_ID 0x4388 /* 43341 802.11n 5G device */
#define BCM4336_D11N_ID 0x4343 /* 4336 802.11n 2.4GHz device */
#define BCM43362_D11N_ID 0x4363 /* 43362 802.11n 2.4GHz device */
#define BCM43421_D11N_ID 0xA99D /* 43421 802.11n dualband device */
#define BCM43909_D11AC_ID 0x43d0 /* 43909 802.11ac dualband device */
#define BCM43909_D11AC2G_ID 0x43d1 /* 43909 802.11ac 2.4G device */
#define BCM43909_D11AC5G_ID 0x43d2 /* 43909 802.11ac 5G device */
#endif /* DEPRECATED */
/* DEPRECATED but used */
#define BCM4306_D11G_ID 0x4320 /* 4306 802.11g */
#define BCM4306_D11A_ID 0x4321 /* 4306 802.11a */
#define BCM4306_D11DUAL_ID 0x4324 /* 4306 dual A+B */
#define BCM43142_D11N2G_ID 0x4365 /* 43142 802.11n 2.4G device */
#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */
#define BCM4318_D11G_ID 0x4318 /* 4318 802.11b/g id */
#define BCM4318_D11DUAL_ID 0x4319 /* 4318 802.11a/b/g id */
#define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */
#define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db device */
#define BCM43227_D11N2G_ID 0x4358 /* 43228 802.11n 2.4GHz device */
#define BCM43228_D11N_ID 0x4359 /* 43228 802.11n DualBand device */
#define BCM4331_D11N_ID 0x4331 /* 4331 802.11n dualband id */
#define BCM4331_D11N2G_ID 0x4332 /* 4331 802.11n 2.4Ghz band id */
#define BCM4331_D11N5G_ID 0x4333 /* 4331 802.11n 5Ghz band id */
/* DEPRECATED */
#define BCM43236_D11N_ID 0x4346 /* 43236 802.11n dualband device */
#define BCM43236_D11N2G_ID 0x4347 /* 43236 802.11n 2.4GHz device */
#define BCM43236_D11N5G_ID 0x4348 /* 43236 802.11n 5GHz device */
#define BCM6362_D11N_ID 0x435f /* 6362 802.11n dualband device */
#define BCM6362_D11N2G_ID 0x433f /* 6362 802.11n 2.4Ghz band id */
#define BCM6362_D11N5G_ID 0x434f /* 6362 802.11n 5Ghz band id */
#define BCM43217_D11N2G_ID 0x43a9 /* 43217 802.11n 2.4GHz device */
#define BCM43131_D11N2G_ID 0x43aa /* 43131 802.11n 2.4GHz device */
#define BCM4360_D11AC_ID 0x43a0
#define BCM4360_D11AC2G_ID 0x43a1
#define BCM4360_D11AC5G_ID 0x43a2
#define BCM4345_D11AC_ID 0x43ab /* 4345 802.11ac dualband device */
#define BCM4345_D11AC2G_ID 0x43ac /* 4345 802.11ac 2.4G device */
#define BCM4345_D11AC5G_ID 0x43ad /* 4345 802.11ac 5G device */
#define BCM43455_D11AC_ID 0x43e3 /* 43455 802.11ac dualband device */
#define BCM43455_D11AC2G_ID 0x43e4 /* 43455 802.11ac 2.4G device */
#define BCM43455_D11AC5G_ID 0x43e5 /* 43455 802.11ac 5G device */
#define BCM4335_D11AC_ID 0x43ae
#define BCM4335_D11AC2G_ID 0x43af
#define BCM4335_D11AC5G_ID 0x43b0
#define BCM4352_D11AC_ID 0x43b1 /* 4352 802.11ac dualband device */
#define BCM4352_D11AC2G_ID 0x43b2 /* 4352 802.11ac 2.4G device */
#define BCM4352_D11AC5G_ID 0x43b3 /* 4352 802.11ac 5G device */
#define BCM43602_D11AC_ID 0x43ba /* ac dualband PCI devid SPROM programmed */
#define BCM43602_D11AC2G_ID 0x43bb /* 43602 802.11ac 2.4G device */
#define BCM43602_D11AC5G_ID 0x43bc /* 43602 802.11ac 5G device */
#define BCM4349_D11AC_ID 0x4349 /* 4349 802.11ac dualband device */
#define BCM4349_D11AC2G_ID 0x43dd /* 4349 802.11ac 2.4G device */
#define BCM4349_D11AC5G_ID 0x43de /* 4349 802.11ac 5G device */
#define BCM53573_D11AC_ID 0x43b4 /* 53573 802.11ac dualband device */
#define BCM53573_D11AC2G_ID 0x43b5 /* 53573 802.11ac 2.4G device */
#define BCM53573_D11AC5G_ID 0x43b6 /* 53573 802.11ac 5G device */
#define BCM47189_D11AC_ID 0x43c6 /* 47189 802.11ac dualband device */
#define BCM47189_D11AC2G_ID 0x43c7 /* 47189 802.11ac 2.4G device */
#define BCM47189_D11AC5G_ID 0x43c8 /* 47189 802.11ac 5G device */
#define BCM4355_D11AC_ID 0x43dc /* 4355 802.11ac dualband device */
#define BCM4355_D11AC2G_ID 0x43fc /* 4355 802.11ac 2.4G device */
#define BCM4355_D11AC5G_ID 0x43fd /* 4355 802.11ac 5G device */
#define BCM4359_D11AC_ID 0x43ef /* 4359 802.11ac dualband device */
#define BCM4359_D11AC2G_ID 0x43fe /* 4359 802.11ac 2.4G device */
#define BCM4359_D11AC5G_ID 0x43ff /* 4359 802.11ac 5G device */
#define BCM43596_D11AC_ID 0x4415 /* 43596 802.11ac dualband device */
#define BCM43596_D11AC2G_ID 0x4416 /* 43596 802.11ac 2.4G device */
#define BCM43596_D11AC5G_ID 0x4417 /* 43596 802.11ac 5G device */
#define BCM43597_D11AC_ID 0x441c /* 43597 802.11ac dualband device */
#define BCM43597_D11AC2G_ID 0x441d /* 43597 802.11ac 2.4G device */
#define BCM43597_D11AC5G_ID 0x441e /* 43597 802.11ac 5G device */
#define BCM43012_D11N_ID 0xA804 /* 43012 802.11n dualband device */
#define BCM43012_D11N2G_ID 0xA805 /* 43012 802.11n 2.4G device */
#define BCM43012_D11N5G_ID 0xA806 /* 43012 802.11n 5G device */
#define BCM43014_D11N_ID 0x4495 /* 43014 802.11n dualband device */
#define BCM43014_D11N2G_ID 0x4496 /* 43014 802.11n 2.4G device */
#define BCM43014_D11N5G_ID 0x4497 /* 43014 802.11n 5G device */
/* PCI Subsystem ID */
#define BCM94313HMGBL_SSID_VEN1 0x0608
#define BCM94313HMG_SSID_VEN1 0x0609
#define BCM943142HM_SSID_VEN1 0x0611
#define BCM4350_D11AC_ID 0x43a3
#define BCM4350_D11AC2G_ID 0x43a4
#define BCM4350_D11AC5G_ID 0x43a5
#define BCM43556_D11AC_ID 0x43b7
#define BCM43556_D11AC2G_ID 0x43b8
#define BCM43556_D11AC5G_ID 0x43b9
#define BCM43558_D11AC_ID 0x43c0
#define BCM43558_D11AC2G_ID 0x43c1
#define BCM43558_D11AC5G_ID 0x43c2
#define BCM43566_D11AC_ID 0x43d3
#define BCM43566_D11AC2G_ID 0x43d4
#define BCM43566_D11AC5G_ID 0x43d5
#define BCM43568_D11AC_ID 0x43d6
#define BCM43568_D11AC2G_ID 0x43d7
#define BCM43568_D11AC5G_ID 0x43d8
#define BCM43569_D11AC_ID 0x43d9
#define BCM43569_D11AC2G_ID 0x43da
#define BCM43569_D11AC5G_ID 0x43db
#define BCM43570_D11AC_ID 0x43d9
#define BCM43570_D11AC2G_ID 0x43da
#define BCM43570_D11AC5G_ID 0x43db
#define BCM4354_D11AC_ID 0x43df /* 4354 802.11ac dualband device */
#define BCM4354_D11AC2G_ID 0x43e0 /* 4354 802.11ac 2.4G device */
#define BCM4354_D11AC5G_ID 0x43e1 /* 4354 802.11ac 5G device */
#define BCM43430_D11N2G_ID 0x43e2 /* 43430 802.11n 2.4G device */
#define BCM43018_D11N2G_ID 0x441b /* 43018 802.11n 2.4G device */
#define BCM4347_D11AC_ID 0x440a /* 4347 802.11ac dualband device */
#define BCM4347_D11AC2G_ID 0x440b /* 4347 802.11ac 2.4G device */
#define BCM4347_D11AC5G_ID 0x440c /* 4347 802.11ac 5G device */
#define BCM4361_D11AC_ID 0x441f /* 4361 802.11ac dualband device */
#define BCM4361_D11AC2G_ID 0x4420 /* 4361 802.11ac 2.4G device */
#define BCM4361_D11AC5G_ID 0x4421 /* 4361 802.11ac 5G device */
#define BCM4362_D11AX_ID 0x4490 /* 4362 802.11ax dualband device */
#define BCM4362_D11AX2G_ID 0x4491 /* 4362 802.11ax 2.4G device */
#define BCM4362_D11AX5G_ID 0x4492 /* 4362 802.11ax 5G device */
#define BCM43751_D11AX_ID 0x449a /* 43751 802.11ax dualband device */
#define BCM43751_D11AX2G_ID 0x449b /* 43751 802.11ax 2.4G device */
#define BCM43751_D11AX5G_ID 0x449c /* 43751 802.11ax 5G device */
#define BCM43752_D11AX_ID 0x449d /* 43752 802.11ax dualband device */
#define BCM43752_D11AX2G_ID 0x449e /* 43752 802.11ax 2.4G device */
#define BCM43752_D11AX5G_ID 0x449f /* 43752 802.11ax 5G device */
#define BCM4364_D11AC_ID 0x4464 /* 4364 802.11ac dualband device */
#define BCM4364_D11AC2G_ID 0x446a /* 4364 802.11ac 2.4G device */
#define BCM4364_D11AC5G_ID 0x446b /* 4364 802.11ac 5G device */
#define BCM4365_D11AC_ID 0x43ca
#define BCM4365_D11AC2G_ID 0x43cb
#define BCM4365_D11AC5G_ID 0x43cc
#define BCM4366_D11AC_ID 0x43c3
#define BCM4366_D11AC2G_ID 0x43c4
#define BCM4366_D11AC5G_ID 0x43c5
/* TBD change below values */
#define BCM4369_D11AX_ID 0x4470 /* 4369 802.11ax dualband device */
#define BCM4369_D11AX2G_ID 0x4471 /* 4369 802.11ax 2.4G device */
#define BCM4369_D11AX5G_ID 0x4472 /* 4369 802.11ax 5G device */
#define BCM4375_D11AX_ID 0x4475 /* 4375 802.11ax dualband device */
#define BCM4375_D11AX2G_ID 0x4476 /* 4375 802.11ax 2.4G device */
#define BCM4375_D11AX5G_ID 0x4477 /* 4375 802.11ax 5G device */
#define BCM43349_D11N_ID 0x43e6 /* 43349 802.11n dualband id */
#define BCM43349_D11N2G_ID 0x43e7 /* 43349 802.11n 2.4Ghz band id */
#define BCM43349_D11N5G_ID 0x43e8 /* 43349 802.11n 5Ghz band id */
#define BCM4358_D11AC_ID 0x43e9 /* 4358 802.11ac dualband device */
#define BCM4358_D11AC2G_ID 0x43ea /* 4358 802.11ac 2.4G device */
#define BCM4358_D11AC5G_ID 0x43eb /* 4358 802.11ac 5G device */
#define BCM4356_D11AC_ID 0x43ec /* 4356 802.11ac dualband device */
#define BCM4356_D11AC2G_ID 0x43ed /* 4356 802.11ac 2.4G device */
#define BCM4356_D11AC5G_ID 0x43ee /* 4356 802.11ac 5G device */
#define BCM4371_D11AC_ID 0x440d /* 4371 802.11ac dualband device */
#define BCM4371_D11AC2G_ID 0x440e /* 4371 802.11ac 2.4G device */
#define BCM4371_D11AC5G_ID 0x440f /* 4371 802.11ac 5G device */
#define BCM7271_D11AC_ID 0x4410 /* 7271 802.11ac dualband device */
#define BCM7271_D11AC2G_ID 0x4411 /* 7271 802.11ac 2.4G device */
#define BCM7271_D11AC5G_ID 0x4412 /* 7271 802.11ac 5G device */
#define BCM4373_D11AC_ID 0x4418 /* 4373 802.11ac dualband device */
#define BCM4373_D11AC2G_ID 0x4419 /* 4373 802.11ac 2.4G device */
#define BCM4373_D11AC5G_ID 0x441a /* 4373 802.11ac 5G device */
#define BCMGPRS_UART_ID 0x4333 /* Uart id used by 4306/gprs card */
#define BCMGPRS2_UART_ID 0x4344 /* Uart id used by 4306/gprs card */
#define FPGA_JTAGM_ID 0x43f0 /* FPGA jtagm device id */
#define BCM_JTAGM_ID 0x43f1 /* BCM jtagm device id */
#define SDIOH_FPGA_ID 0x43f2 /* sdio host fpga */
#define BCM_SDIOH_ID 0x43f3 /* BCM sdio host id */
#define SDIOD_FPGA_ID 0x43f4 /* sdio device fpga */
#define SPIH_FPGA_ID 0x43f5 /* PCI SPI Host Controller FPGA */
#define BCM_SPIH_ID 0x43f6 /* Synopsis SPI Host Controller */
#define MIMO_FPGA_ID 0x43f8 /* FPGA mimo minimacphy device id */
#define BCM_JTAGM2_ID 0x43f9 /* BCM alternate jtagm device id */
#define SDHCI_FPGA_ID 0x43fa /* Standard SDIO Host Controller FPGA */
#define BCM4402_ENET_ID 0x4402 /* 4402 enet */
#define BCM4402_V90_ID 0x4403 /* 4402 v90 codec */
#define BCM4410_DEVICE_ID 0x4410 /* bcm44xx family pci iline */
#define BCM4412_DEVICE_ID 0x4412 /* bcm44xx family pci enet */
#define BCM4430_DEVICE_ID 0x4430 /* bcm44xx family cardbus iline */
#define BCM4432_DEVICE_ID 0x4432 /* bcm44xx family cardbus enet */
#define BCM4704_ENET_ID 0x4706 /* 4704 enet (Use 47XX_ENET_ID instead!) */
#define BCM4710_DEVICE_ID 0x4710 /* 4710 primary function 0 */
#define BCM47XX_AUDIO_ID 0x4711 /* 47xx audio codec */
#define BCM47XX_V90_ID 0x4712 /* 47xx v90 codec */
#define BCM47XX_ENET_ID 0x4713 /* 47xx enet */
#define BCM47XX_EXT_ID 0x4714 /* 47xx external i/f */
#define BCM47XX_GMAC_ID 0x4715 /* 47xx Unimac based GbE */
#define BCM47XX_USBH_ID 0x4716 /* 47xx usb host */
#define BCM47XX_USBD_ID 0x4717 /* 47xx usb device */
#define BCM47XX_IPSEC_ID 0x4718 /* 47xx ipsec */
#define BCM47XX_ROBO_ID 0x4719 /* 47xx/53xx roboswitch core */
#define BCM47XX_USB20H_ID 0x471a /* 47xx usb 2.0 host */
#define BCM47XX_USB20D_ID 0x471b /* 47xx usb 2.0 device */
#define BCM47XX_ATA100_ID 0x471d /* 47xx parallel ATA */
#define BCM47XX_SATAXOR_ID 0x471e /* 47xx serial ATA & XOR DMA */
#define BCM47XX_GIGETH_ID 0x471f /* 47xx GbE (5700) */
#ifdef DEPRECATED /* These products have been deprecated */
#define BCM4712_MIPS_ID 0x4720 /* 4712 base devid */
#define BCM4716_DEVICE_ID 0x4722 /* 4716 base devid */
#endif /* DEPRECATED */
#define BCM47XX_USB30H_ID 0x472a /* 47xx usb 3.0 host */
#define BCM47XX_USB30D_ID 0x472b /* 47xx usb 3.0 device */
#define BCM47XX_USBHUB_ID 0x472c /* 47xx usb hub */
#define BCM47XX_SMBUS_EMU_ID 0x47fe /* 47xx emulated SMBus device */
#define BCM47XX_XOR_EMU_ID 0x47ff /* 47xx emulated XOR engine */
#define EPI41210_DEVICE_ID 0xa0fa /* bcm4210 */
#define EPI41230_DEVICE_ID 0xa10e /* bcm4230 */
#define JINVANI_SDIOH_ID 0x4743 /* Jinvani SDIO Gold Host */
#define BCM27XX_SDIOH_ID 0x2702 /* BCM27xx Standard SDIO Host */
#define PCIXX21_FLASHMEDIA_ID 0x803b /* TI PCI xx21 Standard Host Controller */
#define PCIXX21_SDIOH_ID 0x803c /* TI PCI xx21 Standard Host Controller */
#define R5C822_SDIOH_ID 0x0822 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host */
#define JMICRON_SDIOH_ID 0x2381 /* JMicron Standard SDIO Host Controller */
#define BCM43452_D11AC_ID 0x47ab /* 43452 802.11ac dualband device */
#define BCM43452_D11AC2G_ID 0x47ac /* 43452 802.11ac 2.4G device */
#define BCM43452_D11AC5G_ID 0x47ad /* 43452 802.11ac 5G device */
/* Chip IDs */
#ifdef DEPRECATED /* These products have been deprecated */
#define BCM4306_CHIP_ID 0x4306 /* 4306 chipcommon chipid */
#define BCM4311_CHIP_ID 0x4311 /* 4311 PCIe 802.11a/b/g */
#define BCM43111_CHIP_ID 43111 /* 43111 chipcommon chipid (OTP chipid) */
#define BCM43112_CHIP_ID 43112 /* 43112 chipcommon chipid (OTP chipid) */
#define BCM4312_CHIP_ID 0x4312 /* 4312 chipcommon chipid */
#define BCM4314_CHIP_ID 0x4314 /* 4314 chipcommon chipid */
#define BCM43142_CHIP_ID 43142 /* 43142 chipcommon chipid */
#define BCM43143_CHIP_ID 43143 /* 43143 chipcommon chipid */
#define BCM4313_CHIP_ID 0x4313 /* 4313 chip id */
#define BCM4315_CHIP_ID 0x4315 /* 4315 chip id */
#define BCM4318_CHIP_ID 0x4318 /* 4318 chipcommon chipid */
#define BCM4319_CHIP_ID 0x4319 /* 4319 chip id */
#define BCM4320_CHIP_ID 0x4320 /* 4320 chipcommon chipid */
#define BCM4321_CHIP_ID 0x4321 /* 4321 chipcommon chipid */
#define BCM4322_CHIP_ID 0x4322 /* 4322 chipcommon chipid */
#define BCM43221_CHIP_ID 43221 /* 43221 chipcommon chipid (OTP chipid) */
#define BCM43222_CHIP_ID 43222 /* 43222 chipcommon chipid */
#define BCM43224_CHIP_ID 43224 /* 43224 chipcommon chipid */
#define BCM43225_CHIP_ID 43225 /* 43225 chipcommon chipid */
#define BCM43226_CHIP_ID 43226 /* 43226 chipcommon chipid */
#define BCM43227_CHIP_ID 43227 /* 43227 chipcommon chipid */
#define BCM43228_CHIP_ID 43228 /* 43228 chipcommon chipid */
#define BCM43231_CHIP_ID 43231 /* 43231 chipcommon chipid (OTP chipid) */
#define BCM43237_CHIP_ID 43237 /* 43237 chipcommon chipid */
#define BCM43239_CHIP_ID 43239 /* 43239 chipcommon chipid */
#define BCM4324_CHIP_ID 0x4324 /* 4324 chipcommon chipid */
#define BCM43242_CHIP_ID 43242 /* 43242 chipcommon chipid */
#define BCM43243_CHIP_ID 43243 /* 43243 chipcommon chipid */
#define BCM4325_CHIP_ID 0x4325 /* 4325 chip id */
#define BCM4328_CHIP_ID 0x4328 /* 4328 chip id */
#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */
#define BCM4331_CHIP_ID 0x4331 /* 4331 chipcommon chipid */
#define BCM4334_CHIP_ID 0x4334 /* 4334 chipcommon chipid */
#define BCM43349_CHIP_ID 43349 /* 43349(0xA955) chipcommon chipid */
#define BCM43340_CHIP_ID 43340 /* 43340 chipcommon chipid */
#define BCM43341_CHIP_ID 43341 /* 43341 chipcommon chipid */
#define BCM43342_CHIP_ID 43342 /* 43342 chipcommon chipid */
#define BCM4342_CHIP_ID 4342 /* 4342 chipcommon chipid (OTP, RBBU) */
#define BCM43420_CHIP_ID 43420 /* 43420 chipcommon chipid (OTP, RBBU) */
#define BCM43421_CHIP_ID 43421 /* 43224 chipcommon chipid (OTP, RBBU) */
#define BCM43431_CHIP_ID 43431 /* 4331 chipcommon chipid (OTP, RBBU) */
#define BCM43909_CHIP_ID 0xab85 /* 43909 chipcommon chipid */
#define BCM4712_CHIP_ID 0x4712 /* 4712 chipcommon chipid */
#define BCM4716_CHIP_ID 0x4716 /* 4716 chipcommon chipid */
#define BCM4748_CHIP_ID 0x4748 /* 4716 chipcommon chipid (OTP, RBBU) */
#endif /* DEPRECATED */
/* DEPRECATED but still referenced in components - start */
#define BCM47162_CHIP_ID 47162 /* 47162 chipcommon chipid */
#define BCM5354_CHIP_ID 0x5354 /* 5354 chipcommon chipid */
/* DEPRECATED but still referenced in components - end */
#define BCM43217_CHIP_ID 43217 /* 43217 chip id (OTP chipid) */
#define BCM43131_CHIP_ID 43131 /* 43131 chip id (OTP chipid) */
#define BCM43234_CHIP_ID 43234 /* 43234 chipcommon chipid */
#define BCM43235_CHIP_ID 43235 /* 43235 chipcommon chipid */
#define BCM43236_CHIP_ID 43236 /* 43236 chipcommon chipid */
#define BCM43238_CHIP_ID 43238 /* 43238 chipcommon chipid */
#define BCM43428_CHIP_ID 43428 /* 43228 chipcommon chipid (OTP, RBBU) */
#define BCM43460_CHIP_ID 43460 /* 4360 chipcommon chipid (OTP, RBBU) */
#define BCM43362_CHIP_ID 43362 /* 43362 chipcommon chipid */
#define BCM4330_CHIP_ID 0x4330 /* 4330 chipcommon chipid */
#define BCM43465_CHIP_ID 43465 /* 4366 chipcommon chipid (OTP, RBBU) */
#define BCM43525_CHIP_ID 43525 /* 4365 chipcommon chipid (OTP, RBBU) */
#define BCM47452_CHIP_ID 47452 /* 53573 chipcommon chipid (OTP, RBBU) */
#define BCM6362_CHIP_ID 0x6362 /* 6362 chipcommon chipid */
#define BCM43143_CHIP_ID 43143 /* 43143 chipcommon chipid */
#define BCM4324_CHIP_ID 0x4324 /* 4324 chipcommon chipid */
#define BCM43242_CHIP_ID 43242 /* 43242 chipcommon chipid */
#define BCM4334_CHIP_ID 0x4334 /* 4334 chipcommon chipid */
#define BCM4335_CHIP_ID 0x4335 /* 4335 chipcommon chipid */
#define BCM4339_CHIP_ID 0x4339 /* 4339 chipcommon chipid */
#define BCM4360_CHIP_ID 0x4360 /* 4360 chipcommon chipid */
#define BCM4364_CHIP_ID 0x4364 /* 4364 chipcommon chipid */
#define BCM4352_CHIP_ID 0x4352 /* 4352 chipcommon chipid */
#define BCM43526_CHIP_ID 0xAA06
#define BCM43340_CHIP_ID 43340 /* 43340 chipcommon chipid */
#define BCM43341_CHIP_ID 43341 /* 43341 chipcommon chipid */
#define BCM4350_CHIP_ID 0x4350 /* 4350 chipcommon chipid */
#define BCM4354_CHIP_ID 0x4354 /* 4354 chipcommon chipid */
#define BCM4356_CHIP_ID 0x4356 /* 4356 chipcommon chipid */
#define BCM4371_CHIP_ID 0x4371 /* 4371 chipcommon chipid */
#define BCM43556_CHIP_ID 0xAA24 /* 43556 chipcommon chipid */
#define BCM43558_CHIP_ID 0xAA26 /* 43558 chipcommon chipid */
#define BCM43562_CHIP_ID 0xAA2A /* 43562 chipcommon chipid */
#define BCM43566_CHIP_ID 0xAA2E /* 43566 chipcommon chipid */
#define BCM43567_CHIP_ID 0xAA2F /* 43567 chipcommon chipid */
#define BCM43568_CHIP_ID 0xAA30 /* 43568 chipcommon chipid */
#define BCM43569_CHIP_ID 0xAA31 /* 43569 chipcommon chipid */
#define BCM43570_CHIP_ID 0xAA32 /* 43570 chipcommon chipid */
#define BCM4358_CHIP_ID 0x4358 /* 4358 chipcommon chipid */
#define BCM43012_CHIP_ID 0xA804 /* 43012 chipcommon chipid */
#define BCM43014_CHIP_ID 0xA806 /* 43014 chipcommon chipid */
#define BCM4369_CHIP_ID 0x4369 /* 4369 chipcommon chipid */
#define BCM4350_CHIP(chipid) ((CHIPID(chipid) == BCM4350_CHIP_ID) || \
(CHIPID(chipid) == BCM4354_CHIP_ID) || \
(CHIPID(chipid) == BCM43556_CHIP_ID) || \
(CHIPID(chipid) == BCM43558_CHIP_ID) || \
(CHIPID(chipid) == BCM43566_CHIP_ID) || \
(CHIPID(chipid) == BCM43567_CHIP_ID) || \
(CHIPID(chipid) == BCM43568_CHIP_ID) || \
(CHIPID(chipid) == BCM43569_CHIP_ID) || \
(CHIPID(chipid) == BCM43570_CHIP_ID) || \
(CHIPID(chipid) == BCM4358_CHIP_ID)) /* 4350 variations */
#define BCM4345_CHIP_ID 0x4345 /* 4345 chipcommon chipid */
#define BCM43454_CHIP_ID 43454 /* 43454 chipcommon chipid */
#define BCM43455_CHIP_ID 43455 /* 43455 chipcommon chipid */
#define BCM43457_CHIP_ID 43457 /* 43457 chipcommon chipid */
#define BCM43458_CHIP_ID 43458 /* 43458 chipcommon chipid */
#define BCM4345_CHIP(chipid) (CHIPID(chipid) == BCM4345_CHIP_ID || \
CHIPID(chipid) == BCM43454_CHIP_ID || \
CHIPID(chipid) == BCM43455_CHIP_ID || \
CHIPID(chipid) == BCM43457_CHIP_ID || \
CHIPID(chipid) == BCM43458_CHIP_ID)
#define CASE_BCM4345_CHIP case BCM4345_CHIP_ID: /* fallthrough */ \
case BCM43454_CHIP_ID: /* fallthrough */ \
case BCM43455_CHIP_ID: /* fallthrough */ \
case BCM43457_CHIP_ID: /* fallthrough */ \
case BCM43458_CHIP_ID
#define BCM43430_CHIP_ID 43430 /* 43430 chipcommon chipid */
#define BCM43018_CHIP_ID 43018 /* 43018 chipcommon chipid */
#define BCM4349_CHIP_ID 0x4349 /* 4349 chipcommon chipid */
#define BCM4355_CHIP_ID 0x4355 /* 4355 chipcommon chipid */
#define BCM4359_CHIP_ID 0x4359 /* 4359 chipcommon chipid */
#define BCM4349_CHIP(chipid) ((CHIPID(chipid) == BCM4349_CHIP_ID) || \
(CHIPID(chipid) == BCM4355_CHIP_ID) || \
(CHIPID(chipid) == BCM4359_CHIP_ID))
#define BCM4355_CHIP(chipid) (CHIPID(chipid) == BCM4355_CHIP_ID)
#define BCM4349_CHIP_GRPID BCM4349_CHIP_ID: \
case BCM4355_CHIP_ID: \
case BCM4359_CHIP_ID
#define BCM43596_CHIP_ID 43596 /* 43596 chipcommon chipid */
#define BCM4347_CHIP_ID 0x4347 /* 4347 chipcommon chipid */
#define BCM4357_CHIP_ID 0x4357 /* 4357 chipcommon chipid */
#define BCM4361_CHIP_ID 0x4361 /* 4361 chipcommon chipid */
#define BCM4369_CHIP_ID 0x4369 /* 4369/ chipcommon chipid */
#define BCM4375_CHIP_ID 0x4375 /* 4375/ chipcommon chipid */
#define BCM4377_CHIP_ID 0x4377 /* 4377/ chipcommon chipid */
#define BCM4362_CHIP_ID 0x4362 /* 4362 chipcommon chipid */
#define BCM43751_CHIP_ID 0xAAE7 /* 43751 chipcommon chipid */
#define BCM43752_CHIP_ID 0xAAE8 /* 43752 chipcommon chipid */
#define BCM4347_CHIP(chipid) ((CHIPID(chipid) == BCM4347_CHIP_ID) || \
(CHIPID(chipid) == BCM4357_CHIP_ID) || \
(CHIPID(chipid) == BCM4361_CHIP_ID))
#define BCM4347_CHIP_GRPID BCM4347_CHIP_ID: \
case BCM4357_CHIP_ID: \
case BCM4361_CHIP_ID
#define BCM4369_CHIP(chipid) ((CHIPID(chipid) == BCM4369_CHIP_ID) || \
(CHIPID(chipid) == BCM4377_CHIP_ID))
#define BCM4369_CHIP_GRPID BCM4369_CHIP_ID: \
case BCM4377_CHIP_ID
#define BCM4362_CHIP(chipid) ((CHIPID(chipid) == BCM4362_CHIP_ID) || \
(CHIPID(chipid) == BCM43751_CHIP_ID) || \
(CHIPID(chipid) == BCM43752_CHIP_ID))
#define BCM4362_CHIP_GRPID BCM4362_CHIP_ID: \
case BCM43751_CHIP_ID: \
case BCM43752_CHIP_ID
#define BCM4365_CHIP_ID 0x4365 /* 4365 chipcommon chipid */
#define BCM4366_CHIP_ID 0x4366 /* 4366 chipcommon chipid */
#define BCM43664_CHIP_ID 43664 /* 4366E chipcommon chipid */
#define BCM43666_CHIP_ID 43666 /* 4365E chipcommon chipid */
#define BCM4365_CHIP(chipid) ((CHIPID(chipid) == BCM4365_CHIP_ID) || \
(CHIPID(chipid) == BCM4366_CHIP_ID) || \
(CHIPID(chipid) == BCM43664_CHIP_ID) || \
(CHIPID(chipid) == BCM43666_CHIP_ID))
#define CASE_BCM4365_CHIP case BCM4365_CHIP_ID: /* fallthrough */ \
case BCM4366_CHIP_ID: /* fallthrough */ \
case BCM43664_CHIP_ID: /* fallthrough */ \
case BCM43666_CHIP_ID
#define BCM43602_CHIP_ID 0xaa52 /* 43602 chipcommon chipid */
#define BCM43462_CHIP_ID 0xa9c6 /* 43462 chipcommon chipid */
#define BCM43522_CHIP_ID 0xaa02 /* 43522 chipcommon chipid */
#define BCM43602_CHIP(chipid) ((CHIPID(chipid) == BCM43602_CHIP_ID) || \
(CHIPID(chipid) == BCM43462_CHIP_ID) || \
(CHIPID(chipid) == BCM43522_CHIP_ID)) /* 43602 variations */
#define BCM43012_CHIP(chipid) (CHIPID(chipid) == BCM43012_CHIP_ID)
#define CASE_BCM43602_CHIP case BCM43602_CHIP_ID: /* fallthrough */ \
case BCM43462_CHIP_ID: /* fallthrough */ \
case BCM43522_CHIP_ID
#define BCM4402_CHIP_ID 0x4402 /* 4402 chipid */
#define BCM4704_CHIP_ID 0x4704 /* 4704 chipcommon chipid */
#define BCM4707_CHIP_ID 53010 /* 4707 chipcommon chipid */
#define BCM47094_CHIP_ID 53030 /* 47094 chipcommon chipid */
#define BCM53018_CHIP_ID 53018 /* 53018 chipcommon chipid */
#define BCM4707_CHIP(chipid) (((chipid) == BCM4707_CHIP_ID) || \
((chipid) == BCM53018_CHIP_ID) || \
((chipid) == BCM47094_CHIP_ID))
#define BCM4710_CHIP_ID 0x4710 /* 4710 chipid */
#define BCM4785_CHIP_ID 0x4785 /* 4785 chipcommon chipid */
#define BCM5350_CHIP_ID 0x5350 /* 5350 chipcommon chipid */
#define BCM5352_CHIP_ID 0x5352 /* 5352 chipcommon chipid */
#define BCM5365_CHIP_ID 0x5365 /* 5365 chipcommon chipid */
#define BCM53573_CHIP_ID 53573 /* 53573 chipcommon chipid */
#define BCM53574_CHIP_ID 53574 /* 53574 chipcommon chipid */
#define BCM53573_CHIP(chipid) ((CHIPID(chipid) == BCM53573_CHIP_ID) || \
(CHIPID(chipid) == BCM53574_CHIP_ID) || \
(CHIPID(chipid) == BCM47452_CHIP_ID))
#define BCM53573_CHIP_GRPID BCM53573_CHIP_ID : \
case BCM53574_CHIP_ID : \
case BCM47452_CHIP_ID
#define BCM53573_DEVICE(devid) (((devid) == BCM53573_D11AC_ID) || \
((devid) == BCM53573_D11AC2G_ID) || \
((devid) == BCM53573_D11AC5G_ID) || \
((devid) == BCM47189_D11AC_ID) || \
((devid) == BCM47189_D11AC2G_ID) || \
((devid) == BCM47189_D11AC5G_ID))
#define BCM7271_CHIP_ID 0x05c9 /* 7271 chipcommon chipid */
#define BCM7271_CHIP(chipid) ((CHIPID(chipid) == BCM7271_CHIP_ID))
#define BCM4373_CHIP_ID 0x4373 /* 4373 chipcommon chipid */
/* Package IDs */
#ifdef DEPRECATED /* These products have been deprecated */
#define BCM4303_PKG_ID 2 /* 4303 package id */
#define BCM4309_PKG_ID 1 /* 4309 package id */
#define BCM4712LARGE_PKG_ID 0 /* 340pin 4712 package id */
#define BCM4712SMALL_PKG_ID 1 /* 200pin 4712 package id */
#define BCM4712MID_PKG_ID 2 /* 225pin 4712 package id */
#define BCM4328USBD11G_PKG_ID 2 /* 4328 802.11g USB package id */
#define BCM4328USBDUAL_PKG_ID 3 /* 4328 802.11a/g USB package id */
#define BCM4328SDIOD11G_PKG_ID 4 /* 4328 802.11g SDIO package id */
#define BCM4328SDIODUAL_PKG_ID 5 /* 4328 802.11a/g SDIO package id */
#define BCM4329_289PIN_PKG_ID 0 /* 4329 289-pin package id */
#define BCM4329_182PIN_PKG_ID 1 /* 4329N 182-pin package id */
#define BCM5354E_PKG_ID 1 /* 5354E package id */
#define BCM4716_PKG_ID 8 /* 4716 package id */
#define BCM4717_PKG_ID 9 /* 4717 package id */
#define BCM4718_PKG_ID 10 /* 4718 package id */
#define BCM4331TT_PKG_ID 8 /* 4331 12x12 package id */
#define BCM4331TN_PKG_ID 9 /* 4331 12x9 package id */
#define BCM4331TNA0_PKG_ID 0xb /* 4331 12x9 package id */
#endif /* DEPRECATED */
#define BCM47189_PKG_ID 1 /* 47189 package id */
#define BCM53573_PKG_ID 0 /* 53573 package id */
#define HDLSIM5350_PKG_ID 1 /* HDL simulator package id for a 5350 */
#define HDLSIM_PKG_ID 14 /* HDL simulator package id */
#define HWSIM_PKG_ID 15 /* Hardware simulator package id */
#define BCM4707_PKG_ID 1 /* 4707 package id */
#define BCM4708_PKG_ID 2 /* 4708 package id */
#define BCM4709_PKG_ID 0 /* 4709 package id */
#define PCIXX21_FLASHMEDIA0_ID 0x8033 /* TI PCI xx21 Standard Host Controller */
#define PCIXX21_SDIOH0_ID 0x8034 /* TI PCI xx21 Standard Host Controller */
#define BCM4335_WLCSP_PKG_ID (0x0) /* WLCSP Module/Mobile SDIO/HSIC. */
#define BCM4335_FCBGA_PKG_ID (0x1) /* FCBGA PC/Embeded/Media PCIE/SDIO */
#define BCM4335_WLBGA_PKG_ID (0x2) /* WLBGA COB/Mobile SDIO/HSIC. */
#define BCM4335_FCBGAD_PKG_ID (0x3) /* FCBGA Debug Debug/Dev All if's. */
#define BCM4335_PKG_MASK (0x3)
#define BCM43602_12x12_PKG_ID (0x1) /* 12x12 pins package, used for e.g. router designs */
/* boardflags */
#define BFL_BTC2WIRE 0x00000001 /* old 2wire Bluetooth coexistence, OBSOLETE */
#define BFL_BTCOEX 0x00000001 /* Board supports BTCOEX */
#define BFL_PACTRL 0x00000002 /* Board has gpio 9 controlling the PA */
#define BFL_AIRLINEMODE 0x00000004 /* Board implements gpio radio disable indication */
#define BFL_ADCDIV 0x00000008 /* Board has the rssi ADC divider */
#define BFL_DIS_256QAM 0x00000008
#define BFL_ENETROBO 0x00000010 /* Board has robo switch or core */
#define BFL_TSSIAVG 0x00000010 /* TSSI averaging for ACPHY chips */
#define BFL_NOPLLDOWN 0x00000020 /* Not ok to power down the chip pll and oscillator */
#define BFL_CCKHIPWR 0x00000040 /* Can do high-power CCK transmission */
#define BFL_ENETADM 0x00000080 /* Board has ADMtek switch */
#define BFL_ENETVLAN 0x00000100 /* Board has VLAN capability */
#define BFL_LTECOEX 0x00000200 /* LTE Coex enabled */
#define BFL_NOPCI 0x00000400 /* Board leaves PCI floating */
#define BFL_FEM 0x00000800 /* Board supports the Front End Module */
#define BFL_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */
#define BFL_HGPA 0x00002000 /* Board has a high gain PA */
#define BFL_BTC2WIRE_ALTGPIO 0x00004000 /* Board's BTC 2wire is in the alternate gpios */
#define BFL_ALTIQ 0x00008000 /* Alternate I/Q settings */
#define BFL_NOPA 0x00010000 /* Board has no PA */
#define BFL_RSSIINV 0x00020000 /* Board's RSSI uses positive slope(not TSSI) */
#define BFL_PAREF 0x00040000 /* Board uses the PARef LDO */
#define BFL_3TSWITCH 0x00080000 /* Board uses a triple throw switch shared with BT */
#define BFL_PHASESHIFT 0x00100000 /* Board can support phase shifter */
#define BFL_BUCKBOOST 0x00200000 /* Power topology uses BUCKBOOST */
#define BFL_FEM_BT 0x00400000 /* Board has FEM and switch to share antenna w/ BT */
#define BFL_NOCBUCK 0x00800000 /* Power topology doesn't use CBUCK */
#define BFL_CCKFAVOREVM 0x01000000 /* Favor CCK EVM over spectral mask */
#define BFL_PALDO 0x02000000 /* Power topology uses PALDO */
#define BFL_LNLDO2_2P5 0x04000000 /* Select 2.5V as LNLDO2 output voltage */
#define BFL_FASTPWR 0x08000000
#define BFL_UCPWRCTL_MININDX 0x08000000 /* Enforce min power index to avoid FEM damage */
#define BFL_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */
#define BFL_TRSW_1by2 0x20000000 /* Board has 2 TRSW's in 1by2 designs */
#define BFL_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */
#define BFL_LO_TRSW_R_5GHz 0x40000000 /* In 5G do not throw TRSW to T for clipLO gain */
#define BFL_ELNA_GAINDEF 0x80000000 /* Backoff InitGain based on elna_2g/5g field
* when this flag is set
*/
#define BFL_EXTLNA_TX 0x20000000 /* Temp boardflag to indicate to */
/* boardflags2 */
#define BFL2_RXBB_INT_REG_DIS 0x00000001 /* Board has an external rxbb regulator */
#define BFL2_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */
#define BFL2_TXPWRCTRL_EN 0x00000004 /* Board permits enabling TX Power Control */
#define BFL2_2X4_DIV 0x00000008 /* Board supports the 2X4 diversity switch */
#define BFL2_5G_PWRGAIN 0x00000010 /* Board supports 5G band power gain */
#define BFL2_PCIEWAR_OVR 0x00000020 /* Board overrides ASPM and Clkreq settings */
#define BFL2_CAESERS_BRD 0x00000040 /* Board is Caesers brd (unused by sw) */
#define BFL2_WLCX_ATLAS 0x00000040 /* Board flag to initialize ECI for WLCX on FL-ATLAS */
#define BFL2_BTC3WIRE 0x00000080 /* Board support legacy 3 wire or 4 wire */
#define BFL2_BTCLEGACY 0x00000080 /* Board support legacy 3/4 wire, to replace
* BFL2_BTC3WIRE
*/
#define BFL2_SKWRKFEM_BRD 0x00000100 /* 4321mcm93 board uses Skyworks FEM */
#define BFL2_SPUR_WAR 0x00000200 /* Board has a WAR for clock-harmonic spurs */
#define BFL2_GPLL_WAR 0x00000400 /* Flag to narrow G-band PLL loop b/w */
#define BFL2_TRISTATE_LED 0x00000800 /* Tri-state the LED */
#define BFL2_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */
#define BFL2_2G_SPUR_WAR 0x00002000 /* WAR to reduce and avoid clock-harmonic spurs in 2G */
#define BFL2_BPHY_ALL_TXCORES 0x00004000 /* Transmit bphy frames using all tx cores */
#define BFL2_FCC_BANDEDGE_WAR 0x00008000 /* Activates WAR to improve FCC bandedge performance */
#define BFL2_DAC_SPUR_IMPROVEMENT 0x00008000 /* Reducing DAC Spurs */
#define BFL2_GPLL_WAR2 0x00010000 /* Flag to widen G-band PLL loop b/w */
#define BFL2_REDUCED_PA_TURNONTIME 0x00010000 /* Flag to reduce PA turn on Time */
#define BFL2_IPALVLSHIFT_3P3 0x00020000
#define BFL2_INTERNDET_TXIQCAL 0x00040000 /* Use internal envelope detector for TX IQCAL */
#define BFL2_XTALBUFOUTEN 0x00080000 /* Keep the buffered Xtal output from radio on */
/* Most drivers will turn it off without this flag */
/* to save power. */
#define BFL2_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are controlled by analog PA ctrl lines */
#define BFL2_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are controlled by analog PA ctrl lines */
#define BFL2_ELNACTRL_TRSW_2G 0x00400000 /* AZW4329: 2G gmode_elna_gain controls TR Switch */
#define BFL2_BT_SHARE_ANT0 0x00800000 /* share core0 antenna with BT */
#define BFL2_TEMPSENSE_HIGHER 0x01000000 /* The tempsense threshold can sustain higher value
* than programmed. The exact delta is decided by
* driver per chip/boardtype. This can be used
* when tempsense qualification happens after shipment
*/
#define BFL2_BTC3WIREONLY 0x02000000 /* standard 3 wire btc only. 4 wire not supported */
#define BFL2_PWR_NOMINAL 0x04000000 /* 0: power reduction on, 1: no power reduction */
#define BFL2_EXTLNA_PWRSAVE 0x08000000 /* boardflag to enable ucode to apply power save */
/* ucode control of eLNA during Tx */
#define BFL2_SDR_EN 0x20000000 /* SDR enabled or disabled */
#define BFL2_DYNAMIC_VMID 0x10000000 /* boardflag to enable dynamic Vmid idle TSSI CAL */
#define BFL2_LNA1BYPFORTR2G 0x40000000 /* acphy, enable lna1 bypass for clip gain, 2g */
#define BFL2_LNA1BYPFORTR5G 0x80000000 /* acphy, enable lna1 bypass for clip gain, 5g */
/* SROM 11 - 11ac boardflag definitions */
#define BFL_SROM11_BTCOEX 0x00000001 /* Board supports BTCOEX */
#define BFL_SROM11_WLAN_BT_SH_XTL 0x00000002 /* bluetooth and wlan share same crystal */
#define BFL_SROM11_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */
#define BFL_SROM11_EPA_TURNON_TIME 0x00018000 /* 2 bits for different PA turn on times */
#define BFL_SROM11_EPA_TURNON_TIME_SHIFT 15
#define BFL_SROM11_PRECAL_TX_IDX 0x00040000 /* Dedicated TX IQLOCAL IDX values */
/* per subband, as derived from 43602A1 MCH5 */
#define BFL_SROM11_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */
#define BFL_SROM11_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */
#define BFL2_SROM11_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */
#define BFL2_SROM11_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are ctrl-ed by analog PA ctrl lines */
#define BFL2_SROM11_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are ctrl-ed by analog PA ctrl lines */
#define BFL2_SROM11_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */
#define BFL2_SROM11_EPA_ON_DURING_TXIQLOCAL 0x00020000 /* Keep ext. PA's on in TX IQLO CAL */
/* boardflags3 */
#define BFL3_FEMCTRL_SUB 0x00000007 /* acphy, subrevs of femctrl on top of srom_femctrl */
#define BFL3_RCAL_WAR 0x00000008 /* acphy, rcal war active on this board (4335a0) */
#define BFL3_TXGAINTBLID 0x00000070 /* acphy, txgain table id */
#define BFL3_TXGAINTBLID_SHIFT 0x4 /* acphy, txgain table id shift bit */
#define BFL3_TSSI_DIV_WAR 0x00000080 /* acphy, Seperate paparam for 20/40/80 */
#define BFL3_TSSI_DIV_WAR_SHIFT 0x7 /* acphy, Seperate paparam for 20/40/80 shift bit */
#define BFL3_FEMTBL_FROM_NVRAM 0x00000100 /* acphy, femctrl table is read from nvram */
#define BFL3_FEMTBL_FROM_NVRAM_SHIFT 0x8 /* acphy, femctrl table is read from nvram */
#define BFL3_AGC_CFG_2G 0x00000200 /* acphy, gain control configuration for 2G */
#define BFL3_AGC_CFG_5G 0x00000400 /* acphy, gain control configuration for 5G */
#define BFL3_PPR_BIT_EXT 0x00000800 /* acphy, bit position for 1bit extension for ppr */
#define BFL3_PPR_BIT_EXT_SHIFT 11 /* acphy, bit shift for 1bit extension for ppr */
#define BFL3_BBPLL_SPR_MODE_DIS 0x00001000 /* acphy, disables bbpll spur modes */
#define BFL3_RCAL_OTP_VAL_EN 0x00002000 /* acphy, to read rcal_trim value from otp */
#define BFL3_2GTXGAINTBL_BLANK 0x00004000 /* acphy, blank the first X ticks of 2g gaintbl */
#define BFL3_2GTXGAINTBL_BLANK_SHIFT 14 /* acphy, blank the first X ticks of 2g gaintbl */
#define BFL3_5GTXGAINTBL_BLANK 0x00008000 /* acphy, blank the first X ticks of 5g gaintbl */
#define BFL3_5GTXGAINTBL_BLANK_SHIFT 15 /* acphy, blank the first X ticks of 5g gaintbl */
#define BFL3_PHASETRACK_MAX_ALPHABETA 0x00010000 /* acphy, to max out alpha,beta to 511 */
#define BFL3_PHASETRACK_MAX_ALPHABETA_SHIFT 16 /* acphy, to max out alpha,beta to 511 */
/* acphy, to use backed off gaintbl for lte-coex */
#define BFL3_LTECOEX_GAINTBL_EN 0x00060000
/* acphy, to use backed off gaintbl for lte-coex */
#define BFL3_LTECOEX_GAINTBL_EN_SHIFT 17
#define BFL3_5G_SPUR_WAR 0x00080000 /* acphy, enable spur WAR in 5G band */
#define BFL3_1X1_RSDB_ANT 0x01000000 /* to find if 2-ant RSDB board or 1-ant RSDB board */
#define BFL3_1X1_RSDB_ANT_SHIFT 24
/* acphy: lpmode2g and lpmode_5g related boardflags */
#define BFL3_ACPHY_LPMODE_2G 0x00300000 /* bits 20:21 for lpmode_2g choice */
#define BFL3_ACPHY_LPMODE_2G_SHIFT 20
#define BFL3_ACPHY_LPMODE_5G 0x00C00000 /* bits 22:23 for lpmode_5g choice */
#define BFL3_ACPHY_LPMODE_5G_SHIFT 22
#define BFL3_EXT_LPO_ISCLOCK 0x02000000 /* External LPO is clock, not x-tal */
#define BFL3_FORCE_INT_LPO_SEL 0x04000000 /* Force internal lpo */
#define BFL3_FORCE_EXT_LPO_SEL 0x08000000 /* Force external lpo */
#define BFL3_EN_BRCM_IMPBF 0x10000000 /* acphy, Allow BRCM Implicit TxBF */
#define BFL3_AVVMID_FROM_NVRAM 0x40000000 /* Read Av Vmid from NVRAM */
#define BFL3_VLIN_EN_FROM_NVRAM 0x80000000 /* Read Vlin En from NVRAM */
#define BFL3_AVVMID_FROM_NVRAM_SHIFT 30 /* Read Av Vmid from NVRAM */
#define BFL3_VLIN_EN_FROM_NVRAM_SHIFT 31 /* Enable Vlin from NVRAM */
/* boardflags4 for SROM12/SROM13 */
#define BFL4_SROM12_4dBPAD (1 << 0) /* To distinguigh between normal and 4dB pad board */
#define BFL4_SROM12_2G_DETTYPE (1 << 1) /* Determine power detector type for 2G */
#define BFL4_SROM12_5G_DETTYPE (1 << 2) /* Determine power detector type for 5G */
#define BFL4_SROM13_DETTYPE_EN (1 << 3) /* using pa_dettype from SROM13 flags */
#define BFL4_SROM13_CCK_SPUR_EN (1 << 4) /* using cck spur reduction setting in 4366 */
#define BFL4_SROM13_1P5V_CBUCK (1 << 7) /* using 1.5V cbuck board in 4366 */
#define BFL4_SROM13_EN_SW_TXRXCHAIN_MASK (1 << 8) /* Enable/disable bit for sw chain mask */
#define BFL4_4364_HARPOON 0x0100 /* Harpoon module 4364 */
#define BFL4_4364_GODZILLA 0x0200 /* Godzilla module 4364 */
#define BFL4_BTCOEX_OVER_SECI 0x00000400 /* Enable btcoex over gci seci */
/* papd params */
#define PAPD_TX_ATTN_2G 0xFF
#define PAPD_TX_ATTN_5G 0xFF00
#define PAPD_TX_ATTN_5G_SHIFT 8
#define PAPD_RX_ATTN_2G 0xFF
#define PAPD_RX_ATTN_5G 0xFF00
#define PAPD_RX_ATTN_5G_SHIFT 8
#define PAPD_CAL_IDX_2G 0xFF
#define PAPD_CAL_IDX_5G 0xFF00
#define PAPD_CAL_IDX_5G_SHIFT 8
#define PAPD_BBMULT_2G 0xFF
#define PAPD_BBMULT_5G 0xFF00
#define PAPD_BBMULT_5G_SHIFT 8
#define TIA_GAIN_MODE_2G 0xFF
#define TIA_GAIN_MODE_5G 0xFF00
#define TIA_GAIN_MODE_5G_SHIFT 8
#define PAPD_EPS_OFFSET_2G 0xFFFF
#define PAPD_EPS_OFFSET_5G 0xFFFF0000
#define PAPD_EPS_OFFSET_5G_SHIFT 16
#define PAPD_CALREF_DB_2G 0xFF
#define PAPD_CALREF_DB_5G 0xFF00
#define PAPD_CALREF_DB_5G_SHIFT 8
/* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */
#define BOARD_GPIO_BTC3W_IN 0x850 /* bit 4 is RF_ACTIVE, bit 6 is STATUS, bit 11 is PRI */
#define BOARD_GPIO_BTC3W_OUT 0x020 /* bit 5 is TX_CONF */
#define BOARD_GPIO_BTCMOD_IN 0x010 /* bit 4 is the alternate BT Coexistence Input */
#define BOARD_GPIO_BTCMOD_OUT 0x020 /* bit 5 is the alternate BT Coexistence Out */
#define BOARD_GPIO_BTC_IN 0x080 /* bit 7 is BT Coexistence Input */
#define BOARD_GPIO_BTC_OUT 0x100 /* bit 8 is BT Coexistence Out */
#define BOARD_GPIO_PACTRL 0x200 /* bit 9 controls the PA on new 4306 boards */
#define BOARD_GPIO_12 0x1000 /* gpio 12 */
#define BOARD_GPIO_13 0x2000 /* gpio 13 */
#define BOARD_GPIO_BTC4_IN 0x0800 /* gpio 11, coex4, in */
#define BOARD_GPIO_BTC4_BT 0x2000 /* gpio 12, coex4, bt active */
#define BOARD_GPIO_BTC4_STAT 0x4000 /* gpio 14, coex4, status */
#define BOARD_GPIO_BTC4_WLAN 0x8000 /* gpio 15, coex4, wlan active */
#define BOARD_GPIO_1_WLAN_PWR 0x02 /* throttle WLAN power on X21 board */
#define BOARD_GPIO_2_WLAN_PWR 0x04 /* throttle WLAN power on X29C board */
#define BOARD_GPIO_3_WLAN_PWR 0x08 /* throttle WLAN power on X28 board */
#define BOARD_GPIO_4_WLAN_PWR 0x10 /* throttle WLAN power on X19 board */
#define BOARD_GPIO_13_WLAN_PWR 0x2000 /* throttle WLAN power on X14 board */
#define GPIO_BTC4W_OUT_4312 0x010 /* bit 4 is BT_IODISABLE */
#define PCI_CFG_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */
#define PCI_CFG_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */
#define PCI_CFG_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal power-up */
#define PCI_CFG_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL power-down */
/* power control defines */
#define PLL_DELAY 150 /* us pll on delay */
#define FREF_DELAY 200 /* us fref change delay */
#define MIN_SLOW_CLK 32 /* us Slow clock period */
#define XTAL_ON_DELAY 1000 /* us crystal power-on delay */
/* 43012 wlbga Board */
#define BCM943012WLREF_SSID 0x07d7
/* 43012 fcbga Board */
#define BCM943012FCREF_SSID 0x07d4
/* 43602 Boards, unclear yet what boards will be created. */
#define BCM943602RSVD1_SSID 0x06a5
#define BCM943602RSVD2_SSID 0x06a6
#define BCM943602X87 0X0133
#define BCM943602X87P2 0X0152
#define BCM943602X87P3 0X0153
#define BCM943602X238 0X0132
#define BCM943602X238D 0X014A
#define BCM943602X238DP2 0X0155
#define BCM943602X238DP3 0X0156
#define BCM943602X100 0x0761
#define BCM943602X100GS 0x0157
#define BCM943602X100P2 0x015A
/* # of GPIO pins */
#define GPIO_NUMPINS 32
/* These values are used by dhd host driver. */
#define RDL_RAM_BASE_4319 0x60000000
#define RDL_RAM_BASE_4329 0x60000000
#define RDL_RAM_SIZE_4319 0x48000
#define RDL_RAM_SIZE_4329 0x48000
#define RDL_RAM_SIZE_43236 0x70000
#define RDL_RAM_BASE_43236 0x60000000
#define RDL_RAM_SIZE_4328 0x60000
#define RDL_RAM_BASE_4328 0x80000000
#define RDL_RAM_SIZE_4322 0x60000
#define RDL_RAM_BASE_4322 0x60000000
#define RDL_RAM_SIZE_4360 0xA0000
#define RDL_RAM_BASE_4360 0x60000000
#define RDL_RAM_SIZE_43242 0x90000
#define RDL_RAM_BASE_43242 0x60000000
#define RDL_RAM_SIZE_43143 0x70000
#define RDL_RAM_BASE_43143 0x60000000
#define RDL_RAM_SIZE_4350 0xC0000
#define RDL_RAM_BASE_4350 0x180800
/* generic defs for nvram "muxenab" bits
* Note: these differ for 4335a0. refer bcmchipc.h for specific mux options.
*/
#define MUXENAB_UART 0x00000001
#define MUXENAB_GPIO 0x00000002
#define MUXENAB_ERCX 0x00000004 /* External Radio BT coex */
#define MUXENAB_JTAG 0x00000008
#define MUXENAB_HOST_WAKE 0x00000010 /* configure GPIO for SDIO host_wake */
#define MUXENAB_I2S_EN 0x00000020
#define MUXENAB_I2S_MASTER 0x00000040
#define MUXENAB_I2S_FULL 0x00000080
#define MUXENAB_SFLASH 0x00000100
#define MUXENAB_RFSWCTRL0 0x00000200
#define MUXENAB_RFSWCTRL1 0x00000400
#define MUXENAB_RFSWCTRL2 0x00000800
#define MUXENAB_SECI 0x00001000
#define MUXENAB_BT_LEGACY 0x00002000
#define MUXENAB_HOST_WAKE1 0x00004000 /* configure alternative GPIO for SDIO host_wake */
/* Boot flags */
#define FLASH_KERNEL_NFLASH 0x00000001
#define FLASH_BOOT_NFLASH 0x00000002
#endif /* _BCMDEVS_H */

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