Project import generated by Copybara. GitOrigin-RevId: c7e1b94d58a91150cc4de511235768229864cea6
diff --git a/bcmdhd.1.579.77.41.x/Kconfig b/bcmdhd.1.579.77.41.x/Kconfig deleted file mode 100644 index d48a413..0000000 --- a/bcmdhd.1.579.77.41.x/Kconfig +++ /dev/null
@@ -1,60 +0,0 @@ -config BCMDHD - tristate "Broadcom FullMAC wireless cards support" - ---help--- - This module adds support for wireless adapters based on - Broadcom FullMAC chipset. - -config BCMDHD_FW_PATH - depends on BCMDHD - string "Firmware path" - default "/system/etc/firmware/fw_bcmdhd.bin" - ---help--- - Path to the firmware file. - -config BCMDHD_NVRAM_PATH - depends on BCMDHD - string "NVRAM path" - default "/system/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 - -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" - ---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
diff --git a/bcmdhd.1.579.77.41.x/Makefile b/bcmdhd.1.579.77.41.x/Makefile deleted file mode 100644 index d5fe460..0000000 --- a/bcmdhd.1.579.77.41.x/Makefile +++ /dev/null
@@ -1,230 +0,0 @@ -# bcmdhd -# 1. WL_IFACE_COMB_NUM_CHANNELS must be added if Android version is 4.4 with Kernel version 3.0~3.4, -# otherwise please remove it. - -ifneq ($(CONFIG_BCMDHD),) -PWD=$(src) -else -CONFIG_BCMDHD := m -CONFIG_BCMDHD_FW_PATH="/system/etc/firmware/fw_bcmdhd.bin" -CONFIG_BCMDHD_NVRAM_PATH="/system/etc/firmware/nvram.txt" -CONFIG_BCMDHD_SDIO := y -CONFIG_BCMDHD_OOB := y -endif -CONFIG_BCMDHD_DISABLE_WOWLAN := y -CONFIG_MACH_PLATFORM := y - -$(warning "PWD=$(PWD)") - -DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \ - -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DBCMFILEIMAGE \ - -DDHDTHREAD -DDHD_DEBUG -DSHOW_EVENTS -DBCMDBG -DGET_OTP_MAC_ENABLE \ - -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT -DSUPPORT_PM2_ONLY \ - -DPKT_FILTER_SUPPORT -DPNO_SUPPORT -DDHDTCPACK_SUPPRESS \ - -DDHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT \ - -DMULTIPLE_SUPPLICANT -DMFP \ - -DWL_EXT_IAPSTA -DKEEP_ALIVE \ - -I$(PWD) -I$(PWD)/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 \ - hnd_pktq.o hnd_pktpool.o dhd_config.o wl_android_ext.o - -ifeq ($(CONFIG_BCMDHD),y) -DHDCFLAGS += -DDHD_BUILTIN -$(warning "Built-in DHD") -else -$(warning "Module DHD") -endif -DHDCFLAGS += -DBCOL_TCPKA_SYNC -DBCOL_TCPKA_SYNC_MATCHED_BY_PORT -DHDCFLAGS += -DTCPKA_REPAIR -DHDCFLAGS += -DPF_HOSTWAKE -DHDCFLAGS += -DDHCPC_SUPPORT -DHDCFLAGS += -DONLINECHK_SUPPORT -DHDCFLAGS += -DIDSUP_STATS -DSDIO_TRAITS_STATS -DHDCFLAGS += -DHAL_API -DPF_SETUP_COMMAND -DHDCFLAGS += -DEVENT_SETUP -DHDCFLAGS += -DDHD_SK_PACING_SHIFT=8 -DHDCFLAGS += -DWNM_NEST -DHDCFLAGS += -DEVENT_DATA_HOSTWAKE -DHOSTWAKE_EVENT_TIMEOUT=5000 -DHDCFLAGS += -DSCHED_WAKE -DHDCFLAGS += -DUART_HB_CONFIG -DHDCFLAGS += -DTCPKA_BYPASS -DHDCFLAGS += -DRESUME_INIT -DHDCFLAGS += -DDHD_WAKE_STATUS -DDHD_WAKE_EVENT_STATUS -DDHD_WAKE_RX_STATUS -#DHDCFLAGS += -DDHD_WAKEPKT_DUMP -DHDCFLAGS += -DTXSEQ_SYNC -DHDCFLAGS += -DDHD_CONSOLE_IDX_SYNC -DHDCFLAGS += -DCUSTOM_ASSOC_RETRY_MAX=10 -DHDCFLAGS += -DASSOC_PREFER_BAND -DHDCFLAGS += -DWIFI_STATS -DHDCFLAGS += -DSIMPLE_MAC_PRINT -DHDCFLAGS += -DPSPOLL_WAIT -DPSPOLL_KA_WAIT -DPM_KEEP_ALIVE -DHDCFLAGS += -DGARP_KEEP_ALIVE -DHDCFLAGS += -DBLOCK_LIST_CFG -DRELOAD_WIFI -DHDCFLAGS += -DNOTI_BITBANG - -#BCMDHD_SDIO -ifneq ($(CONFIG_BCMDHD_SDIO),) -DHDCFLAGS += \ - -DBCMSDIO -DMMC_SDIO_ABORT -DBCMLXSDMMC -DUSE_SDIOFIFO_IOVAR \ - -DSDTEST -DBDC -DDHD_USE_IDLECOUNT -DCUSTOM_SDIO_F2_BLKSIZE=128 \ - -DBCMSDIOH_TXGLOM -DBCMSDIOH_TXGLOM_EXT -DHDCFLAGS += -DRXFRAME_THREAD - -ifeq ($(CONFIG_HISILICON_PLATFORM),y) - DHDCFLAGS += -DSDIO_ISR_THREAD -else -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 -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 -ifneq ($(CONFIG_PCI_MSI),) - DHDCFLAGS += -DDHD_USE_MSI -endif -ifeq ($(CONFIG_DHD_USE_STATIC_BUF),y) - DHDCFLAGS += -DDHD_USE_STATIC_CTRLBUF -endif - -DHDOFILES += dhd_pcie.o dhd_pcie_linux.o pcie_core.o dhd_flowring.o \ - dhd_msgbuf.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)) - -DHDOFILES += dbus.o dbus_usb.o dbus_usb_linux.o dhd_cdc.o dhd_wlfc.o -endif - -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_VTS_SUPPORT),y) -ifneq ($(CONFIG_CFG80211),) -DHDCFLAGS += \ - -DGSCAN_SUPPORT -DRTT_SUPPORT -DCUSTOM_FORCE_NODFS_FLAG \ - -DLINKSTAT_SUPPORT -DDEBUGABILITY -DDBG_PKT_MON -DPKT_FILTER_SUPPORT \ - -DAPF -DDHD_WAKE_STATUS \ - -DCUSTOM_COUNTRY_CODE -DDHD_FW_COREDUMP -DEXPLICIT_DISCIF_CLEANUP - -DHDOFILES += dhd_debug_linux.o dhd_debug.o bcmxtlv.o dhd_rtt.o \ - bcm_app_utils.o -endif -endif - -# MESH support for kernel 3.10 later -ifeq ($(CONFIG_WL_MESH),y) - DHDCFLAGS += -DWLMESH -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 -DSET_RANDOM_MAC_SOFTAP,$(DHDCFLAGS)) -endif - -obj-$(CONFIG_BCMDHD) += dhd.o -dhd-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 -else -ifneq ($(CONFIG_DHD_OF_SUPPORT),) - DHDOFILES += dhd_custom_hikey.o - DHDCFLAGS += -DDHD_OF_SUPPORT -ifneq ($(CONFIG_BROADCOM_WIFI_RESERVED_MEM),) - DHDOFILES += dhd_custom_memprealloc.o -endif -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 += -DDHD_USE_STATIC_MEMDUMP -DCONFIG_DHD_USE_STATIC_BUF -endif - -ifneq ($(CONFIG_WIRELESS_EXT),) - DHDOFILES += wl_iw.o wl_escan.o - DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT -DUSE_IW -DWL_ESCAN -endif -ifneq ($(CONFIG_CFG80211),) - DHDOFILES += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o wl_cfg_btcoex.o wl_cfgvendor.o - DHDOFILES += dhd_cfg80211.o - DHDCFLAGS += -DWL_CFG80211 -DWLP2P -DWL_CFG80211_STA_EVENT -DWL_ENABLE_P2P_IF - DHDCFLAGS += -DWL_IFACE_COMB_NUM_CHANNELS - DHDCFLAGS += -DCUSTOM_ROAM_TRIGGER_SETTING=-65 - DHDCFLAGS += -DCUSTOM_ROAM_DELTA_SETTING=15 - DHDCFLAGS += -DCUSTOM_KEEP_ALIVE_SETTING=28000 - DHDCFLAGS += -DCUSTOM_PNO_EVENT_LOCK_xTIME=7 - DHDCFLAGS += -DWL_SUPPORT_AUTO_CHANNEL - DHDCFLAGS += -DWL_SUPPORT_BACKPORTED_KPATCHES - DHDCFLAGS += -DESCAN_RESULT_PATCH -DESCAN_BUF_OVERFLOW_MGMT - DHDCFLAGS += -DVSDB -DWL_CFG80211_VSDB_PRIORITIZE_SCAN_REQUEST - DHDCFLAGS += -DMIRACAST_AMPDU_SIZE=8 - DHDCFLAGS += -DWL_VIRTUAL_APSTA -DWL_CCODE_RELOAD -endif -EXTRA_CFLAGS = $(DHDCFLAGS) -ifeq ($(CONFIG_BCMDHD),m) -EXTRA_LDFLAGS += --strip-debug -endif - -DHDCFLAGS += -DCUSTOMER_HW_AMLOGIC -DHDCFLAGS += -DCONFIG_PATH_AUTO_SELECT -DHDCFLAGS += -DRMMOD_KEEP_F2 -DPOWERUP_MAX_RETRY=0 -DEXT_POWER_SET - -ARCH ?= arm64 -CROSS_COMPILE ?= ../prebuilt/toolchain/aarch64/bin/aarch64-cros-linux-gnu- -KDIR ?= ../../kernel - -CFLAGS_MODULE = -fno-pic -EXTRA_CFLAGS = $(DHDCFLAGS) -Wframe-larger-than=1312 - -all: - $(warning "DHDFLAGS=$(DHDCFLAGS)") - - $(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules -clean: - $(MAKE) -C $(KDIR) M=$(PWD) ARCH=$(ARCH) clean - rm -fr *.mod.c *.mod *.o .*.cmd *.ko *~ - rm .tmp_versions -fr ; rm Module.symvers -fr - rm -fr Module.markers ; rm -fr modules.order
diff --git a/bcmdhd.1.579.77.41.x/aiutils.c b/bcmdhd.1.579.77.41.x/aiutils.c deleted file mode 100644 index c29cfe4..0000000 --- a/bcmdhd.1.579.77.41.x/aiutils.c +++ /dev/null
@@ -1,1810 +0,0 @@ -/* - * Misc utility routines for accessing chip-specific features - * of the SiliconBackplane-based Broadcom chips. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: aiutils.c 625027 2016-03-15 08:20:18Z $ - */ -#include <bcm_cfg.h> -#include <typedefs.h> -#include <bcmdefs.h> -#include <osl.h> -#include <bcmutils.h> -#include <siutils.h> -#include <hndsoc.h> -#include <sbchipc.h> -#include <pcicfg.h> - -#include "siutils_priv.h" -#include <bcmdevs.h> - -#define BCM5357_DMP() (0) -#define BCM53573_DMP() (0) -#define BCM4707_DMP() (0) -#define PMU_DMP() (0) -#define GCI_DMP() (0) -#define remap_coreid(sih, coreid) (coreid) -#define remap_corerev(sih, corerev) (corerev) - -/* EROM parsing */ - -static uint32 -get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match) -{ - uint32 ent; - uint inv = 0, nom = 0; - uint32 size = 0; - - while (TRUE) { - ent = R_REG(si_osh(sih), *eromptr); - (*eromptr)++; - - if (mask == 0) - break; - - if ((ent & ER_VALID) == 0) { - inv++; - continue; - } - - if (ent == (ER_END | ER_VALID)) - break; - - if ((ent & mask) == match) - break; - - /* escape condition related EROM size if it has invalid values */ - size += sizeof(*eromptr); - if (size >= ER_SZ_MAX) { - SI_ERROR(("Failed to find end of EROM marker\n")); - break; - } - - nom++; - } - - SI_VMSG(("%s: Returning ent 0x%08x\n", __FUNCTION__, ent)); - if (inv + nom) { - SI_VMSG((" after %d invalid and %d non-matching entries\n", inv, nom)); - } - return ent; -} - -static uint32 -get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh, - uint32 *sizel, uint32 *sizeh) -{ - uint32 asd, sz, szd; - - BCM_REFERENCE(ad); - - asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID); - if (((asd & ER_TAG1) != ER_ADD) || - (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) || - ((asd & AD_ST_MASK) != st)) { - /* This is not what we want, "push" it back */ - (*eromptr)--; - return 0; - } - *addrl = asd & AD_ADDR_MASK; - if (asd & AD_AG32) - *addrh = get_erom_ent(sih, eromptr, 0, 0); - else - *addrh = 0; - *sizeh = 0; - sz = asd & AD_SZ_MASK; - if (sz == AD_SZ_SZD) { - szd = get_erom_ent(sih, eromptr, 0, 0); - *sizel = szd & SD_SZ_MASK; - if (szd & SD_SG32) - *sizeh = get_erom_ent(sih, eromptr, 0, 0); - } else - *sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT); - - SI_VMSG((" SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n", - sp, ad, st, *sizeh, *sizel, *addrh, *addrl)); - - return asd; -} - - -/* parse the enumeration rom to identify all cores */ -void -ai_scan(si_t *sih, void *regs, uint devid) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - chipcregs_t *cc = (chipcregs_t *)regs; - uint32 erombase, *eromptr, *eromlim; - axi_wrapper_t * axi_wrapper = sii->axi_wrapper; - - BCM_REFERENCE(devid); - - erombase = R_REG(sii->osh, &cc->eromptr); - - switch (BUSTYPE(sih->bustype)) { - case SI_BUS: - eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); - break; - - case PCI_BUS: - /* Set wrappers address */ - sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE); - - /* Now point the window at the erom */ - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase); - eromptr = regs; - break; - -#ifdef BCMSDIO - case SPI_BUS: - case SDIO_BUS: - eromptr = (uint32 *)(uintptr)erombase; - break; -#endif /* BCMSDIO */ - - case PCMCIA_BUS: - default: - SI_ERROR(("Don't know how to do AXI enumertion on bus %d\n", sih->bustype)); - ASSERT(0); - return; - } - eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); - sii->axi_num_wrappers = 0; - - SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n", - OSL_OBFUSCATE_BUF(regs), erombase, - OSL_OBFUSCATE_BUF(eromptr), OSL_OBFUSCATE_BUF(eromlim))); - while (eromptr < eromlim) { - uint32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; - uint32 mpd, asd, addrl, addrh, sizel, sizeh; - uint i, j, idx; - bool br; - - br = FALSE; - - /* Grok a component */ - cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI); - if (cia == (ER_END | ER_VALID)) { - SI_VMSG(("Found END of erom after %d cores\n", sii->numcores)); - return; - } - - cib = get_erom_ent(sih, &eromptr, 0, 0); - - if ((cib & ER_TAG) != ER_CI) { - SI_ERROR(("CIA not followed by CIB\n")); - goto error; - } - - cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT; - mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT; - crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT; - nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT; - nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT; - nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; - nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; - -#ifdef BCMDBG_SI - SI_VMSG(("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, " - "nsw = %d, nmp = %d & nsp = %d\n", - mfg, cid, crev, OSL_OBFUSCATE_BUF(eromptr - 1), nmw, nsw, nmp, nsp)); -#else - BCM_REFERENCE(crev); -#endif - - if (CHIPID(sih->chip) == BCM4347_CHIP_ID) { - /* 4347 has more entries for ARM core - * This should apply to all chips but crashes on router - * This is a temp fix to be further analyze - */ - if (nsp == 0) - continue; - } else { - /* Include Default slave wrapper for timeout monitoring */ - if ((nsp == 0) || -#if !defined(AXI_TIMEOUTS) && !defined(BCM_BACKPLANE_TIMEOUT) - ((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || -#endif /* !defined(AXI_TIMEOUTS) && !defined(BCM_BACKPLANE_TIMEOUT) */ - FALSE) { - continue; - } - } - - if ((nmw + nsw == 0)) { - /* A component which is not a core */ - if (cid == OOB_ROUTER_CORE_ID) { - asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, - &addrl, &addrh, &sizel, &sizeh); - if (asd != 0) { - sii->oob_router = addrl; - } - } - if (cid != GMAC_COMMON_4706_CORE_ID && cid != NS_CCB_CORE_ID && - cid != PMU_CORE_ID && cid != GCI_CORE_ID) - continue; - } - - idx = sii->numcores; - - cores_info->cia[idx] = cia; - cores_info->cib[idx] = cib; - cores_info->coreid[idx] = remap_coreid(sih, cid); - - for (i = 0; i < nmp; i++) { - mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); - if ((mpd & ER_TAG) != ER_MP) { - SI_ERROR(("Not enough MP entries for component 0x%x\n", cid)); - goto error; - } - SI_VMSG((" Master port %d, mp: %d id: %d\n", i, - (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT, - (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT)); - } - - /* First Slave Address Descriptor should be port 0: - * the main register space for the core - */ - asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); - if (asd == 0) { - do { - /* Try again to see if it is a bridge */ - asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, - &sizel, &sizeh); - if (asd != 0) - br = TRUE; - else { - if (br == TRUE) { - break; - } - else if ((addrh != 0) || (sizeh != 0) || - (sizel != SI_CORE_SIZE)) { - SI_ERROR(("addrh = 0x%x\t sizeh = 0x%x\t size1 =" - "0x%x\n", addrh, sizeh, sizel)); - SI_ERROR(("First Slave ASD for" - "core 0x%04x malformed " - "(0x%08x)\n", cid, asd)); - goto error; - } - } - } while (1); - } - cores_info->coresba[idx] = addrl; - cores_info->coresba_size[idx] = sizel; - /* Get any more ASDs in port 0 */ - j = 1; - do { - asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, - &sizel, &sizeh); - if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) { - cores_info->coresba2[idx] = addrl; - cores_info->coresba2_size[idx] = sizel; - } - j++; - } while (asd != 0); - - /* Go through the ASDs for other slave ports */ - for (i = 1; i < nsp; i++) { - j = 0; - do { - asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh, - &sizel, &sizeh); - - if (asd == 0) - break; - j++; - } while (1); - if (j == 0) { - SI_ERROR((" SP %d has no address descriptors\n", i)); - goto error; - } - } - - /* Now get master wrappers */ - for (i = 0; i < nmw; i++) { - asd = get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, &addrh, - &sizel, &sizeh); - if (asd == 0) { - SI_ERROR(("Missing descriptor for MW %d\n", i)); - goto error; - } - if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { - SI_ERROR(("Master wrapper %d is not 4KB\n", i)); - goto error; - } - if (i == 0) - cores_info->wrapba[idx] = addrl; - else if (i == 1) - cores_info->wrapba2[idx] = addrl; - - - ASSERT(sii->axi_num_wrappers < SI_MAX_AXI_WRAPPERS); - axi_wrapper[sii->axi_num_wrappers].mfg = mfg; - axi_wrapper[sii->axi_num_wrappers].cid = cid; - axi_wrapper[sii->axi_num_wrappers].rev = crev; - axi_wrapper[sii->axi_num_wrappers].wrapper_type = AI_MASTER_WRAPPER; - axi_wrapper[sii->axi_num_wrappers].wrapper_addr = addrl; - sii->axi_num_wrappers++; - SI_VMSG(("MASTER WRAPPER: %d, mfg:%x, cid:%x, rev:%x, addr:%x, size:%x\n", - sii->axi_num_wrappers, mfg, cid, crev, addrl, sizel)); - } - - /* And finally slave wrappers */ - for (i = 0; i < nsw; i++) { - uint fwp = (nsp == 1) ? 0 : 1; - asd = get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, &addrl, &addrh, - &sizel, &sizeh); - - /* cache APB bridge wrapper address for set/clear timeout */ - if ((mfg == MFGID_ARM) && (cid == APB_BRIDGE_ID)) { - ASSERT(sii->num_br < SI_MAXBR); - sii->br_wrapba[sii->num_br++] = addrl; - } - - if (asd == 0) { - SI_ERROR(("Missing descriptor for SW %d\n", i)); - goto error; - } - if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { - SI_ERROR(("Slave wrapper %d is not 4KB\n", i)); - goto error; - } - if ((nmw == 0) && (i == 0)) - cores_info->wrapba[idx] = addrl; - else if ((nmw == 0) && (i == 1)) - cores_info->wrapba2[idx] = addrl; - - /* Include all slave wrappers to the list to - * enable and monitor watchdog timeouts - */ - - ASSERT(sii->axi_num_wrappers < SI_MAX_AXI_WRAPPERS); - axi_wrapper[sii->axi_num_wrappers].mfg = mfg; - axi_wrapper[sii->axi_num_wrappers].cid = cid; - axi_wrapper[sii->axi_num_wrappers].rev = crev; - axi_wrapper[sii->axi_num_wrappers].wrapper_type = AI_SLAVE_WRAPPER; - axi_wrapper[sii->axi_num_wrappers].wrapper_addr = addrl; - sii->axi_num_wrappers++; - - SI_VMSG(("SLAVE WRAPPER: %d, mfg:%x, cid:%x, rev:%x, addr:%x, size:%x\n", - sii->axi_num_wrappers, mfg, cid, crev, addrl, sizel)); - } - - -#ifndef BCM_BACKPLANE_TIMEOUT - /* Don't record bridges */ - if (br) - continue; -#endif - - /* Done with core */ - sii->numcores++; - } - - SI_ERROR(("Reached end of erom without finding END\n")); - -error: - sii->numcores = 0; - return; -} - -#define AI_SETCOREIDX_MAPSIZE(coreid) \ - (((coreid) == NS_CCB_CORE_ID) ? 15 * SI_CORE_SIZE : SI_CORE_SIZE) - -/* This function changes the logical "focus" to the indicated core. - * Return the current core's virtual address. - */ -static volatile void * -_ai_setcoreidx(si_t *sih, uint coreidx, uint use_wrap2) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint32 addr, wrap, wrap2; - volatile void *regs; - - if (coreidx >= MIN(sii->numcores, SI_MAXCORES)) - return (NULL); - - addr = cores_info->coresba[coreidx]; - wrap = cores_info->wrapba[coreidx]; - wrap2 = cores_info->wrapba2[coreidx]; - -#ifdef BCM_BACKPLANE_TIMEOUT - /* No need to disable interrupts while entering/exiting APB bridge core */ - if ((cores_info->coreid[coreidx] != APB_BRIDGE_CORE_ID) && - (cores_info->coreid[sii->curidx] != APB_BRIDGE_CORE_ID)) -#endif /* BCM_BACKPLANE_TIMEOUT */ - { - /* - * If the user has provided an interrupt mask enabled function, - * then assert interrupts are disabled before switching the core. - */ - ASSERT((sii->intrsenabled_fn == NULL) || - !(*(sii)->intrsenabled_fn)((sii)->intr_arg)); - } - - switch (BUSTYPE(sih->bustype)) { - case SI_BUS: - /* map new one */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = REG_MAP(addr, - AI_SETCOREIDX_MAPSIZE(cores_info->coreid[coreidx])); - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - sii->curmap = regs = cores_info->regs[coreidx]; - if (!cores_info->wrappers[coreidx] && (wrap != 0)) { - cores_info->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->wrappers[coreidx])); - } - if (!cores_info->wrappers2[coreidx] && (wrap2 != 0)) { - cores_info->wrappers2[coreidx] = REG_MAP(wrap2, SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->wrappers2[coreidx])); - } - if (use_wrap2) - sii->curwrap = cores_info->wrappers2[coreidx]; - else - sii->curwrap = cores_info->wrappers[coreidx]; - break; - - case PCI_BUS: -#ifdef BCM_BACKPLANE_TIMEOUT - /* No need to set the BAR0 if core is APB Bridge. - * This is to reduce 2 PCI writes while checkng for errlog - */ - if (cores_info->coreid[coreidx] != APB_BRIDGE_CORE_ID) -#endif /* BCM_BACKPLANE_TIMEOUT */ - { - /* point bar0 window */ - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, addr); - } - - regs = sii->curmap; - /* point bar0 2nd 4KB window to the primary wrapper */ - if (use_wrap2) - wrap = wrap2; - if (PCIE_GEN2(sii)) - OSL_PCI_WRITE_CONFIG(sii->osh, PCIE2_BAR0_WIN2, 4, wrap); - else - OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, wrap); - break; - -#ifdef BCMSDIO - case SPI_BUS: - case SDIO_BUS: - sii->curmap = regs = (void *)((uintptr)addr); - if (use_wrap2) - sii->curwrap = (void *)((uintptr)wrap2); - else - sii->curwrap = (void *)((uintptr)wrap); - break; -#endif /* BCMSDIO */ - - case PCMCIA_BUS: - default: - ASSERT(0); - regs = NULL; - break; - } - - sii->curmap = regs; - sii->curidx = coreidx; - - return regs; -} - -volatile void * -ai_setcoreidx(si_t *sih, uint coreidx) -{ - return _ai_setcoreidx(sih, coreidx, 0); -} - -volatile void * -ai_setcoreidx_2ndwrap(si_t *sih, uint coreidx) -{ - return _ai_setcoreidx(sih, coreidx, 1); -} - -void -ai_coreaddrspaceX(si_t *sih, uint asidx, uint32 *addr, uint32 *size) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - chipcregs_t *cc = NULL; - uint32 erombase, *eromptr, *eromlim; - uint i, j, cidx; - uint32 cia, cib, nmp, nsp; - uint32 asd, addrl, addrh, sizel, sizeh; - - for (i = 0; i < sii->numcores; i++) { - if (cores_info->coreid[i] == CC_CORE_ID) { - cc = (chipcregs_t *)cores_info->regs[i]; - break; - } - } - if (cc == NULL) - goto error; - - erombase = R_REG(sii->osh, &cc->eromptr); - eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE); - eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32)); - - cidx = sii->curidx; - cia = cores_info->cia[cidx]; - cib = cores_info->cib[cidx]; - - nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; - nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; - - /* scan for cores */ - while (eromptr < eromlim) { - if ((get_erom_ent(sih, &eromptr, ER_TAG, ER_CI) == cia) && - (get_erom_ent(sih, &eromptr, 0, 0) == cib)) { - break; - } - } - - /* skip master ports */ - for (i = 0; i < nmp; i++) - get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); - - /* Skip ASDs in port 0 */ - asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh); - if (asd == 0) { - /* Try again to see if it is a bridge */ - asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh, - &sizel, &sizeh); - } - - j = 1; - do { - asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh, - &sizel, &sizeh); - j++; - } while (asd != 0); - - /* Go through the ASDs for other slave ports */ - for (i = 1; i < nsp; i++) { - j = 0; - do { - asd = get_asd(sih, &eromptr, i, j, AD_ST_SLAVE, &addrl, &addrh, - &sizel, &sizeh); - if (asd == 0) - break; - - if (!asidx--) { - *addr = addrl; - *size = sizel; - return; - } - j++; - } while (1); - - if (j == 0) { - SI_ERROR((" SP %d has no address descriptors\n", i)); - break; - } - } - -error: - *size = 0; - return; -} - -/* Return the number of address spaces in current core */ -int -ai_numaddrspaces(si_t *sih) -{ - - BCM_REFERENCE(sih); - - return 2; -} - -/* Return the address of the nth address space in the current core */ -uint32 -ai_addrspace(si_t *sih, uint asidx) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint cidx; - - cidx = sii->curidx; - - if (asidx == 0) - return cores_info->coresba[cidx]; - else if (asidx == 1) - return cores_info->coresba2[cidx]; - else { - SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", - __FUNCTION__, asidx)); - return 0; - } -} - -/* Return the size of the nth address space in the current core */ -uint32 -ai_addrspacesize(si_t *sih, uint asidx) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint cidx; - - cidx = sii->curidx; - - if (asidx == 0) - return cores_info->coresba_size[cidx]; - else if (asidx == 1) - return cores_info->coresba2_size[cidx]; - else { - SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", - __FUNCTION__, asidx)); - return 0; - } -} - -uint -ai_flag(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - - if (BCM5357_DMP()) { - SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); - return sii->curidx; - } - if (BCM4707_DMP()) { - SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n", - __FUNCTION__)); - return sii->curidx; - } - if (BCM53573_DMP()) { - SI_ERROR(("%s: Attempting to read DMP registers on 53573\n", __FUNCTION__)); - return sii->curidx; - } -#ifdef REROUTE_OOBINT - if (PMU_DMP()) { - SI_ERROR(("%s: Attempting to read PMU DMP registers\n", - __FUNCTION__)); - return PMU_OOB_BIT; - } -#else - if (PMU_DMP()) { - uint idx, flag; - idx = sii->curidx; - ai_setcoreidx(sih, SI_CC_IDX); - flag = ai_flag_alt(sih); - ai_setcoreidx(sih, idx); - return flag; - } -#endif /* REROUTE_OOBINT */ - - ai = sii->curwrap; - ASSERT(ai != NULL); - - return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f); -} - -uint -ai_flag_alt(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - - if (BCM5357_DMP()) { - SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__)); - return sii->curidx; - } - if (BCM4707_DMP()) { - SI_ERROR(("%s: Attempting to read CHIPCOMMONB DMP registers on 4707\n", - __FUNCTION__)); - return sii->curidx; - } -#ifdef REROUTE_OOBINT - if (PMU_DMP()) { - SI_ERROR(("%s: Attempting to read PMU DMP registers\n", - __FUNCTION__)); - return PMU_OOB_BIT; - } -#endif /* REROUTE_OOBINT */ - - ai = sii->curwrap; - - return ((R_REG(sii->osh, &ai->oobselouta30) >> AI_OOBSEL_1_SHIFT) & AI_OOBSEL_MASK); -} - -void -ai_setint(si_t *sih, int siflag) -{ - BCM_REFERENCE(sih); - BCM_REFERENCE(siflag); - -} - -uint -ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val) -{ - si_info_t *sii = SI_INFO(sih); - uint32 *map = (uint32 *) sii->curwrap; - - if (mask || val) { - uint32 w = R_REG(sii->osh, map+(offset/4)); - w &= ~mask; - w |= val; - W_REG(sii->osh, map+(offset/4), w); - } - - return (R_REG(sii->osh, map+(offset/4))); -} - -uint -ai_corevendor(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint32 cia; - - cia = cores_info->cia[sii->curidx]; - return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT); -} - -uint -ai_corerev(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint32 cib; - - - cib = cores_info->cib[sii->curidx]; - return remap_corerev(sih, (cib & CIB_REV_MASK) >> CIB_REV_SHIFT); -} - -bool -ai_iscoreup(si_t *sih) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - - ai = sii->curwrap; - - return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) && - ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0)); -} - -/* - * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation, - * switch back to the original core, and return the new value. - * - * When using the silicon backplane, no fiddling with interrupts or core switches is needed. - * - * Also, when using pci/pcie, we can optimize away the core switching for pci registers - * and (on newer pci cores) chipcommon registers. - */ -uint -ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val) -{ - uint origidx = 0; - volatile uint32 *r = NULL; - uint w; - uint intr_val = 0; - bool fast = FALSE; - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - - ASSERT(GOODIDX(coreidx)); - ASSERT(regoff < SI_CORE_SIZE); - ASSERT((val & ~mask) == 0); - - if (coreidx >= SI_MAXCORES) - return 0; - - if (BUSTYPE(sih->bustype) == SI_BUS) { - /* If internal bus, we can always get at everything */ - fast = TRUE; - /* map if does not exist */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], - SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - r = (volatile uint32 *)((volatile uchar *)cores_info->regs[coreidx] + regoff); - } else if (BUSTYPE(sih->bustype) == PCI_BUS) { - /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ - - if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { - /* Chipc registers are mapped at 12KB */ - - fast = TRUE; - r = (volatile uint32 *)((volatile char *)sii->curmap + - PCI_16KB0_CCREGS_OFFSET + regoff); - } else if (sii->pub.buscoreidx == coreidx) { - /* pci registers are at either in the last 2KB of an 8KB window - * or, in pcie and pci rev 13 at 8KB - */ - fast = TRUE; - if (SI_FAST(sii)) - r = (volatile uint32 *)((volatile char *)sii->curmap + - PCI_16KB0_PCIREGS_OFFSET + regoff); - else - r = (volatile uint32 *)((volatile char *)sii->curmap + - ((regoff >= SBCONFIGOFF) ? - PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + - regoff); - } - } - - if (!fast) { - INTR_OFF(sii, intr_val); - - /* save current core index */ - origidx = si_coreidx(&sii->pub); - - /* switch core */ - r = (volatile uint32*) ((volatile uchar*) ai_setcoreidx(&sii->pub, coreidx) + - regoff); - } - ASSERT(r != NULL); - - /* mask and set */ - if (mask || val) { - w = (R_REG(sii->osh, r) & ~mask) | val; - W_REG(sii->osh, r, w); - } - - /* readback */ - w = R_REG(sii->osh, r); - - if (!fast) { - /* restore core index */ - if (origidx != coreidx) - ai_setcoreidx(&sii->pub, origidx); - - INTR_RESTORE(sii, intr_val); - } - - return (w); -} - -/* - * If there is no need for fiddling with interrupts or core switches (typically silicon - * back plane registers, pci registers and chipcommon registers), this function - * returns the register offset on this core to a mapped address. This address can - * be used for W_REG/R_REG directly. - * - * For accessing registers that would need a core switch, this function will return - * NULL. - */ -volatile uint32 * -ai_corereg_addr(si_t *sih, uint coreidx, uint regoff) -{ - volatile uint32 *r = NULL; - bool fast = FALSE; - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - - ASSERT(GOODIDX(coreidx)); - ASSERT(regoff < SI_CORE_SIZE); - - if (coreidx >= SI_MAXCORES) - return 0; - - if (BUSTYPE(sih->bustype) == SI_BUS) { - /* If internal bus, we can always get at everything */ - fast = TRUE; - /* map if does not exist */ - if (!cores_info->regs[coreidx]) { - cores_info->regs[coreidx] = REG_MAP(cores_info->coresba[coreidx], - SI_CORE_SIZE); - ASSERT(GOODREGS(cores_info->regs[coreidx])); - } - r = (volatile uint32 *)((volatile uchar *)cores_info->regs[coreidx] + regoff); - } else if (BUSTYPE(sih->bustype) == PCI_BUS) { - /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */ - - if ((cores_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { - /* Chipc registers are mapped at 12KB */ - - fast = TRUE; - r = (volatile uint32 *)((volatile char *)sii->curmap + - PCI_16KB0_CCREGS_OFFSET + regoff); - } else if (sii->pub.buscoreidx == coreidx) { - /* pci registers are at either in the last 2KB of an 8KB window - * or, in pcie and pci rev 13 at 8KB - */ - fast = TRUE; - if (SI_FAST(sii)) - r = (volatile uint32 *)((volatile char *)sii->curmap + - PCI_16KB0_PCIREGS_OFFSET + regoff); - else - r = (volatile uint32 *)((volatile char *)sii->curmap + - ((regoff >= SBCONFIGOFF) ? - PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) + - regoff); - } - } - - if (!fast) { - ASSERT(sii->curidx == coreidx); - r = (volatile uint32*) ((volatile uchar*)sii->curmap + regoff); - } - - return (r); -} - -void -ai_core_disable(si_t *sih, uint32 bits) -{ - si_info_t *sii = SI_INFO(sih); - volatile uint32 dummy; - uint32 status; - aidmp_t *ai; - - - ASSERT(GOODREGS(sii->curwrap)); - ai = sii->curwrap; - - /* if core is already in reset, just return */ - if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) { - return; - } - - /* ensure there are no pending backplane operations */ - SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); - - /* if pending backplane ops still, try waiting longer */ - if (status != 0) { - /* 300usecs was sufficient to allow backplane ops to clear for big hammer */ - /* during driver load we may need more time */ - SPINWAIT(((status = R_REG(sii->osh, &ai->resetstatus)) != 0), 10000); - /* if still pending ops, continue on and try disable anyway */ - /* this is in big hammer path, so don't call wl_reinit in this case... */ - } - - W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); - dummy = R_REG(sii->osh, &ai->resetctrl); - BCM_REFERENCE(dummy); - OSL_DELAY(1); - - W_REG(sii->osh, &ai->ioctrl, bits); - dummy = R_REG(sii->osh, &ai->ioctrl); - BCM_REFERENCE(dummy); - OSL_DELAY(10); -} - -/* reset and re-enable a core - * inputs: - * bits - core specific bits that are set during and after reset sequence - * resetbits - core specific bits that are set only during reset sequence - */ -static void -_ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - volatile uint32 dummy; - uint loop_counter = 10; - - ASSERT(GOODREGS(sii->curwrap)); - ai = sii->curwrap; - - /* if core is already out of reset, just return */ - - /* ensure there are no pending backplane operations */ - SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); - - - /* put core into reset state */ - W_REG(sii->osh, &ai->resetctrl, AIRC_RESET); - OSL_DELAY(10); - - /* ensure there are no pending backplane operations */ - SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); - - W_REG(sii->osh, &ai->ioctrl, (bits | resetbits | SICF_FGC | SICF_CLOCK_EN)); - dummy = R_REG(sii->osh, &ai->ioctrl); - BCM_REFERENCE(dummy); - - /* ensure there are no pending backplane operations */ - SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); - - - while (R_REG(sii->osh, &ai->resetctrl) != 0 && --loop_counter != 0) { - /* ensure there are no pending backplane operations */ - SPINWAIT(((dummy = R_REG(sii->osh, &ai->resetstatus)) != 0), 300); - - - /* take core out of reset */ - W_REG(sii->osh, &ai->resetctrl, 0); - - /* ensure there are no pending backplane operations */ - SPINWAIT((R_REG(sii->osh, &ai->resetstatus) != 0), 300); - } - - - W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN)); - dummy = R_REG(sii->osh, &ai->ioctrl); - BCM_REFERENCE(dummy); - OSL_DELAY(1); -} - -void -ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint idx = sii->curidx; - - if (cores_info->wrapba2[idx] != 0) { - ai_setcoreidx_2ndwrap(sih, idx); - _ai_core_reset(sih, bits, resetbits); - ai_setcoreidx(sih, idx); - } - - _ai_core_reset(sih, bits, resetbits); -} - -void -ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - uint32 w; - - if (BCM5357_DMP()) { - SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", - __FUNCTION__)); - return; - } - if (BCM4707_DMP()) { - SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", - __FUNCTION__)); - return; - } - if (PMU_DMP()) { - SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n", - __FUNCTION__)); - return; - } - - ASSERT(GOODREGS(sii->curwrap)); - ai = sii->curwrap; - - ASSERT((val & ~mask) == 0); - - if (mask || val) { - w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); - W_REG(sii->osh, &ai->ioctrl, w); - } -} - -uint32 -ai_core_cflags(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - uint32 w; - - if (BCM5357_DMP()) { - SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n", - __FUNCTION__)); - return 0; - } - if (BCM4707_DMP()) { - SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", - __FUNCTION__)); - return 0; - } - - if (PMU_DMP()) { - SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n", - __FUNCTION__)); - return 0; - } - ASSERT(GOODREGS(sii->curwrap)); - ai = sii->curwrap; - - ASSERT((val & ~mask) == 0); - - if (mask || val) { - w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val); - W_REG(sii->osh, &ai->ioctrl, w); - } - - return R_REG(sii->osh, &ai->ioctrl); -} - -uint32 -ai_core_sflags(si_t *sih, uint32 mask, uint32 val) -{ - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - uint32 w; - - if (BCM5357_DMP()) { - SI_ERROR(("%s: Accessing USB20H DMP register (iostatus) on 5357\n", - __FUNCTION__)); - return 0; - } - if (BCM4707_DMP()) { - SI_ERROR(("%s: Accessing CHIPCOMMONB DMP register (ioctrl) on 4707\n", - __FUNCTION__)); - return 0; - } - if (PMU_DMP()) { - SI_ERROR(("%s: Accessing PMU DMP register (ioctrl)\n", - __FUNCTION__)); - return 0; - } - - ASSERT(GOODREGS(sii->curwrap)); - ai = sii->curwrap; - - ASSERT((val & ~mask) == 0); - ASSERT((mask & ~SISF_CORE_BITS) == 0); - - if (mask || val) { - w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val); - W_REG(sii->osh, &ai->iostatus, w); - } - - return R_REG(sii->osh, &ai->iostatus); -} - -#if defined(BCMDBG_PHYDUMP) -/* print interesting aidmp registers */ -void -ai_dumpregs(si_t *sih, struct bcmstrbuf *b) -{ - si_info_t *sii = SI_INFO(sih); - osl_t *osh; - aidmp_t *ai; - uint i; - uint32 prev_value = 0; - axi_wrapper_t * axi_wrapper = sii->axi_wrapper; - uint32 cfg_reg = 0; - uint bar0_win_offset = 0; - - osh = sii->osh; - - - /* Save and restore wrapper access window */ - if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { - if (PCIE_GEN2(sii)) { - cfg_reg = PCIE2_BAR0_CORE2_WIN2; - bar0_win_offset = PCIE2_BAR0_CORE2_WIN2_OFFSET; - } else { - cfg_reg = PCI_BAR0_WIN2; - bar0_win_offset = PCI_BAR0_WIN2_OFFSET; - } - - prev_value = OSL_PCI_READ_CONFIG(osh, cfg_reg, 4); - - if (prev_value == ID32_INVALID) { - SI_PRINT(("%s, PCI_BAR0_WIN2 - %x\n", __FUNCTION__, prev_value)); - return; - } - } - - bcm_bprintf(b, "ChipNum:%x, ChipRev;%x, BusType:%x, BoardType:%x, BoardVendor:%x\n\n", - sih->chip, sih->chiprev, sih->bustype, sih->boardtype, sih->boardvendor); - - for (i = 0; i < sii->axi_num_wrappers; i++) { - - if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { - /* Set BAR0 window to bridge wapper base address */ - OSL_PCI_WRITE_CONFIG(osh, - cfg_reg, 4, axi_wrapper[i].wrapper_addr); - - ai = (aidmp_t *) ((volatile uint8*)sii->curmap + bar0_win_offset); - } else { - ai = (aidmp_t *)(uintptr) axi_wrapper[i].wrapper_addr; - } - - bcm_bprintf(b, "core 0x%x: core_rev:%d, %s_WR ADDR:%x \n", axi_wrapper[i].cid, - axi_wrapper[i].rev, - axi_wrapper[i].wrapper_type == AI_SLAVE_WRAPPER ? "SLAVE" : "MASTER", - axi_wrapper[i].wrapper_addr); - - /* BCM5357_DMP() */ - if (((CHIPID(sih->chip) == BCM5357_CHIP_ID) || - (CHIPID(sih->chip) == BCM4749_CHIP_ID)) && - (sih->chippkg == BCM5357_PKG_ID) && - (axi_wrapper[i].cid == USB20H_CORE_ID)) { - bcm_bprintf(b, "Skipping usb20h in 5357\n"); - continue; - } - - /* BCM4707_DMP() */ - if (BCM4707_CHIP(CHIPID(sih->chip)) && - (axi_wrapper[i].cid == NS_CCB_CORE_ID)) { - bcm_bprintf(b, "Skipping chipcommonb in 4707\n"); - continue; - } - - bcm_bprintf(b, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x " - "ioctrlwidth 0x%x iostatuswidth 0x%x\n" - "resetctrl 0x%x resetstatus 0x%x resetreadid 0x%x resetwriteid 0x%x\n" - "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x " - "errlogaddrlo 0x%x errlogaddrhi 0x%x\n" - "errlogid 0x%x errloguser 0x%x errlogflags 0x%x\n" - "intstatus 0x%x config 0x%x itcr 0x%x\n\n", - R_REG(osh, &ai->ioctrlset), - R_REG(osh, &ai->ioctrlclear), - R_REG(osh, &ai->ioctrl), - R_REG(osh, &ai->iostatus), - R_REG(osh, &ai->ioctrlwidth), - R_REG(osh, &ai->iostatuswidth), - R_REG(osh, &ai->resetctrl), - R_REG(osh, &ai->resetstatus), - R_REG(osh, &ai->resetreadid), - R_REG(osh, &ai->resetwriteid), - R_REG(osh, &ai->errlogctrl), - R_REG(osh, &ai->errlogdone), - R_REG(osh, &ai->errlogstatus), - R_REG(osh, &ai->errlogaddrlo), - R_REG(osh, &ai->errlogaddrhi), - R_REG(osh, &ai->errlogid), - R_REG(osh, &ai->errloguser), - R_REG(osh, &ai->errlogflags), - R_REG(osh, &ai->intstatus), - R_REG(osh, &ai->config), - R_REG(osh, &ai->itcr)); - } - - /* Restore the initial wrapper space */ - if (prev_value && cfg_reg) { - OSL_PCI_WRITE_CONFIG(osh, cfg_reg, 4, prev_value); - } - -} -#endif - - -void -ai_enable_backplane_timeouts(si_t *sih) -{ -#if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT) - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - uint32 i; - axi_wrapper_t * axi_wrapper = sii->axi_wrapper; - -#ifdef BCM_BACKPLANE_TIMEOUT - uint32 prev_value = 0; - osl_t *osh = sii->osh; - uint32 cfg_reg = 0; - uint32 offset = 0; -#endif /* BCM_BACKPLANE_TIMEOUT */ - - if ((sii->axi_num_wrappers == 0) || -#ifdef BCM_BACKPLANE_TIMEOUT - (!PCIE(sii)) || -#endif /* BCM_BACKPLANE_TIMEOUT */ - FALSE) { - SI_VMSG((" %s, axi_num_wrappers:%d, Is_PCIE:%d, BUS_TYPE:%d, ID:%x\n", - __FUNCTION__, sii->axi_num_wrappers, PCIE(sii), - BUSTYPE(sii->pub.bustype), sii->pub.buscoretype)); - return; - } - -#ifdef BCM_BACKPLANE_TIMEOUT - /* Save and restore the wrapper access window */ - if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { - if (PCIE_GEN1(sii)) { - cfg_reg = PCI_BAR0_WIN2; - offset = PCI_BAR0_WIN2_OFFSET; - } else if (PCIE_GEN2(sii)) { - cfg_reg = PCIE2_BAR0_CORE2_WIN2; - offset = PCIE2_BAR0_CORE2_WIN2_OFFSET; - } - else { - osl_panic("!PCIE_GEN1 && !PCIE_GEN2\n"); - } - - prev_value = OSL_PCI_READ_CONFIG(osh, cfg_reg, 4); - if (prev_value == ID32_INVALID) { - SI_PRINT(("%s, PCI_BAR0_WIN2 - %x\n", __FUNCTION__, prev_value)); - return; - } - } - -#endif /* BCM_BACKPLANE_TIMEOUT */ - - for (i = 0; i < sii->axi_num_wrappers; ++i) { - - if (axi_wrapper[i].wrapper_type != AI_SLAVE_WRAPPER) { - SI_VMSG(("SKIP ENABLE BPT: MFG:%x, CID:%x, ADDR:%x\n", - axi_wrapper[i].mfg, - axi_wrapper[i].cid, - axi_wrapper[i].wrapper_addr)); - continue; - } - -#ifdef BCM_BACKPLANE_TIMEOUT - if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { - /* Set BAR0_CORE2_WIN2 to wapper base address */ - OSL_PCI_WRITE_CONFIG(osh, - cfg_reg, 4, axi_wrapper[i].wrapper_addr); - - /* set AI to BAR0 + Offset corresponding to Gen1 or gen2 */ - ai = (aidmp_t *) ((uint8*)sii->curmap + offset); - } - else -#endif /* BCM_BACKPLANE_TIMEOUT */ - { - ai = (aidmp_t *)(uintptr) axi_wrapper[i].wrapper_addr; - } - - W_REG(sii->osh, &ai->errlogctrl, (1 << AIELC_TO_ENAB_SHIFT) | - ((AXI_TO_VAL << AIELC_TO_EXP_SHIFT) & AIELC_TO_EXP_MASK)); - - SI_VMSG(("ENABLED BPT: MFG:%x, CID:%x, ADDR:%x, ERR_CTRL:%x\n", - axi_wrapper[i].mfg, - axi_wrapper[i].cid, - axi_wrapper[i].wrapper_addr, - R_REG(sii->osh, &ai->errlogctrl))); - } - -#ifdef BCM_BACKPLANE_TIMEOUT - /* Restore the initial wrapper space */ - if (prev_value) { - OSL_PCI_WRITE_CONFIG(osh, cfg_reg, 4, prev_value); - } -#endif /* BCM_BACKPLANE_TIMEOUT */ - -#endif /* AXI_TIMEOUTS || BCM_BACKPLANE_TIMEOUT */ -} - -#if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT) - -/* slave error is ignored, so account for those cases */ -static uint32 si_ignore_errlog_cnt = 0; - -static bool -ai_ignore_errlog(si_info_t *sii, uint32 lo_addr, uint32 hi_addr, uint32 err_axi_id, uint32 errsts) -{ - uint32 axi_id; - - /* ignore the BT slave errors if the errlog is to chipcommon addr 0x190 */ - switch (CHIPID(sii->pub.chip)) { - case BCM4350_CHIP_ID: - axi_id = BCM4350_BT_AXI_ID; - break; - case BCM4345_CHIP_ID: - axi_id = BCM4345_BT_AXI_ID; - break; - default: - return FALSE; - } - - /* AXI ID check */ - if ((err_axi_id & AI_ERRLOGID_AXI_ID_MASK) != axi_id) - return FALSE; - - /* slave errors */ - if ((errsts & AIELS_TIMEOUT_MASK) != AIELS_SLAVE_ERR) - return FALSE; - - /* chipc reg 0x190 */ - if ((hi_addr != BT_CC_SPROM_BADREG_HI) || (lo_addr != BT_CC_SPROM_BADREG_LO)) - return FALSE; - - return TRUE; -} -#endif /* defined (AXI_TIMEOUTS) || defined (BCM_BACKPLANE_TIMEOUT) */ - -#ifdef BCM_BACKPLANE_TIMEOUT - -/* Function to return the APB bridge details corresponding to the core */ -bool -ai_get_apb_bridge(si_t * sih, uint32 coreidx, uint32 *apb_id, uint32 * apb_coreuinit) -{ - uint i; - uint32 core_base, core_end; - si_info_t *sii = SI_INFO(sih); - static uint32 coreidx_cached = 0, apb_id_cached = 0, apb_coreunit_cached = 0; - uint32 tmp_coreunit = 0; - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - - if (coreidx >= MIN(sii->numcores, SI_MAXCORES)) - return FALSE; - - /* Most of the time apb bridge query will be for d11 core. - * Maintain the last cache and return if found rather than iterating the table - */ - if (coreidx_cached == coreidx) { - *apb_id = apb_id_cached; - *apb_coreuinit = apb_coreunit_cached; - return TRUE; - } - - core_base = cores_info->coresba[coreidx]; - core_end = core_base + cores_info->coresba_size[coreidx]; - - for (i = 0; i < sii->numcores; i++) { - if (cores_info->coreid[i] == APB_BRIDGE_ID) { - uint32 apb_base; - uint32 apb_end; - - apb_base = cores_info->coresba[i]; - apb_end = apb_base + cores_info->coresba_size[i]; - - if ((core_base >= apb_base) && - (core_end <= apb_end)) { - /* Current core is attached to this APB bridge */ - *apb_id = apb_id_cached = APB_BRIDGE_ID; - *apb_coreuinit = apb_coreunit_cached = tmp_coreunit; - coreidx_cached = coreidx; - return TRUE; - } - /* Increment the coreunit */ - tmp_coreunit++; - } - } - - return FALSE; -} - -uint32 -ai_clear_backplane_to_fast(si_t *sih, void * addr) -{ - si_info_t *sii = SI_INFO(sih); - void * curmap = sii->curmap; - bool core_reg = FALSE; - - /* Use fast path only for core register access */ - if ((addr >= curmap) && (addr < (curmap + SI_CORE_SIZE))) { - /* address being accessed is within current core reg map */ - core_reg = TRUE; - } - - if (core_reg) { - uint32 apb_id, apb_coreuinit; - - if (ai_get_apb_bridge(sih, si_coreidx(&sii->pub), - &apb_id, &apb_coreuinit) == TRUE) { - /* Found the APB bridge corresponding to current core, - * Check for bus errors in APB wrapper - */ - return ai_clear_backplane_to_per_core(sih, - apb_id, apb_coreuinit, NULL); - } - } - - /* Default is to poll for errors on all slave wrappers */ - return si_clear_backplane_to(sih); -} -#endif /* BCM_BACKPLANE_TIMEOUT */ - -#if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT) -/* - * API to clear the back plane timeout per core. - * Caller may passs optional wrapper address. If present this will be used as - * the wrapper base address. If wrapper base address is provided then caller - * must provide the coreid also. - * If both coreid and wrapper is zero, then err status of current bridge - * will be verified. - */ -uint32 -ai_clear_backplane_to_per_core(si_t *sih, uint coreid, uint coreunit, void * wrap) -{ - int ret = AXI_WRAP_STS_NONE; - aidmp_t *ai = NULL; - uint32 errlog_status = 0; - si_info_t *sii = SI_INFO(sih); - uint32 errlog_lo = 0, errlog_hi = 0, errlog_id = 0, errlog_flags = 0; - uint32 current_coreidx = si_coreidx(sih); - uint32 target_coreidx = si_findcoreidx(sih, coreid, coreunit); - -#if defined(BCM_BACKPLANE_TIMEOUT) - si_axi_error_t * axi_error = &sih->err_info->axi_error[sih->err_info->count]; -#endif /* BCM_BACKPLANE_TIMEOUT */ - bool restore_core = FALSE; - - if ((sii->axi_num_wrappers == 0) || -#ifdef BCM_BACKPLANE_TIMEOUT - (!PCIE(sii)) || -#endif /* BCM_BACKPLANE_TIMEOUT */ - FALSE) { - SI_VMSG((" %s, axi_num_wrappers:%d, Is_PCIE:%d, BUS_TYPE:%d, ID:%x\n", - __FUNCTION__, sii->axi_num_wrappers, PCIE(sii), - BUSTYPE(sii->pub.bustype), sii->pub.buscoretype)); - return AXI_WRAP_STS_NONE; - } - - if (wrap != NULL) { - ai = (aidmp_t *)wrap; - } else if (coreid && (target_coreidx != current_coreidx)) { - - if (ai_setcoreidx(sih, target_coreidx) == NULL) { - /* Unable to set the core */ - SI_PRINT(("Set Code Failed: coreid:%x, unit:%d, target_coreidx:%d\n", - coreid, coreunit, target_coreidx)); - errlog_lo = target_coreidx; - ret = AXI_WRAP_STS_SET_CORE_FAIL; - goto end; - } - - restore_core = TRUE; - ai = (aidmp_t *)si_wrapperregs(sih); - } else { - /* Read error status of current wrapper */ - ai = (aidmp_t *)si_wrapperregs(sih); - - /* Update CoreID to current Code ID */ - coreid = si_coreid(sih); - } - - /* read error log status */ - errlog_status = R_REG(sii->osh, &ai->errlogstatus); - - if (errlog_status == ID32_INVALID) { - /* Do not try to peek further */ - SI_PRINT(("%s, errlogstatus:%x - Slave Wrapper:%x\n", - __FUNCTION__, errlog_status, coreid)); - ret = AXI_WRAP_STS_WRAP_RD_ERR; - errlog_lo = (uint32)&ai->errlogstatus; - goto end; - } - - if ((errlog_status & AIELS_TIMEOUT_MASK) != 0) { - uint32 tmp; - uint32 count = 0; - /* set ErrDone to clear the condition */ - W_REG(sii->osh, &ai->errlogdone, AIELD_ERRDONE_MASK); - - /* SPINWAIT on errlogstatus timeout status bits */ - while ((tmp = R_REG(sii->osh, &ai->errlogstatus)) & AIELS_TIMEOUT_MASK) { - - if (tmp == ID32_INVALID) { - SI_PRINT(("%s: prev errlogstatus:%x, errlogstatus:%x\n", - __FUNCTION__, errlog_status, tmp)); - ret = AXI_WRAP_STS_WRAP_RD_ERR; - errlog_lo = (uint32)&ai->errlogstatus; - goto end; - } - /* - * Clear again, to avoid getting stuck in the loop, if a new error - * is logged after we cleared the first timeout - */ - W_REG(sii->osh, &ai->errlogdone, AIELD_ERRDONE_MASK); - - count++; - OSL_DELAY(10); - if ((10 * count) > AI_REG_READ_TIMEOUT) { - errlog_status = tmp; - break; - } - } - - errlog_lo = R_REG(sii->osh, &ai->errlogaddrlo); - errlog_hi = R_REG(sii->osh, &ai->errlogaddrhi); - errlog_id = R_REG(sii->osh, &ai->errlogid); - errlog_flags = R_REG(sii->osh, &ai->errlogflags); - - /* we are already in the error path, so OK to check for the slave error */ - if (ai_ignore_errlog(sii, errlog_lo, errlog_hi, errlog_id, - errlog_status)) { - si_ignore_errlog_cnt++; - goto end; - } - - /* only reset APB Bridge on timeout (not slave error, or dec error) */ - switch (errlog_status & AIELS_TIMEOUT_MASK) { - case AIELS_SLAVE_ERR: - SI_PRINT(("AXI slave error")); - ret = AXI_WRAP_STS_SLAVE_ERR; - break; - - case AIELS_TIMEOUT: - /* reset APB Bridge */ - OR_REG(sii->osh, &ai->resetctrl, AIRC_RESET); - /* sync write */ - (void)R_REG(sii->osh, &ai->resetctrl); - /* clear Reset bit */ - AND_REG(sii->osh, &ai->resetctrl, ~(AIRC_RESET)); - /* sync write */ - (void)R_REG(sii->osh, &ai->resetctrl); - SI_PRINT(("AXI timeout")); - ret = AXI_WRAP_STS_TIMEOUT; - break; - - case AIELS_DECODE: - SI_PRINT(("AXI decode error")); - ret = AXI_WRAP_STS_DECODE_ERR; - break; - default: - ASSERT(0); /* should be impossible */ - } - - SI_PRINT(("\tCoreID: %x\n", coreid)); - SI_PRINT(("\t errlog: lo 0x%08x, hi 0x%08x, id 0x%08x, flags 0x%08x" - ", status 0x%08x\n", - errlog_lo, errlog_hi, errlog_id, errlog_flags, - errlog_status)); - } - -end: - -#if defined(BCM_BACKPLANE_TIMEOUT) - if (axi_error && (ret != AXI_WRAP_STS_NONE)) { - axi_error->error = ret; - axi_error->coreid = coreid; - axi_error->errlog_lo = errlog_lo; - axi_error->errlog_hi = errlog_hi; - axi_error->errlog_id = errlog_id; - axi_error->errlog_flags = errlog_flags; - axi_error->errlog_status = errlog_status; - sih->err_info->count++; - - if (sih->err_info->count == SI_MAX_ERRLOG_SIZE) { - sih->err_info->count = SI_MAX_ERRLOG_SIZE - 1; - SI_PRINT(("AXI Error log overflow\n")); - } - } -#endif /* BCM_BACKPLANE_TIMEOUT */ - - if (restore_core) { - if (ai_setcoreidx(sih, current_coreidx) == NULL) { - /* Unable to set the core */ - return ID32_INVALID; - } - } - - return ret; -} -#endif /* AXI_TIMEOUTS || BCM_BACKPLANE_TIMEOUT */ - -/* - * This API polls all slave wrappers for errors and returns bit map of - * all reported errors. - * return - bit map of - * AXI_WRAP_STS_NONE - * AXI_WRAP_STS_TIMEOUT - * AXI_WRAP_STS_SLAVE_ERR - * AXI_WRAP_STS_DECODE_ERR - * AXI_WRAP_STS_PCI_RD_ERR - * AXI_WRAP_STS_WRAP_RD_ERR - * AXI_WRAP_STS_SET_CORE_FAIL - * On timeout detection, correspondign bridge will be reset to - * unblock the bus. - * Error reported in each wrapper can be retrieved using the API - * si_get_axi_errlog_info() - */ -uint32 -ai_clear_backplane_to(si_t *sih) -{ - uint32 ret = 0; -#if defined(AXI_TIMEOUTS) || defined(BCM_BACKPLANE_TIMEOUT) - - si_info_t *sii = SI_INFO(sih); - aidmp_t *ai; - uint32 i; - axi_wrapper_t * axi_wrapper = sii->axi_wrapper; - -#ifdef BCM_BACKPLANE_TIMEOUT - uint32 prev_value = 0; - osl_t *osh = sii->osh; - uint32 cfg_reg = 0; - uint32 offset = 0; - - if ((sii->axi_num_wrappers == 0) || (!PCIE(sii))) -#else - if (sii->axi_num_wrappers == 0) -#endif - { - SI_VMSG((" %s, axi_num_wrappers:%d, Is_PCIE:%d, BUS_TYPE:%d, ID:%x\n", - __FUNCTION__, sii->axi_num_wrappers, PCIE(sii), - BUSTYPE(sii->pub.bustype), sii->pub.buscoretype)); - return AXI_WRAP_STS_NONE; - } - -#ifdef BCM_BACKPLANE_TIMEOUT - /* Save and restore wrapper access window */ - if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { - if (PCIE_GEN1(sii)) { - cfg_reg = PCI_BAR0_WIN2; - offset = PCI_BAR0_WIN2_OFFSET; - } else if (PCIE_GEN2(sii)) { - cfg_reg = PCIE2_BAR0_CORE2_WIN2; - offset = PCIE2_BAR0_CORE2_WIN2_OFFSET; - } - else { - osl_panic("!PCIE_GEN1 && !PCIE_GEN2\n"); - } - - prev_value = OSL_PCI_READ_CONFIG(osh, cfg_reg, 4); - - if (prev_value == ID32_INVALID) { - si_axi_error_t * axi_error = - &sih->err_info->axi_error[sih->err_info->count]; - SI_PRINT(("%s, PCI_BAR0_WIN2 - %x\n", __FUNCTION__, prev_value)); - - axi_error->error = ret = AXI_WRAP_STS_PCI_RD_ERR; - axi_error->errlog_lo = cfg_reg; - sih->err_info->count++; - - if (sih->err_info->count == SI_MAX_ERRLOG_SIZE) { - sih->err_info->count = SI_MAX_ERRLOG_SIZE - 1; - SI_PRINT(("AXI Error log overflow\n")); - } - - return ret; - } - } -#endif /* BCM_BACKPLANE_TIMEOUT */ - - for (i = 0; i < sii->axi_num_wrappers; ++i) { - uint32 tmp; - - if (axi_wrapper[i].wrapper_type != AI_SLAVE_WRAPPER) { - continue; - } - -#ifdef BCM_BACKPLANE_TIMEOUT - - if (BUSTYPE(sii->pub.bustype) == PCI_BUS) { - /* Set BAR0_CORE2_WIN2 to bridge wapper base address */ - OSL_PCI_WRITE_CONFIG(osh, - cfg_reg, 4, axi_wrapper[i].wrapper_addr); - - /* set AI to BAR0 + Offset corresponding to Gen1 or gen2 */ - ai = (aidmp_t *) ((uint8*)sii->curmap + offset); - } - else -#endif /* BCM_BACKPLANE_TIMEOUT */ - { - ai = (aidmp_t *)(uintptr) axi_wrapper[i].wrapper_addr; - } - - tmp = ai_clear_backplane_to_per_core(sih, axi_wrapper[i].cid, 0, (void*)ai); - - ret |= tmp; - } - -#ifdef BCM_BACKPLANE_TIMEOUT - /* Restore the initial wrapper space */ - if (prev_value) { - OSL_PCI_WRITE_CONFIG(osh, cfg_reg, 4, prev_value); - } -#endif /* BCM_BACKPLANE_TIMEOUT */ - -#endif /* AXI_TIMEOUTS || BCM_BACKPLANE_TIMEOUT */ - - return ret; -} - -uint -ai_num_slaveports(si_t *sih, uint coreidx) -{ - si_info_t *sii = SI_INFO(sih); - si_cores_info_t *cores_info = (si_cores_info_t *)sii->cores_info; - uint32 cib; - - cib = cores_info->cib[coreidx]; - return ((cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT); -}
diff --git a/bcmdhd.1.579.77.41.x/bcm_app_utils.c b/bcmdhd.1.579.77.41.x/bcm_app_utils.c deleted file mode 100644 index a5a7a5b..0000000 --- a/bcmdhd.1.579.77.41.x/bcm_app_utils.c +++ /dev/null
@@ -1,1015 +0,0 @@ -/* - * Misc utility routines used by kernel or app-level. - * Contents are wifi-specific, used by any kernel or app-level - * software that might want wifi things as it grows. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * 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_app_utils.c 623866 2016-03-09 11:58:34Z $ - */ - -#include <typedefs.h> - -#ifdef BCMDRIVER -#include <osl.h> -#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) -#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) -#else /* BCMDRIVER */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#ifndef ASSERT -#define ASSERT(exp) -#endif -#endif /* BCMDRIVER */ -#include <bcmwifi_channels.h> - -#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL)) -#include <bcmstdlib.h> /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */ -#endif - -#include <bcmutils.h> -#include <wlioctl.h> -#include <wlioctl_utils.h> - -#ifndef BCMDRIVER -/* Take an array of measurments representing a single channel over time and return - a summary. Currently implemented as a simple average but could easily evolve - into more cpomplex alogrithms. -*/ -cca_congest_channel_req_t * -cca_per_chan_summary(cca_congest_channel_req_t *input, cca_congest_channel_req_t *avg, bool percent) -{ - int sec; - cca_congest_t totals; - - totals.duration = 0; - totals.congest_ibss = 0; - totals.congest_obss = 0; - totals.interference = 0; - avg->num_secs = 0; - - for (sec = 0; sec < input->num_secs; sec++) { - if (input->secs[sec].duration) { - totals.duration += input->secs[sec].duration; - totals.congest_ibss += input->secs[sec].congest_ibss; - totals.congest_obss += input->secs[sec].congest_obss; - totals.interference += input->secs[sec].interference; - avg->num_secs++; - } - } - avg->chanspec = input->chanspec; - - if (!avg->num_secs || !totals.duration) - return (avg); - - if (percent) { - avg->secs[0].duration = totals.duration / avg->num_secs; - avg->secs[0].congest_ibss = totals.congest_ibss * 100/totals.duration; - avg->secs[0].congest_obss = totals.congest_obss * 100/totals.duration; - avg->secs[0].interference = totals.interference * 100/totals.duration; - } else { - avg->secs[0].duration = totals.duration / avg->num_secs; - avg->secs[0].congest_ibss = totals.congest_ibss / avg->num_secs; - avg->secs[0].congest_obss = totals.congest_obss / avg->num_secs; - avg->secs[0].interference = totals.interference / avg->num_secs; - } - - return (avg); -} - -static void -cca_info(uint8 *bitmap, int num_bits, int *left, int *bit_pos) -{ - int i; - for (*left = 0, i = 0; i < num_bits; i++) { - if (isset(bitmap, i)) { - (*left)++; - *bit_pos = i; - } - } -} - -static uint8 -spec_to_chan(chanspec_t chspec) -{ - uint8 center_ch, edge, primary, sb; - - center_ch = CHSPEC_CHANNEL(chspec); - - if (CHSPEC_BW_LE20(chspec)) { - return center_ch; - } else { - /* the lower edge of the wide channel is half the bw from - * the center channel. - */ - if (CHSPEC_IS40(chspec)) { - edge = center_ch - CH_20MHZ_APART; - } else { - /* must be 80MHz (until we support more) */ - ASSERT(CHSPEC_IS80(chspec)); - edge = center_ch - CH_40MHZ_APART; - } - - /* find the channel number of the lowest 20MHz primary channel */ - primary = edge + CH_10MHZ_APART; - - /* select the actual subband */ - sb = (chspec & WL_CHANSPEC_CTL_SB_MASK) >> WL_CHANSPEC_CTL_SB_SHIFT; - primary = primary + sb * CH_20MHZ_APART; - - return primary; - } -} - -/* - Take an array of measumrements representing summaries of different channels. - Return a recomended channel. - Interference is evil, get rid of that first. - Then hunt for lowest Other bss traffic. - Don't forget that channels with low duration times may not have accurate readings. - For the moment, do not overwrite input array. -*/ -int -cca_analyze(cca_congest_channel_req_t *input[], int num_chans, uint flags, chanspec_t *answer) -{ - uint8 *bitmap = NULL; /* 38 Max channels needs 5 bytes = 40 */ - int i, left, winner, ret_val = 0; - uint32 min_obss = 1 << 30; - uint bitmap_sz; - - bitmap_sz = CEIL(num_chans, NBBY); - bitmap = (uint8 *)malloc(bitmap_sz); - if (bitmap == NULL) { - printf("unable to allocate memory\n"); - return BCME_NOMEM; - } - - memset(bitmap, 0, bitmap_sz); - /* Initially, all channels are up for consideration */ - for (i = 0; i < num_chans; i++) { - if (input[i]->chanspec) - setbit(bitmap, i); - } - cca_info(bitmap, num_chans, &left, &i); - if (!left) { - ret_val = CCA_ERRNO_TOO_FEW; - goto f_exit; - } - - /* Filter for 2.4 GHz Band */ - if (flags & CCA_FLAG_2G_ONLY) { - for (i = 0; i < num_chans; i++) { - if (!CHSPEC_IS2G(input[i]->chanspec)) - clrbit(bitmap, i); - } - } - cca_info(bitmap, num_chans, &left, &i); - if (!left) { - ret_val = CCA_ERRNO_BAND; - goto f_exit; - } - - /* Filter for 5 GHz Band */ - if (flags & CCA_FLAG_5G_ONLY) { - for (i = 0; i < num_chans; i++) { - if (!CHSPEC_IS5G(input[i]->chanspec)) - clrbit(bitmap, i); - } - } - cca_info(bitmap, num_chans, &left, &i); - if (!left) { - ret_val = CCA_ERRNO_BAND; - goto f_exit; - } - - /* Filter for Duration */ - if (!(flags & CCA_FLAG_IGNORE_DURATION)) { - for (i = 0; i < num_chans; i++) { - if (input[i]->secs[0].duration < CCA_THRESH_MILLI) - clrbit(bitmap, i); - } - } - cca_info(bitmap, num_chans, &left, &i); - if (!left) { - ret_val = CCA_ERRNO_DURATION; - goto f_exit; - } - - /* Filter for 1 6 11 on 2.4 Band */ - if (flags & CCA_FLAGS_PREFER_1_6_11) { - int tmp_channel = spec_to_chan(input[i]->chanspec); - int is2g = CHSPEC_IS2G(input[i]->chanspec); - for (i = 0; i < num_chans; i++) { - if (is2g && tmp_channel != 1 && tmp_channel != 6 && tmp_channel != 11) - clrbit(bitmap, i); - } - } - cca_info(bitmap, num_chans, &left, &i); - if (!left) { - ret_val = CCA_ERRNO_PREF_CHAN; - goto f_exit; - } - - /* Toss high interference interference */ - if (!(flags & CCA_FLAG_IGNORE_INTERFER)) { - for (i = 0; i < num_chans; i++) { - if (input[i]->secs[0].interference > CCA_THRESH_INTERFERE) - clrbit(bitmap, i); - } - cca_info(bitmap, num_chans, &left, &i); - if (!left) { - ret_val = CCA_ERRNO_INTERFER; - goto f_exit; - } - } - - /* Now find lowest obss */ - winner = 0; - for (i = 0; i < num_chans; i++) { - if (isset(bitmap, i) && input[i]->secs[0].congest_obss < min_obss) { - winner = i; - min_obss = input[i]->secs[0].congest_obss; - } - } - *answer = input[winner]->chanspec; - f_exit: - free(bitmap); /* free the allocated memory for bitmap */ - return ret_val; -} -#endif /* !BCMDRIVER */ - -/* offset of cntmember by sizeof(uint32) from the first cnt variable, txframe. */ -#define IDX_IN_WL_CNT_VER_6_T(cntmember) \ - ((OFFSETOF(wl_cnt_ver_6_t, cntmember) - OFFSETOF(wl_cnt_ver_6_t, txframe)) / sizeof(uint32)) - -#define IDX_IN_WL_CNT_VER_11_T(cntmember) \ - ((OFFSETOF(wl_cnt_ver_11_t, cntmember) - OFFSETOF(wl_cnt_ver_11_t, txframe)) \ - / sizeof(uint32)) - -/* Exclude version and length fields */ -#define NUM_OF_CNT_IN_WL_CNT_VER_6_T \ - ((sizeof(wl_cnt_ver_6_t) - 2 * sizeof(uint16)) / sizeof(uint32)) -/* Exclude macstat cnt variables. wl_cnt_ver_6_t only has 62 macstat cnt variables. */ -#define NUM_OF_WLCCNT_IN_WL_CNT_VER_6_T \ - (NUM_OF_CNT_IN_WL_CNT_VER_6_T - (WL_CNT_MCST_VAR_NUM - 2)) - -/* Exclude version and length fields */ -#define NUM_OF_CNT_IN_WL_CNT_VER_11_T \ - ((sizeof(wl_cnt_ver_11_t) - 2 * sizeof(uint16)) / sizeof(uint32)) -/* Exclude 64 macstat cnt variables. */ -#define NUM_OF_WLCCNT_IN_WL_CNT_VER_11_T \ - (NUM_OF_CNT_IN_WL_CNT_VER_11_T - WL_CNT_MCST_VAR_NUM) - -/* Index conversion table from wl_cnt_ver_6_t to wl_cnt_wlc_t */ -static const uint8 wlcntver6t_to_wlcntwlct[NUM_OF_WLCCNT_IN_WL_CNT_VER_6_T] = { - IDX_IN_WL_CNT_VER_6_T(txframe), - IDX_IN_WL_CNT_VER_6_T(txbyte), - IDX_IN_WL_CNT_VER_6_T(txretrans), - IDX_IN_WL_CNT_VER_6_T(txerror), - IDX_IN_WL_CNT_VER_6_T(txctl), - IDX_IN_WL_CNT_VER_6_T(txprshort), - IDX_IN_WL_CNT_VER_6_T(txserr), - IDX_IN_WL_CNT_VER_6_T(txnobuf), - IDX_IN_WL_CNT_VER_6_T(txnoassoc), - IDX_IN_WL_CNT_VER_6_T(txrunt), - IDX_IN_WL_CNT_VER_6_T(txchit), - IDX_IN_WL_CNT_VER_6_T(txcmiss), - IDX_IN_WL_CNT_VER_6_T(txuflo), - IDX_IN_WL_CNT_VER_6_T(txphyerr), - IDX_IN_WL_CNT_VER_6_T(txphycrs), - IDX_IN_WL_CNT_VER_6_T(rxframe), - IDX_IN_WL_CNT_VER_6_T(rxbyte), - IDX_IN_WL_CNT_VER_6_T(rxerror), - IDX_IN_WL_CNT_VER_6_T(rxctl), - IDX_IN_WL_CNT_VER_6_T(rxnobuf), - IDX_IN_WL_CNT_VER_6_T(rxnondata), - IDX_IN_WL_CNT_VER_6_T(rxbadds), - IDX_IN_WL_CNT_VER_6_T(rxbadcm), - IDX_IN_WL_CNT_VER_6_T(rxfragerr), - IDX_IN_WL_CNT_VER_6_T(rxrunt), - IDX_IN_WL_CNT_VER_6_T(rxgiant), - IDX_IN_WL_CNT_VER_6_T(rxnoscb), - IDX_IN_WL_CNT_VER_6_T(rxbadproto), - IDX_IN_WL_CNT_VER_6_T(rxbadsrcmac), - IDX_IN_WL_CNT_VER_6_T(rxbadda), - IDX_IN_WL_CNT_VER_6_T(rxfilter), - IDX_IN_WL_CNT_VER_6_T(rxoflo), - IDX_IN_WL_CNT_VER_6_T(rxuflo), - IDX_IN_WL_CNT_VER_6_T(rxuflo) + 1, - IDX_IN_WL_CNT_VER_6_T(rxuflo) + 2, - IDX_IN_WL_CNT_VER_6_T(rxuflo) + 3, - IDX_IN_WL_CNT_VER_6_T(rxuflo) + 4, - IDX_IN_WL_CNT_VER_6_T(rxuflo) + 5, - IDX_IN_WL_CNT_VER_6_T(d11cnt_txrts_off), - IDX_IN_WL_CNT_VER_6_T(d11cnt_rxcrc_off), - IDX_IN_WL_CNT_VER_6_T(d11cnt_txnocts_off), - IDX_IN_WL_CNT_VER_6_T(dmade), - IDX_IN_WL_CNT_VER_6_T(dmada), - IDX_IN_WL_CNT_VER_6_T(dmape), - IDX_IN_WL_CNT_VER_6_T(reset), - IDX_IN_WL_CNT_VER_6_T(tbtt), - IDX_IN_WL_CNT_VER_6_T(txdmawar), - IDX_IN_WL_CNT_VER_6_T(pkt_callback_reg_fail), - IDX_IN_WL_CNT_VER_6_T(txfrag), - IDX_IN_WL_CNT_VER_6_T(txmulti), - IDX_IN_WL_CNT_VER_6_T(txfail), - IDX_IN_WL_CNT_VER_6_T(txretry), - IDX_IN_WL_CNT_VER_6_T(txretrie), - IDX_IN_WL_CNT_VER_6_T(rxdup), - IDX_IN_WL_CNT_VER_6_T(txrts), - IDX_IN_WL_CNT_VER_6_T(txnocts), - IDX_IN_WL_CNT_VER_6_T(txnoack), - IDX_IN_WL_CNT_VER_6_T(rxfrag), - IDX_IN_WL_CNT_VER_6_T(rxmulti), - IDX_IN_WL_CNT_VER_6_T(rxcrc), - IDX_IN_WL_CNT_VER_6_T(txfrmsnt), - IDX_IN_WL_CNT_VER_6_T(rxundec), - IDX_IN_WL_CNT_VER_6_T(tkipmicfaill), - IDX_IN_WL_CNT_VER_6_T(tkipcntrmsr), - IDX_IN_WL_CNT_VER_6_T(tkipreplay), - IDX_IN_WL_CNT_VER_6_T(ccmpfmterr), - IDX_IN_WL_CNT_VER_6_T(ccmpreplay), - IDX_IN_WL_CNT_VER_6_T(ccmpundec), - IDX_IN_WL_CNT_VER_6_T(fourwayfail), - IDX_IN_WL_CNT_VER_6_T(wepundec), - IDX_IN_WL_CNT_VER_6_T(wepicverr), - IDX_IN_WL_CNT_VER_6_T(decsuccess), - IDX_IN_WL_CNT_VER_6_T(tkipicverr), - IDX_IN_WL_CNT_VER_6_T(wepexcluded), - IDX_IN_WL_CNT_VER_6_T(txchanrej), - IDX_IN_WL_CNT_VER_6_T(psmwds), - IDX_IN_WL_CNT_VER_6_T(phywatchdog), - IDX_IN_WL_CNT_VER_6_T(prq_entries_handled), - IDX_IN_WL_CNT_VER_6_T(prq_undirected_entries), - IDX_IN_WL_CNT_VER_6_T(prq_bad_entries), - IDX_IN_WL_CNT_VER_6_T(atim_suppress_count), - IDX_IN_WL_CNT_VER_6_T(bcn_template_not_ready), - IDX_IN_WL_CNT_VER_6_T(bcn_template_not_ready_done), - IDX_IN_WL_CNT_VER_6_T(late_tbtt_dpc), - IDX_IN_WL_CNT_VER_6_T(rx1mbps), - IDX_IN_WL_CNT_VER_6_T(rx2mbps), - IDX_IN_WL_CNT_VER_6_T(rx5mbps5), - IDX_IN_WL_CNT_VER_6_T(rx6mbps), - IDX_IN_WL_CNT_VER_6_T(rx9mbps), - IDX_IN_WL_CNT_VER_6_T(rx11mbps), - IDX_IN_WL_CNT_VER_6_T(rx12mbps), - IDX_IN_WL_CNT_VER_6_T(rx18mbps), - IDX_IN_WL_CNT_VER_6_T(rx24mbps), - IDX_IN_WL_CNT_VER_6_T(rx36mbps), - IDX_IN_WL_CNT_VER_6_T(rx48mbps), - IDX_IN_WL_CNT_VER_6_T(rx54mbps), - IDX_IN_WL_CNT_VER_6_T(rx108mbps), - IDX_IN_WL_CNT_VER_6_T(rx162mbps), - IDX_IN_WL_CNT_VER_6_T(rx216mbps), - IDX_IN_WL_CNT_VER_6_T(rx270mbps), - IDX_IN_WL_CNT_VER_6_T(rx324mbps), - IDX_IN_WL_CNT_VER_6_T(rx378mbps), - IDX_IN_WL_CNT_VER_6_T(rx432mbps), - IDX_IN_WL_CNT_VER_6_T(rx486mbps), - IDX_IN_WL_CNT_VER_6_T(rx540mbps), - IDX_IN_WL_CNT_VER_6_T(rfdisable), - IDX_IN_WL_CNT_VER_6_T(txexptime), - IDX_IN_WL_CNT_VER_6_T(txmpdu_sgi), - IDX_IN_WL_CNT_VER_6_T(rxmpdu_sgi), - IDX_IN_WL_CNT_VER_6_T(txmpdu_stbc), - IDX_IN_WL_CNT_VER_6_T(rxmpdu_stbc), - IDX_IN_WL_CNT_VER_6_T(rxundec_mcst), - IDX_IN_WL_CNT_VER_6_T(tkipmicfaill_mcst), - IDX_IN_WL_CNT_VER_6_T(tkipcntrmsr_mcst), - IDX_IN_WL_CNT_VER_6_T(tkipreplay_mcst), - IDX_IN_WL_CNT_VER_6_T(ccmpfmterr_mcst), - IDX_IN_WL_CNT_VER_6_T(ccmpreplay_mcst), - IDX_IN_WL_CNT_VER_6_T(ccmpundec_mcst), - IDX_IN_WL_CNT_VER_6_T(fourwayfail_mcst), - IDX_IN_WL_CNT_VER_6_T(wepundec_mcst), - IDX_IN_WL_CNT_VER_6_T(wepicverr_mcst), - IDX_IN_WL_CNT_VER_6_T(decsuccess_mcst), - IDX_IN_WL_CNT_VER_6_T(tkipicverr_mcst), - IDX_IN_WL_CNT_VER_6_T(wepexcluded_mcst) -}; - -/* Index conversion table from wl_cnt_ver_11_t to wl_cnt_wlc_t */ -static const uint8 wlcntver11t_to_wlcntwlct[NUM_OF_WLCCNT_IN_WL_CNT_VER_11_T] = { - IDX_IN_WL_CNT_VER_11_T(txframe), - IDX_IN_WL_CNT_VER_11_T(txbyte), - IDX_IN_WL_CNT_VER_11_T(txretrans), - IDX_IN_WL_CNT_VER_11_T(txerror), - IDX_IN_WL_CNT_VER_11_T(txctl), - IDX_IN_WL_CNT_VER_11_T(txprshort), - IDX_IN_WL_CNT_VER_11_T(txserr), - IDX_IN_WL_CNT_VER_11_T(txnobuf), - IDX_IN_WL_CNT_VER_11_T(txnoassoc), - IDX_IN_WL_CNT_VER_11_T(txrunt), - IDX_IN_WL_CNT_VER_11_T(txchit), - IDX_IN_WL_CNT_VER_11_T(txcmiss), - IDX_IN_WL_CNT_VER_11_T(txuflo), - IDX_IN_WL_CNT_VER_11_T(txphyerr), - IDX_IN_WL_CNT_VER_11_T(txphycrs), - IDX_IN_WL_CNT_VER_11_T(rxframe), - IDX_IN_WL_CNT_VER_11_T(rxbyte), - IDX_IN_WL_CNT_VER_11_T(rxerror), - IDX_IN_WL_CNT_VER_11_T(rxctl), - IDX_IN_WL_CNT_VER_11_T(rxnobuf), - IDX_IN_WL_CNT_VER_11_T(rxnondata), - IDX_IN_WL_CNT_VER_11_T(rxbadds), - IDX_IN_WL_CNT_VER_11_T(rxbadcm), - IDX_IN_WL_CNT_VER_11_T(rxfragerr), - IDX_IN_WL_CNT_VER_11_T(rxrunt), - IDX_IN_WL_CNT_VER_11_T(rxgiant), - IDX_IN_WL_CNT_VER_11_T(rxnoscb), - IDX_IN_WL_CNT_VER_11_T(rxbadproto), - IDX_IN_WL_CNT_VER_11_T(rxbadsrcmac), - IDX_IN_WL_CNT_VER_11_T(rxbadda), - IDX_IN_WL_CNT_VER_11_T(rxfilter), - IDX_IN_WL_CNT_VER_11_T(rxoflo), - IDX_IN_WL_CNT_VER_11_T(rxuflo), - IDX_IN_WL_CNT_VER_11_T(rxuflo) + 1, - IDX_IN_WL_CNT_VER_11_T(rxuflo) + 2, - IDX_IN_WL_CNT_VER_11_T(rxuflo) + 3, - IDX_IN_WL_CNT_VER_11_T(rxuflo) + 4, - IDX_IN_WL_CNT_VER_11_T(rxuflo) + 5, - IDX_IN_WL_CNT_VER_11_T(d11cnt_txrts_off), - IDX_IN_WL_CNT_VER_11_T(d11cnt_rxcrc_off), - IDX_IN_WL_CNT_VER_11_T(d11cnt_txnocts_off), - IDX_IN_WL_CNT_VER_11_T(dmade), - IDX_IN_WL_CNT_VER_11_T(dmada), - IDX_IN_WL_CNT_VER_11_T(dmape), - IDX_IN_WL_CNT_VER_11_T(reset), - IDX_IN_WL_CNT_VER_11_T(tbtt), - IDX_IN_WL_CNT_VER_11_T(txdmawar), - IDX_IN_WL_CNT_VER_11_T(pkt_callback_reg_fail), - IDX_IN_WL_CNT_VER_11_T(txfrag), - IDX_IN_WL_CNT_VER_11_T(txmulti), - IDX_IN_WL_CNT_VER_11_T(txfail), - IDX_IN_WL_CNT_VER_11_T(txretry), - IDX_IN_WL_CNT_VER_11_T(txretrie), - IDX_IN_WL_CNT_VER_11_T(rxdup), - IDX_IN_WL_CNT_VER_11_T(txrts), - IDX_IN_WL_CNT_VER_11_T(txnocts), - IDX_IN_WL_CNT_VER_11_T(txnoack), - IDX_IN_WL_CNT_VER_11_T(rxfrag), - IDX_IN_WL_CNT_VER_11_T(rxmulti), - IDX_IN_WL_CNT_VER_11_T(rxcrc), - IDX_IN_WL_CNT_VER_11_T(txfrmsnt), - IDX_IN_WL_CNT_VER_11_T(rxundec), - IDX_IN_WL_CNT_VER_11_T(tkipmicfaill), - IDX_IN_WL_CNT_VER_11_T(tkipcntrmsr), - IDX_IN_WL_CNT_VER_11_T(tkipreplay), - IDX_IN_WL_CNT_VER_11_T(ccmpfmterr), - IDX_IN_WL_CNT_VER_11_T(ccmpreplay), - IDX_IN_WL_CNT_VER_11_T(ccmpundec), - IDX_IN_WL_CNT_VER_11_T(fourwayfail), - IDX_IN_WL_CNT_VER_11_T(wepundec), - IDX_IN_WL_CNT_VER_11_T(wepicverr), - IDX_IN_WL_CNT_VER_11_T(decsuccess), - IDX_IN_WL_CNT_VER_11_T(tkipicverr), - IDX_IN_WL_CNT_VER_11_T(wepexcluded), - IDX_IN_WL_CNT_VER_11_T(txchanrej), - IDX_IN_WL_CNT_VER_11_T(psmwds), - IDX_IN_WL_CNT_VER_11_T(phywatchdog), - IDX_IN_WL_CNT_VER_11_T(prq_entries_handled), - IDX_IN_WL_CNT_VER_11_T(prq_undirected_entries), - IDX_IN_WL_CNT_VER_11_T(prq_bad_entries), - IDX_IN_WL_CNT_VER_11_T(atim_suppress_count), - IDX_IN_WL_CNT_VER_11_T(bcn_template_not_ready), - IDX_IN_WL_CNT_VER_11_T(bcn_template_not_ready_done), - IDX_IN_WL_CNT_VER_11_T(late_tbtt_dpc), - IDX_IN_WL_CNT_VER_11_T(rx1mbps), - IDX_IN_WL_CNT_VER_11_T(rx2mbps), - IDX_IN_WL_CNT_VER_11_T(rx5mbps5), - IDX_IN_WL_CNT_VER_11_T(rx6mbps), - IDX_IN_WL_CNT_VER_11_T(rx9mbps), - IDX_IN_WL_CNT_VER_11_T(rx11mbps), - IDX_IN_WL_CNT_VER_11_T(rx12mbps), - IDX_IN_WL_CNT_VER_11_T(rx18mbps), - IDX_IN_WL_CNT_VER_11_T(rx24mbps), - IDX_IN_WL_CNT_VER_11_T(rx36mbps), - IDX_IN_WL_CNT_VER_11_T(rx48mbps), - IDX_IN_WL_CNT_VER_11_T(rx54mbps), - IDX_IN_WL_CNT_VER_11_T(rx108mbps), - IDX_IN_WL_CNT_VER_11_T(rx162mbps), - IDX_IN_WL_CNT_VER_11_T(rx216mbps), - IDX_IN_WL_CNT_VER_11_T(rx270mbps), - IDX_IN_WL_CNT_VER_11_T(rx324mbps), - IDX_IN_WL_CNT_VER_11_T(rx378mbps), - IDX_IN_WL_CNT_VER_11_T(rx432mbps), - IDX_IN_WL_CNT_VER_11_T(rx486mbps), - IDX_IN_WL_CNT_VER_11_T(rx540mbps), - IDX_IN_WL_CNT_VER_11_T(rfdisable), - IDX_IN_WL_CNT_VER_11_T(txexptime), - IDX_IN_WL_CNT_VER_11_T(txmpdu_sgi), - IDX_IN_WL_CNT_VER_11_T(rxmpdu_sgi), - IDX_IN_WL_CNT_VER_11_T(txmpdu_stbc), - IDX_IN_WL_CNT_VER_11_T(rxmpdu_stbc), - IDX_IN_WL_CNT_VER_11_T(rxundec_mcst), - IDX_IN_WL_CNT_VER_11_T(tkipmicfaill_mcst), - IDX_IN_WL_CNT_VER_11_T(tkipcntrmsr_mcst), - IDX_IN_WL_CNT_VER_11_T(tkipreplay_mcst), - IDX_IN_WL_CNT_VER_11_T(ccmpfmterr_mcst), - IDX_IN_WL_CNT_VER_11_T(ccmpreplay_mcst), - IDX_IN_WL_CNT_VER_11_T(ccmpundec_mcst), - IDX_IN_WL_CNT_VER_11_T(fourwayfail_mcst), - IDX_IN_WL_CNT_VER_11_T(wepundec_mcst), - IDX_IN_WL_CNT_VER_11_T(wepicverr_mcst), - IDX_IN_WL_CNT_VER_11_T(decsuccess_mcst), - IDX_IN_WL_CNT_VER_11_T(tkipicverr_mcst), - IDX_IN_WL_CNT_VER_11_T(wepexcluded_mcst), - IDX_IN_WL_CNT_VER_11_T(dma_hang), - IDX_IN_WL_CNT_VER_11_T(reinit), - IDX_IN_WL_CNT_VER_11_T(pstatxucast), - IDX_IN_WL_CNT_VER_11_T(pstatxnoassoc), - IDX_IN_WL_CNT_VER_11_T(pstarxucast), - IDX_IN_WL_CNT_VER_11_T(pstarxbcmc), - IDX_IN_WL_CNT_VER_11_T(pstatxbcmc), - IDX_IN_WL_CNT_VER_11_T(cso_passthrough), - IDX_IN_WL_CNT_VER_11_T(cso_normal), - IDX_IN_WL_CNT_VER_11_T(chained), - IDX_IN_WL_CNT_VER_11_T(chainedsz1), - IDX_IN_WL_CNT_VER_11_T(unchained), - IDX_IN_WL_CNT_VER_11_T(maxchainsz), - IDX_IN_WL_CNT_VER_11_T(currchainsz), - IDX_IN_WL_CNT_VER_11_T(pciereset), - IDX_IN_WL_CNT_VER_11_T(cfgrestore), - IDX_IN_WL_CNT_VER_11_T(reinitreason), - IDX_IN_WL_CNT_VER_11_T(reinitreason) + 1, - IDX_IN_WL_CNT_VER_11_T(reinitreason) + 2, - IDX_IN_WL_CNT_VER_11_T(reinitreason) + 3, - IDX_IN_WL_CNT_VER_11_T(reinitreason) + 4, - IDX_IN_WL_CNT_VER_11_T(reinitreason) + 5, - IDX_IN_WL_CNT_VER_11_T(reinitreason) + 6, - IDX_IN_WL_CNT_VER_11_T(reinitreason) + 7, - IDX_IN_WL_CNT_VER_11_T(rxrtry), - IDX_IN_WL_CNT_VER_11_T(rxmpdu_mu), - IDX_IN_WL_CNT_VER_11_T(txbar), - IDX_IN_WL_CNT_VER_11_T(rxbar), - IDX_IN_WL_CNT_VER_11_T(txpspoll), - IDX_IN_WL_CNT_VER_11_T(rxpspoll), - IDX_IN_WL_CNT_VER_11_T(txnull), - IDX_IN_WL_CNT_VER_11_T(rxnull), - IDX_IN_WL_CNT_VER_11_T(txqosnull), - IDX_IN_WL_CNT_VER_11_T(rxqosnull), - IDX_IN_WL_CNT_VER_11_T(txassocreq), - IDX_IN_WL_CNT_VER_11_T(rxassocreq), - IDX_IN_WL_CNT_VER_11_T(txreassocreq), - IDX_IN_WL_CNT_VER_11_T(rxreassocreq), - IDX_IN_WL_CNT_VER_11_T(txdisassoc), - IDX_IN_WL_CNT_VER_11_T(rxdisassoc), - IDX_IN_WL_CNT_VER_11_T(txassocrsp), - IDX_IN_WL_CNT_VER_11_T(rxassocrsp), - IDX_IN_WL_CNT_VER_11_T(txreassocrsp), - IDX_IN_WL_CNT_VER_11_T(rxreassocrsp), - IDX_IN_WL_CNT_VER_11_T(txauth), - IDX_IN_WL_CNT_VER_11_T(rxauth), - IDX_IN_WL_CNT_VER_11_T(txdeauth), - IDX_IN_WL_CNT_VER_11_T(rxdeauth), - IDX_IN_WL_CNT_VER_11_T(txprobereq), - IDX_IN_WL_CNT_VER_11_T(rxprobereq), - IDX_IN_WL_CNT_VER_11_T(txprobersp), - IDX_IN_WL_CNT_VER_11_T(rxprobersp), - IDX_IN_WL_CNT_VER_11_T(txaction), - IDX_IN_WL_CNT_VER_11_T(rxaction), - IDX_IN_WL_CNT_VER_11_T(ampdu_wds), - IDX_IN_WL_CNT_VER_11_T(txlost), - IDX_IN_WL_CNT_VER_11_T(txdatamcast), - IDX_IN_WL_CNT_VER_11_T(txdatabcast) -}; - -/* Index conversion table from wl_cnt_ver_11_t to - * either wl_cnt_ge40mcst_v1_t or wl_cnt_lt40mcst_v1_t - */ -static const uint8 wlcntver11t_to_wlcntXX40mcstv1t[WL_CNT_MCST_VAR_NUM] = { - IDX_IN_WL_CNT_VER_11_T(txallfrm), - IDX_IN_WL_CNT_VER_11_T(txrtsfrm), - IDX_IN_WL_CNT_VER_11_T(txctsfrm), - IDX_IN_WL_CNT_VER_11_T(txackfrm), - IDX_IN_WL_CNT_VER_11_T(txdnlfrm), - IDX_IN_WL_CNT_VER_11_T(txbcnfrm), - IDX_IN_WL_CNT_VER_11_T(txfunfl), - IDX_IN_WL_CNT_VER_11_T(txfunfl) + 1, - IDX_IN_WL_CNT_VER_11_T(txfunfl) + 2, - IDX_IN_WL_CNT_VER_11_T(txfunfl) + 3, - IDX_IN_WL_CNT_VER_11_T(txfunfl) + 4, - IDX_IN_WL_CNT_VER_11_T(txfunfl) + 5, - IDX_IN_WL_CNT_VER_11_T(txfbw), - IDX_IN_WL_CNT_VER_11_T(txmpdu), - IDX_IN_WL_CNT_VER_11_T(txtplunfl), - IDX_IN_WL_CNT_VER_11_T(txphyerror), - IDX_IN_WL_CNT_VER_11_T(pktengrxducast), - IDX_IN_WL_CNT_VER_11_T(pktengrxdmcast), - IDX_IN_WL_CNT_VER_11_T(rxfrmtoolong), - IDX_IN_WL_CNT_VER_11_T(rxfrmtooshrt), - IDX_IN_WL_CNT_VER_11_T(rxinvmachdr), - IDX_IN_WL_CNT_VER_11_T(rxbadfcs), - IDX_IN_WL_CNT_VER_11_T(rxbadplcp), - IDX_IN_WL_CNT_VER_11_T(rxcrsglitch), - IDX_IN_WL_CNT_VER_11_T(rxstrt), - IDX_IN_WL_CNT_VER_11_T(rxdfrmucastmbss), - IDX_IN_WL_CNT_VER_11_T(rxmfrmucastmbss), - IDX_IN_WL_CNT_VER_11_T(rxcfrmucast), - IDX_IN_WL_CNT_VER_11_T(rxrtsucast), - IDX_IN_WL_CNT_VER_11_T(rxctsucast), - IDX_IN_WL_CNT_VER_11_T(rxackucast), - IDX_IN_WL_CNT_VER_11_T(rxdfrmocast), - IDX_IN_WL_CNT_VER_11_T(rxmfrmocast), - IDX_IN_WL_CNT_VER_11_T(rxcfrmocast), - IDX_IN_WL_CNT_VER_11_T(rxrtsocast), - IDX_IN_WL_CNT_VER_11_T(rxctsocast), - IDX_IN_WL_CNT_VER_11_T(rxdfrmmcast), - IDX_IN_WL_CNT_VER_11_T(rxmfrmmcast), - IDX_IN_WL_CNT_VER_11_T(rxcfrmmcast), - IDX_IN_WL_CNT_VER_11_T(rxbeaconmbss), - IDX_IN_WL_CNT_VER_11_T(rxdfrmucastobss), - IDX_IN_WL_CNT_VER_11_T(rxbeaconobss), - IDX_IN_WL_CNT_VER_11_T(rxrsptmout), - IDX_IN_WL_CNT_VER_11_T(bcntxcancl), - IDX_IN_WL_CNT_VER_11_T(rxnodelim), - IDX_IN_WL_CNT_VER_11_T(rxf0ovfl), - IDX_IN_WL_CNT_VER_11_T(rxf1ovfl), - IDX_IN_WL_CNT_VER_11_T(rxf2ovfl), - IDX_IN_WL_CNT_VER_11_T(txsfovfl), - IDX_IN_WL_CNT_VER_11_T(pmqovfl), - IDX_IN_WL_CNT_VER_11_T(rxcgprqfrm), - IDX_IN_WL_CNT_VER_11_T(rxcgprsqovfl), - IDX_IN_WL_CNT_VER_11_T(txcgprsfail), - IDX_IN_WL_CNT_VER_11_T(txcgprssuc), - IDX_IN_WL_CNT_VER_11_T(prs_timeout), - IDX_IN_WL_CNT_VER_11_T(rxnack), - IDX_IN_WL_CNT_VER_11_T(frmscons), - IDX_IN_WL_CNT_VER_11_T(txnack), - IDX_IN_WL_CNT_VER_11_T(rxback), - IDX_IN_WL_CNT_VER_11_T(txback), - IDX_IN_WL_CNT_VER_11_T(bphy_rxcrsglitch), - IDX_IN_WL_CNT_VER_11_T(rxdrop20s), - IDX_IN_WL_CNT_VER_11_T(rxtoolate), - IDX_IN_WL_CNT_VER_11_T(bphy_badplcp) -}; - -/* For mcst offsets that were not used. (2 Pads) */ -#define INVALID_MCST_IDX ((uint8)(-1)) -/* Index conversion table from wl_cnt_ver_11_t to wl_cnt_v_le10_mcst_t */ -static const uint8 wlcntver11t_to_wlcntvle10mcstt[WL_CNT_MCST_VAR_NUM] = { - IDX_IN_WL_CNT_VER_11_T(txallfrm), - IDX_IN_WL_CNT_VER_11_T(txrtsfrm), - IDX_IN_WL_CNT_VER_11_T(txctsfrm), - IDX_IN_WL_CNT_VER_11_T(txackfrm), - IDX_IN_WL_CNT_VER_11_T(txdnlfrm), - IDX_IN_WL_CNT_VER_11_T(txbcnfrm), - IDX_IN_WL_CNT_VER_11_T(txfunfl), - IDX_IN_WL_CNT_VER_11_T(txfunfl) + 1, - IDX_IN_WL_CNT_VER_11_T(txfunfl) + 2, - IDX_IN_WL_CNT_VER_11_T(txfunfl) + 3, - IDX_IN_WL_CNT_VER_11_T(txfunfl) + 4, - IDX_IN_WL_CNT_VER_11_T(txfunfl) + 5, - IDX_IN_WL_CNT_VER_11_T(txfbw), - INVALID_MCST_IDX, - IDX_IN_WL_CNT_VER_11_T(txtplunfl), - IDX_IN_WL_CNT_VER_11_T(txphyerror), - IDX_IN_WL_CNT_VER_11_T(pktengrxducast), - IDX_IN_WL_CNT_VER_11_T(pktengrxdmcast), - IDX_IN_WL_CNT_VER_11_T(rxfrmtoolong), - IDX_IN_WL_CNT_VER_11_T(rxfrmtooshrt), - IDX_IN_WL_CNT_VER_11_T(rxinvmachdr), - IDX_IN_WL_CNT_VER_11_T(rxbadfcs), - IDX_IN_WL_CNT_VER_11_T(rxbadplcp), - IDX_IN_WL_CNT_VER_11_T(rxcrsglitch), - IDX_IN_WL_CNT_VER_11_T(rxstrt), - IDX_IN_WL_CNT_VER_11_T(rxdfrmucastmbss), - IDX_IN_WL_CNT_VER_11_T(rxmfrmucastmbss), - IDX_IN_WL_CNT_VER_11_T(rxcfrmucast), - IDX_IN_WL_CNT_VER_11_T(rxrtsucast), - IDX_IN_WL_CNT_VER_11_T(rxctsucast), - IDX_IN_WL_CNT_VER_11_T(rxackucast), - IDX_IN_WL_CNT_VER_11_T(rxdfrmocast), - IDX_IN_WL_CNT_VER_11_T(rxmfrmocast), - IDX_IN_WL_CNT_VER_11_T(rxcfrmocast), - IDX_IN_WL_CNT_VER_11_T(rxrtsocast), - IDX_IN_WL_CNT_VER_11_T(rxctsocast), - IDX_IN_WL_CNT_VER_11_T(rxdfrmmcast), - IDX_IN_WL_CNT_VER_11_T(rxmfrmmcast), - IDX_IN_WL_CNT_VER_11_T(rxcfrmmcast), - IDX_IN_WL_CNT_VER_11_T(rxbeaconmbss), - IDX_IN_WL_CNT_VER_11_T(rxdfrmucastobss), - IDX_IN_WL_CNT_VER_11_T(rxbeaconobss), - IDX_IN_WL_CNT_VER_11_T(rxrsptmout), - IDX_IN_WL_CNT_VER_11_T(bcntxcancl), - INVALID_MCST_IDX, - IDX_IN_WL_CNT_VER_11_T(rxf0ovfl), - IDX_IN_WL_CNT_VER_11_T(rxf1ovfl), - IDX_IN_WL_CNT_VER_11_T(rxf2ovfl), - IDX_IN_WL_CNT_VER_11_T(txsfovfl), - IDX_IN_WL_CNT_VER_11_T(pmqovfl), - IDX_IN_WL_CNT_VER_11_T(rxcgprqfrm), - IDX_IN_WL_CNT_VER_11_T(rxcgprsqovfl), - IDX_IN_WL_CNT_VER_11_T(txcgprsfail), - IDX_IN_WL_CNT_VER_11_T(txcgprssuc), - IDX_IN_WL_CNT_VER_11_T(prs_timeout), - IDX_IN_WL_CNT_VER_11_T(rxnack), - IDX_IN_WL_CNT_VER_11_T(frmscons), - IDX_IN_WL_CNT_VER_11_T(txnack), - IDX_IN_WL_CNT_VER_11_T(rxback), - IDX_IN_WL_CNT_VER_11_T(txback), - IDX_IN_WL_CNT_VER_11_T(bphy_rxcrsglitch), - IDX_IN_WL_CNT_VER_11_T(rxdrop20s), - IDX_IN_WL_CNT_VER_11_T(rxtoolate), - IDX_IN_WL_CNT_VER_11_T(bphy_badplcp) -}; - - -/* Index conversion table from wl_cnt_ver_6_t to wl_cnt_v_le10_mcst_t */ -static const uint8 wlcntver6t_to_wlcntvle10mcstt[WL_CNT_MCST_VAR_NUM] = { - IDX_IN_WL_CNT_VER_6_T(txallfrm), - IDX_IN_WL_CNT_VER_6_T(txrtsfrm), - IDX_IN_WL_CNT_VER_6_T(txctsfrm), - IDX_IN_WL_CNT_VER_6_T(txackfrm), - IDX_IN_WL_CNT_VER_6_T(txdnlfrm), - IDX_IN_WL_CNT_VER_6_T(txbcnfrm), - IDX_IN_WL_CNT_VER_6_T(txfunfl), - IDX_IN_WL_CNT_VER_6_T(txfunfl) + 1, - IDX_IN_WL_CNT_VER_6_T(txfunfl) + 2, - IDX_IN_WL_CNT_VER_6_T(txfunfl) + 3, - IDX_IN_WL_CNT_VER_6_T(txfunfl) + 4, - IDX_IN_WL_CNT_VER_6_T(txfunfl) + 5, - IDX_IN_WL_CNT_VER_6_T(txfbw), - INVALID_MCST_IDX, - IDX_IN_WL_CNT_VER_6_T(txtplunfl), - IDX_IN_WL_CNT_VER_6_T(txphyerror), - IDX_IN_WL_CNT_VER_6_T(pktengrxducast), - IDX_IN_WL_CNT_VER_6_T(pktengrxdmcast), - IDX_IN_WL_CNT_VER_6_T(rxfrmtoolong), - IDX_IN_WL_CNT_VER_6_T(rxfrmtooshrt), - IDX_IN_WL_CNT_VER_6_T(rxinvmachdr), - IDX_IN_WL_CNT_VER_6_T(rxbadfcs), - IDX_IN_WL_CNT_VER_6_T(rxbadplcp), - IDX_IN_WL_CNT_VER_6_T(rxcrsglitch), - IDX_IN_WL_CNT_VER_6_T(rxstrt), - IDX_IN_WL_CNT_VER_6_T(rxdfrmucastmbss), - IDX_IN_WL_CNT_VER_6_T(rxmfrmucastmbss), - IDX_IN_WL_CNT_VER_6_T(rxcfrmucast), - IDX_IN_WL_CNT_VER_6_T(rxrtsucast), - IDX_IN_WL_CNT_VER_6_T(rxctsucast), - IDX_IN_WL_CNT_VER_6_T(rxackucast), - IDX_IN_WL_CNT_VER_6_T(rxdfrmocast), - IDX_IN_WL_CNT_VER_6_T(rxmfrmocast), - IDX_IN_WL_CNT_VER_6_T(rxcfrmocast), - IDX_IN_WL_CNT_VER_6_T(rxrtsocast), - IDX_IN_WL_CNT_VER_6_T(rxctsocast), - IDX_IN_WL_CNT_VER_6_T(rxdfrmmcast), - IDX_IN_WL_CNT_VER_6_T(rxmfrmmcast), - IDX_IN_WL_CNT_VER_6_T(rxcfrmmcast), - IDX_IN_WL_CNT_VER_6_T(rxbeaconmbss), - IDX_IN_WL_CNT_VER_6_T(rxdfrmucastobss), - IDX_IN_WL_CNT_VER_6_T(rxbeaconobss), - IDX_IN_WL_CNT_VER_6_T(rxrsptmout), - IDX_IN_WL_CNT_VER_6_T(bcntxcancl), - INVALID_MCST_IDX, - IDX_IN_WL_CNT_VER_6_T(rxf0ovfl), - IDX_IN_WL_CNT_VER_6_T(rxf1ovfl), - IDX_IN_WL_CNT_VER_6_T(rxf2ovfl), - IDX_IN_WL_CNT_VER_6_T(txsfovfl), - IDX_IN_WL_CNT_VER_6_T(pmqovfl), - IDX_IN_WL_CNT_VER_6_T(rxcgprqfrm), - IDX_IN_WL_CNT_VER_6_T(rxcgprsqovfl), - IDX_IN_WL_CNT_VER_6_T(txcgprsfail), - IDX_IN_WL_CNT_VER_6_T(txcgprssuc), - IDX_IN_WL_CNT_VER_6_T(prs_timeout), - IDX_IN_WL_CNT_VER_6_T(rxnack), - IDX_IN_WL_CNT_VER_6_T(frmscons), - IDX_IN_WL_CNT_VER_6_T(txnack), - IDX_IN_WL_CNT_VER_6_T(rxback), - IDX_IN_WL_CNT_VER_6_T(txback), - IDX_IN_WL_CNT_VER_6_T(bphy_rxcrsglitch), - IDX_IN_WL_CNT_VER_6_T(rxdrop20s), - IDX_IN_WL_CNT_VER_6_T(rxtoolate), - IDX_IN_WL_CNT_VER_6_T(bphy_badplcp) -}; - -/* copy wlc layer counters from old type cntbuf to wl_cnt_wlc_t type. */ -static int -wl_copy_wlccnt(uint16 cntver, uint32 *dst, uint32 *src, uint8 src_max_idx) -{ - uint i; - if (dst == NULL || src == NULL) { - return BCME_ERROR; - } - - /* Init wlccnt with invalid value. Unchanged value will not be printed out */ - for (i = 0; i < (sizeof(wl_cnt_wlc_t) / sizeof(uint32)); i++) { - dst[i] = INVALID_CNT_VAL; - } - - if (cntver == WL_CNT_VERSION_6) { - for (i = 0; i < NUM_OF_WLCCNT_IN_WL_CNT_VER_6_T; i++) { - if (wlcntver6t_to_wlcntwlct[i] >= src_max_idx) { - /* src buffer does not have counters from here */ - break; - } - dst[i] = src[wlcntver6t_to_wlcntwlct[i]]; - } - } else { - for (i = 0; i < NUM_OF_WLCCNT_IN_WL_CNT_VER_11_T; i++) { - if (wlcntver11t_to_wlcntwlct[i] >= src_max_idx) { - /* src buffer does not have counters from here */ - break; - } - dst[i] = src[wlcntver11t_to_wlcntwlct[i]]; - } - } - return BCME_OK; -} - -/* copy macstat counters from old type cntbuf to wl_cnt_v_le10_mcst_t type. */ -static int -wl_copy_macstat_upto_ver10(uint16 cntver, uint32 *dst, uint32 *src) -{ - uint i; - - if (dst == NULL || src == NULL) { - return BCME_ERROR; - } - - if (cntver == WL_CNT_VERSION_6) { - for (i = 0; i < WL_CNT_MCST_VAR_NUM; i++) { - if (wlcntver6t_to_wlcntvle10mcstt[i] == INVALID_MCST_IDX) { - /* This mcst counter does not exist in wl_cnt_ver_6_t */ - dst[i] = INVALID_CNT_VAL; - } else { - dst[i] = src[wlcntver6t_to_wlcntvle10mcstt[i]]; - } - } - } else { - for (i = 0; i < WL_CNT_MCST_VAR_NUM; i++) { - if (wlcntver11t_to_wlcntvle10mcstt[i] == INVALID_MCST_IDX) { - /* This mcst counter does not exist in wl_cnt_ver_11_t */ - dst[i] = INVALID_CNT_VAL; - } else { - dst[i] = src[wlcntver11t_to_wlcntvle10mcstt[i]]; - } - } - } - return BCME_OK; -} - -static int -wl_copy_macstat_ver11(uint32 *dst, uint32 *src) -{ - uint i; - - if (dst == NULL || src == NULL) { - return BCME_ERROR; - } - - for (i = 0; i < WL_CNT_MCST_VAR_NUM; i++) { - dst[i] = src[wlcntver11t_to_wlcntXX40mcstv1t[i]]; - } - return BCME_OK; -} - -/** - * Translate non-xtlv 'wl counters' IOVar buffer received by old driver/FW to xtlv format. - * Parameters: - * cntbuf: pointer to non-xtlv 'wl counters' IOVar buffer received by old driver/FW. - * Newly translated xtlv format is written to this pointer. - * buflen: length of the "cntbuf" without any padding. - * corerev: chip core revision of the driver/FW. - */ -int -wl_cntbuf_to_xtlv_format(void *ctx, void *cntbuf, int buflen, uint32 corerev) -{ - wl_cnt_wlc_t *wlccnt = NULL; - uint32 *macstat = NULL; - xtlv_desc_t xtlv_desc[3]; - uint16 mcst_xtlv_id; - int res = BCME_OK; - wl_cnt_info_t *cntinfo = cntbuf; - void *xtlvbuf_p = cntinfo->data; - uint16 ver = cntinfo->version; - uint16 xtlvbuflen = (uint16)buflen; - uint16 src_max_idx; -#ifdef BCMDRIVER - osl_t *osh = ctx; -#else - BCM_REFERENCE(ctx); -#endif - - if (ver >= WL_CNT_VERSION_XTLV) { - /* Already in xtlv format. */ - goto exit; - } - -#ifdef BCMDRIVER - wlccnt = MALLOC(osh, sizeof(*wlccnt)); - macstat = MALLOC(osh, WL_CNT_MCST_STRUCT_SZ); -#else - wlccnt = (wl_cnt_wlc_t *)malloc(sizeof(*wlccnt)); - macstat = (uint32 *)malloc(WL_CNT_MCST_STRUCT_SZ); -#endif - if (!wlccnt || !macstat) { - printf("%s: malloc fail!\n", __FUNCTION__); - res = BCME_NOMEM; - goto exit; - } - - /* Check if the max idx in the struct exceeds the boundary of uint8 */ - if (NUM_OF_CNT_IN_WL_CNT_VER_6_T > ((uint8)(-1) + 1) || - NUM_OF_CNT_IN_WL_CNT_VER_11_T > ((uint8)(-1) + 1)) { - printf("wlcntverXXt_to_wlcntwlct and src_max_idx need" - " to be of uint16 instead of uint8\n"); - res = BCME_ERROR; - goto exit; - } - - /* Exclude version and length fields in either wlc_cnt_ver_6_t or wlc_cnt_ver_11_t */ - src_max_idx = (cntinfo->datalen - OFFSETOF(wl_cnt_info_t, data)) / sizeof(uint32); - if (src_max_idx > (uint8)(-1)) { - printf("wlcntverXXt_to_wlcntwlct and src_max_idx need" - " to be of uint16 instead of uint8\n" - "Try updating wl utility to the latest.\n"); - src_max_idx = (uint8)(-1); - } - - /* Copy wlc layer counters to wl_cnt_wlc_t */ - res = wl_copy_wlccnt(ver, (uint32 *)wlccnt, (uint32 *)cntinfo->data, (uint8)src_max_idx); - if (res != BCME_OK) { - printf("wl_copy_wlccnt fail!\n"); - goto exit; - } - - /* Copy macstat counters to wl_cnt_wlc_t */ - if (ver == WL_CNT_VERSION_11) { - res = wl_copy_macstat_ver11(macstat, (uint32 *)cntinfo->data); - if (res != BCME_OK) { - printf("wl_copy_macstat_ver11 fail!\n"); - goto exit; - } - if (corerev >= 40) { - mcst_xtlv_id = WL_CNT_XTLV_GE40_UCODE_V1; - } else { - mcst_xtlv_id = WL_CNT_XTLV_LT40_UCODE_V1; - } - } else { - res = wl_copy_macstat_upto_ver10(ver, macstat, (uint32 *)cntinfo->data); - if (res != BCME_OK) { - printf("wl_copy_macstat_upto_ver10 fail!\n"); - goto exit; - } - mcst_xtlv_id = WL_CNT_XTLV_CNTV_LE10_UCODE; - } - - xtlv_desc[0].type = WL_CNT_XTLV_WLC; - xtlv_desc[0].len = sizeof(*wlccnt); - xtlv_desc[0].ptr = wlccnt; - - xtlv_desc[1].type = mcst_xtlv_id; - xtlv_desc[1].len = WL_CNT_MCST_STRUCT_SZ; - xtlv_desc[1].ptr = macstat; - - xtlv_desc[2].type = 0; - xtlv_desc[2].len = 0; - xtlv_desc[2].ptr = NULL; - - memset(cntbuf, 0, buflen); - - res = bcm_pack_xtlv_buf_from_mem(&xtlvbuf_p, &xtlvbuflen, - xtlv_desc, BCM_XTLV_OPTION_ALIGN32); - cntinfo->datalen = (buflen - xtlvbuflen); -exit: -#ifdef BCMDRIVER - if (wlccnt) { - MFREE(osh, wlccnt, sizeof(*wlccnt)); - } - if (macstat) { - MFREE(osh, macstat, WL_CNT_MCST_STRUCT_SZ); - } -#else - if (wlccnt) { - free(wlccnt); - } - if (macstat) { - free(macstat); - } -#endif - return res; -}
diff --git a/bcmdhd.1.579.77.41.x/bcmevent.c b/bcmdhd.1.579.77.41.x/bcmevent.c deleted file mode 100644 index 9ffb1db..0000000 --- a/bcmdhd.1.579.77.41.x/bcmevent.c +++ /dev/null
@@ -1,448 +0,0 @@ -/* - * bcmevent read-only data shared by kernel or app layers - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: bcmevent.c 707287 2017-06-27 06:44:29Z $ - */ - -#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 - BCMEVENT_NAME(WLC_E_RSSI), - BCMEVENT_NAME(WLC_E_PFN_SCAN_COMPLETE), - BCMEVENT_NAME(WLC_E_EXTLOG_MSG), - BCMEVENT_NAME(WLC_E_ACTION_FRAME), - BCMEVENT_NAME(WLC_E_ACTION_FRAME_RX), - BCMEVENT_NAME(WLC_E_ACTION_FRAME_COMPLETE), - 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 -#ifdef PROP_TXSTATUS - BCMEVENT_NAME(WLC_E_FIFO_CREDIT_MAP), -#endif - BCMEVENT_NAME(WLC_E_WAKE_EVENT), - BCMEVENT_NAME(WLC_E_DCS_REQUEST), - BCMEVENT_NAME(WLC_E_RM_COMPLETE), -#ifdef WLMEDIA_HTSF - BCMEVENT_NAME(WLC_E_HTSFSYNC), -#endif - BCMEVENT_NAME(WLC_E_OVERLAY_REQ), - BCMEVENT_NAME(WLC_E_CSA_COMPLETE_IND), - BCMEVENT_NAME(WLC_E_EXCESS_PM_WAKE_EVENT), - BCMEVENT_NAME(WLC_E_PFN_SCAN_NONE), - BCMEVENT_NAME(WLC_E_PFN_SCAN_ALLGONE), -#ifdef SOFTAP - BCMEVENT_NAME(WLC_E_GTK_PLUMBED), -#endif - BCMEVENT_NAME(WLC_E_ASSOC_REQ_IE), - BCMEVENT_NAME(WLC_E_ASSOC_RESP_IE), - BCMEVENT_NAME(WLC_E_BEACON_FRAME_RX), -#ifdef IDSUP_STATS - BCMEVENT_NAME(WLC_E_AUTH_REQ), -#endif /* IDSUP_STATS */ -#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) - BCMEVENT_NAME(WLC_E_PROXD), -#endif - BCMEVENT_NAME(WLC_E_CCA_CHAN_QUAL), - BCMEVENT_NAME(WLC_E_BSSID), -#ifdef PROP_TXSTATUS - BCMEVENT_NAME(WLC_E_BCMC_CREDIT_SUPPORT), -#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 -#if defined(BT_WIFI_HANDOVER) || defined(WL_TBOW) - BCMEVENT_NAME(WLC_E_BT_WIFI_HANDOVER_REQ), -#endif - 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_PSK_AUTH), - BCMEVENT_NAME(WLC_E_SDB_TRANSITION), - BCMEVENT_NAME(WLC_E_NATOE_NFCT), - BCMEVENT_NAME(WLC_E_TEMP_THROTTLE), - BCMEVENT_NAME(WLC_E_LINK_QUALITY), - BCMEVENT_NAME(WLC_E_BSSTRANS_RESP), - BCMEVENT_NAME(WLC_E_TWT_SETUP), - BCMEVENT_NAME(WLC_E_HE_TWT_SETUP), - BCMEVENT_NAME(WLC_E_NAN_CRITICAL), - BCMEVENT_NAME(WLC_E_NAN_NON_CRITICAL), - BCMEVENT_NAME(WLC_E_RADAR_DETECTED), - BCMEVENT_NAME(WLC_E_RANGING_EVENT), - BCMEVENT_NAME(WLC_E_INVALID_IE), - BCMEVENT_NAME(WLC_E_MODE_SWITCH), - BCMEVENT_NAME(WLC_E_PKT_FILTER), - BCMEVENT_NAME(WLC_E_DMA_TXFLUSH_COMPLETE), - BCMEVENT_NAME(WLC_E_FBT), - 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_ONLINE_CHK_EVENT), - BCMEVENT_NAME(WLC_E_ONLINE_CHK_HOSTWAKE), - BCMEVENT_NAME(WLC_E_TVPM_MITIGATION), - BCMEVENT_NAME(WLC_E_DHCPC_EVENT), - BCMEVENT_NAME(WLC_E_TIMEOUT_EXHAUSTED), - BCMEVENT_NAME(WLC_E_HOSTWAKE), - BCMEVENT_NAME(WLC_E_TKO), - BCMEVENT_NAME(WLC_E_ID_AUTH), - BCMEVENT_NAME(WLC_E_BSSTRANS), -}; - - -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"); -} - -const char *bcmstatus_get_name(u32 status_code) -{ - switch(status_code) { - case WLC_E_STATUS_SUCCESS: - return "SUCCESS"; - case WLC_E_STATUS_FAIL: - return "FAIL"; - case WLC_E_STATUS_TIMEOUT: - return "TIMEOUT"; - case WLC_E_STATUS_NO_NETWORKS: - return "NO NETWORK"; - case WLC_E_STATUS_ABORT: - return "ABORT"; - case WLC_E_STATUS_NO_ACK: - return "NO ACK"; - case WLC_E_STATUS_UNSOLICITED: - return "UNSOLICITED"; - case WLC_E_STATUS_ATTEMPT: - return "ATTEMPT"; - case WLC_E_STATUS_PARTIAL: - return "PARTIAL"; - case WLC_E_STATUS_NEWSCAN: - return "NEW SCAN"; - case WLC_E_STATUS_NEWASSOC: - return "NEW ASSOC"; - case WLC_E_STATUS_11HQUIET: - return "11H QUIET"; - case WLC_E_STATUS_SUPPRESS: - return "SUPPRESS"; - case WLC_E_STATUS_NOCHANS: - return "NO ALLOWED CHANNEL"; - case WLC_E_STATUS_CS_ABORT: - return "ABORT CHANNEL SELECT"; - case WLC_E_STATUS_ERROR: - return "ERROR"; - default: - return "UNDEFINED STATUS"; - } -} - -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 - - default: - err = BCME_NOTFOUND; - goto done; - } - - BCM_REFERENCE(data_len); -done: - return err; -}
diff --git a/bcmdhd.1.579.77.41.x/bcmsdh.c b/bcmdhd.1.579.77.41.x/bcmsdh.c deleted file mode 100644 index a4144ef..0000000 --- a/bcmdhd.1.579.77.41.x/bcmsdh.c +++ /dev/null
@@ -1,847 +0,0 @@ -/* - * BCMSDH interface glue - * implement bcmsdh API for SDIOH driver - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: bcmsdh.c 671319 2016-11-21 14:27:29Z $ - */ - -/** - * @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 - -#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; - - bcmsdh_force_sbwad_calc(bcmsdh, FALSE); - - /* Report the BAR, to fix if needed */ - bcmsdh->sbwad = SI_ENUM_BASE; - - /* 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, int plen, void *arg, int 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; - ASSERT(bcmsdh); - - status = sdioh_interrupt_set(bcmsdh->sdioh, TRUE); - 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; - ASSERT(bcmsdh); - - status = sdioh_interrupt_set(bcmsdh->sdioh, FALSE); - 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 - - -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 - 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 - 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 - 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 - - 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 - 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 - 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, FALSE)) { - 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) -{ - return 0; -} -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) -{ - return; -} - - -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 -} - -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)); -}
diff --git a/bcmdhd.1.579.77.41.x/bcmsdh_linux.c b/bcmdhd.1.579.77.41.x/bcmsdh_linux.c deleted file mode 100644 index 8a8b619..0000000 --- a/bcmdhd.1.579.77.41.x/bcmsdh_linux.c +++ /dev/null
@@ -1,510 +0,0 @@ -/* - * SDIO access interface for drivers - linux specific (pci only) - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: bcmsdh_linux.c 672609 2016-11-29 07:00:46Z $ - */ - -/** - * @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> -#if defined(CONFIG_ARCH_ODIN) -#include <linux/platform_data/gpio-odin.h> -#endif /* defined(CONFIG_ARCH_ODIN) */ -#include <dhd_linux.h> -#include <dhd_dbg.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; - -/** - * 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) { - DHD_INFO(("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, ®s); - if (bcmsdh == NULL) { - DHD_ERROR(("%s: bcmsdh_attach failed\n", __FUNCTION__)); - goto err; - } - bcmsdh_osinfo = MALLOC(osh, sizeof(bcmsdh_os_info_t)); - if (bcmsdh_osinfo == NULL) { - DHD_ERROR(("%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) { - DHD_ERROR(("%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) { - DHD_ERROR(("%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) -{ - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - unsigned long flags; - int ret; - - 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); - 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; - DHD_INFO(("%s: register client driver\n", __FUNCTION__)); - error = bcmsdh_register_client_driver(); - if (error) - DHD_ERROR(("%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 - - 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) -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; - - bcmsdh_oob_intr_set(bcmsdh, FALSE); - 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) { - DHD_ERROR(("%s: irq is already registered\n", __FUNCTION__)); - return -EBUSY; - } -#ifdef HW_OOB - DHD_INFO(("%s: HW_OOB irq=%d flags=0x%X\n", __FUNCTION__, - (int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags)); -#else - DHD_INFO(("%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; -#if defined(CONFIG_ARCH_ODIN) - err = odin_gpio_sms_request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq, - bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh); -#else - err = request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq, - bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh); -#endif /* defined(CONFIG_ARCH_ODIN) */ - if (err) { - DHD_ERROR(("%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) - DHD_INFO(("%s: disable_irq_wake\n", __FUNCTION__)); - bcmsdh_osinfo->oob_irq_wake_enabled = FALSE; -#else - err = enable_irq_wake(bcmsdh_osinfo->oob_irq_num); - if (err) - DHD_ERROR(("%s: enable_irq_wake failed with %d\n", __FUNCTION__, err)); - else - bcmsdh_osinfo->oob_irq_wake_enabled = TRUE; -#endif - - return 0; -} - -void bcmsdh_oob_intr_unregister(bcmsdh_info_t *bcmsdh) -{ - int err = 0; - bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - if (!bcmsdh_osinfo->oob_irq_registered) { - DHD_INFO(("%s: irq is not registered\n", __FUNCTION__)); - return; - } - if (bcmsdh_osinfo->oob_irq_wake_enabled) { - err = disable_irq_wake(bcmsdh_osinfo->oob_irq_num); - if (!err) - bcmsdh_osinfo->oob_irq_wake_enabled = FALSE; - } - if (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 - -/* 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 - -#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 - -#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 */
diff --git a/bcmdhd.1.579.77.41.x/bcmsdh_sdmmc.c b/bcmdhd.1.579.77.41.x/bcmsdh_sdmmc.c deleted file mode 100644 index 8bb2e13..0000000 --- a/bcmdhd.1.579.77.41.x/bcmsdh_sdmmc.c +++ /dev/null
@@ -1,1779 +0,0 @@ -/* - * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Proprietary,Open:>> - * - * $Id: bcmsdh_sdmmc.c 710913 2017-07-14 10:17:51Z $ - */ -#include <typedefs.h> - -#include <bcmdevs.h> -#include <bcmendian.h> -#include <bcmutils.h> -#include <osl.h> -#include <sdio.h> /* SDIO Device and Protocol Specs */ -#include <sdioh.h> /* Standard SDIO Host Controller Specification */ -#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */ -#include <sdiovar.h> /* ioctl/iovars */ - -#include <linux/mmc/core.h> -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 0, 0)) -#include <drivers/mmc/core/host.h> -void -mmc_host_clk_hold(struct mmc_host *host) -{ - BCM_REFERENCE(host); - return; -} - -void -mmc_host_clk_release(struct mmc_host *host) -{ - BCM_REFERENCE(host); - return; -} -#elif (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 0, 8)) -#include <drivers/mmc/core/host.h> -#else -#include <linux/mmc/host.h> -#endif /* (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 0, 0)) */ -#include <linux/mmc/card.h> -#include <linux/mmc/sdio_func.h> -#include <linux/mmc/sdio_ids.h> - -#include <dngl_stats.h> -#include <dhd.h> -#include <dhd_dbg.h> -#ifdef CUSTOMER_HW_AMLOGIC -#include <linux/amlogic/aml_gpio_consumer.h> -extern int wifi_irq_trigger_level(void); -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) -#include <linux/suspend.h> -extern volatile bool dhd_mmc_suspend; -#endif -#include "bcmsdh_sdmmc.h" - -#ifndef BCMSDH_MODULE -extern int sdio_function_init(void); -extern void sdio_function_cleanup(void); -#endif /* BCMSDH_MODULE */ - -#if !defined(OOB_INTR_ONLY) -static void IRQHandler(struct sdio_func *func); -static void IRQHandlerF2(struct sdio_func *func); -#endif /* !defined(OOB_INTR_ONLY) */ -static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr); -extern int sdio_reset_comm(struct mmc_card *card); -#ifdef GLOBAL_SDMMC_INSTANCE -extern PBCMSDH_SDMMC_INSTANCE gInstance; -#endif - -#define DEFAULT_SDIO_F2_BLKSIZE 512 -#ifndef CUSTOM_SDIO_F2_BLKSIZE -#define CUSTOM_SDIO_F2_BLKSIZE DEFAULT_SDIO_F2_BLKSIZE -#endif - -#define DEFAULT_SDIO_F1_BLKSIZE 64 -#ifndef CUSTOM_SDIO_F1_BLKSIZE -#define CUSTOM_SDIO_F1_BLKSIZE DEFAULT_SDIO_F1_BLKSIZE -#endif - -#define MAX_IO_RW_EXTENDED_BLK 511 - -uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ -uint sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE; -uint sd_f1_blocksize = CUSTOM_SDIO_F1_BLKSIZE; - -#if defined(BT_OVER_SDIO) -uint sd_f3_blocksize = 64; -#endif /* defined (BT_OVER_SDIO) */ - -uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */ - -uint sd_power = 1; /* Default to SD Slot powered ON */ -uint sd_clock = 1; /* Default to SD Clock turned ON */ -uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */ -uint sd_msglevel = 0x01; -uint sd_use_dma = TRUE; - -#ifndef CUSTOM_RXCHAIN -#define CUSTOM_RXCHAIN 0 -#endif - -DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait); -DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait); -DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait); -DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait); - -#define DMA_ALIGN_MASK 0x03 -#define MMC_SDIO_ABORT_RETRY_LIMIT 5 - -int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data); - -void sdmmc_set_clock_rate(sdioh_info_t *sd, uint hz); -uint sdmmc_get_clock_rate(sdioh_info_t *sd); -void sdmmc_set_clock_divisor(sdioh_info_t *sd, uint sd_div); -#if defined(BT_OVER_SDIO) -extern -void sdioh_sdmmc_card_enable_func_f3(sdioh_info_t *sd, struct sdio_func *func) -{ - sd->func[3] = func; - sd_info(("%s sd->func[3] %p\n", __FUNCTION__, sd->func[3])); -} -#endif /* defined (BT_OVER_SDIO) */ - -static int -sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd) -{ - int err_ret; - uint32 fbraddr; - uint8 func; - - sd_trace(("%s\n", __FUNCTION__)); - - /* Get the Card's common CIS address */ - sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0); - sd->func_cis_ptr[0] = sd->com_cis_ptr; - sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); - - /* Get the Card's function CIS (for each function) */ - for (fbraddr = SDIOD_FBR_STARTADDR, func = 1; - func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { - sd->func_cis_ptr[func] = sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr); - sd_info(("%s: Function %d CIS Ptr = 0x%x\n", - __FUNCTION__, func, sd->func_cis_ptr[func])); - } - - sd->func_cis_ptr[0] = sd->com_cis_ptr; - sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); - - /* Enable Function 1 */ - sdio_claim_host(sd->func[1]); - err_ret = sdio_enable_func(sd->func[1]); - sdio_release_host(sd->func[1]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x\n", err_ret)); - } - - return FALSE; -} - -/* - * Public entry points & extern's - */ -extern sdioh_info_t * -sdioh_attach(osl_t *osh, struct sdio_func *func) -{ - sdioh_info_t *sd = NULL; - int err_ret; - - sd_trace(("%s\n", __FUNCTION__)); - - if (func == NULL) { - sd_err(("%s: sdio function device is NULL\n", __FUNCTION__)); - return NULL; - } - - if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { - sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); - return NULL; - } - bzero((char *)sd, sizeof(sdioh_info_t)); - sd->osh = osh; - sd->fake_func0.num = 0; - sd->fake_func0.card = func->card; - sd->func[0] = &sd->fake_func0; -#ifdef GLOBAL_SDMMC_INSTANCE - if (func->num == 2) - sd->func[1] = gInstance->func[1]; -#else - sd->func[1] = func->card->sdio_func[0]; -#endif - sd->func[2] = func->card->sdio_func[1]; -#ifdef GLOBAL_SDMMC_INSTANCE - sd->func[func->num] = func; -#endif - -#if defined(BT_OVER_SDIO) - sd->func[3] = NULL; -#endif /* defined (BT_OVER_SDIO) */ - - sd->num_funcs = 2; - sd->sd_blockmode = TRUE; - sd->use_client_ints = TRUE; - sd->client_block_size[0] = 64; - sd->use_rxchain = CUSTOM_RXCHAIN; - if (sd->func[1] == NULL || sd->func[2] == NULL) { - sd_err(("%s: func 1 or 2 is null \n", __FUNCTION__)); - goto fail; - } - sdio_set_drvdata(sd->func[1], sd); - - sdio_claim_host(sd->func[1]); - sd->client_block_size[1] = sd_f1_blocksize; - err_ret = sdio_set_block_size(sd->func[1], sd_f1_blocksize); - sdio_release_host(sd->func[1]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize(%d)\n", err_ret)); - goto fail; - } - - sdio_claim_host(sd->func[2]); - sd->client_block_size[2] = sd_f2_blocksize; - sd_info(("%s: set sd_f2_blocksize %d\n", __FUNCTION__, sd_f2_blocksize)); - err_ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize); - sdio_release_host(sd->func[2]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d(%d)\n", - sd_f2_blocksize, err_ret)); - goto fail; - } - - sd->sd_clk_rate = sdmmc_get_clock_rate(sd); - sd_info(("%s: sd clock rate = %u\n", __FUNCTION__, sd->sd_clk_rate)); - sdioh_sdmmc_card_enablefuncs(sd); - - sd_trace(("%s: Done\n", __FUNCTION__)); - return sd; - -fail: - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return NULL; -} - - -extern SDIOH_API_RC -sdioh_detach(osl_t *osh, sdioh_info_t *sd) -{ - sd_trace(("%s\n", __FUNCTION__)); - - if (sd) { - - /* Disable Function 2 */ - if (sd->func[2]) { - sdio_claim_host(sd->func[2]); - sdio_disable_func(sd->func[2]); - sdio_release_host(sd->func[2]); - } - - /* Disable Function 1 */ - if (sd->func[1]) { - sdio_claim_host(sd->func[1]); - sdio_disable_func(sd->func[1]); - sdio_release_host(sd->func[1]); - } - - sd->func[1] = NULL; - sd->func[2] = NULL; - - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - } - return SDIOH_API_RC_SUCCESS; -} - -#if defined(OOB_INTR_ONLY) && defined(HW_OOB) - -extern SDIOH_API_RC -sdioh_enable_func_intr(sdioh_info_t *sd) -{ - uint8 reg; - int err; - - if (sd->func[0] == NULL) { - sd_err(("%s: function 0 pointer is NULL\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - sdio_claim_host(sd->func[0]); - reg = sdio_readb(sd->func[0], SDIOD_CCCR_INTEN, &err); - if (err) { - sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); - sdio_release_host(sd->func[0]); - return SDIOH_API_RC_FAIL; - } - /* Enable F1 and F2 interrupts, clear master enable */ - reg &= ~INTR_CTL_MASTER_EN; - reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); -#if defined(BT_OVER_SDIO) - reg |= (INTR_CTL_FUNC3_EN); -#endif /* defined (BT_OVER_SDIO) */ - sdio_writeb(sd->func[0], reg, SDIOD_CCCR_INTEN, &err); - sdio_release_host(sd->func[0]); - - if (err) { - sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); - return SDIOH_API_RC_FAIL; - } - - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_disable_func_intr(sdioh_info_t *sd) -{ - uint8 reg; - int err; - - if (sd->func[0] == NULL) { - sd_err(("%s: function 0 pointer is NULL\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - sdio_claim_host(sd->func[0]); - reg = sdio_readb(sd->func[0], SDIOD_CCCR_INTEN, &err); - if (err) { - sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); - sdio_release_host(sd->func[0]); - return SDIOH_API_RC_FAIL; - } - reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN); -#if defined(BT_OVER_SDIO) - reg &= ~INTR_CTL_FUNC3_EN; -#endif - /* Disable master interrupt with the last function interrupt */ - if (!(reg & 0xFE)) - reg = 0; - sdio_writeb(sd->func[0], reg, SDIOD_CCCR_INTEN, &err); - sdio_release_host(sd->func[0]); - - if (err) { - sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err)); - return SDIOH_API_RC_FAIL; - } - - return SDIOH_API_RC_SUCCESS; -} -#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ - -/* Configure callback to client when we recieve client interrupt */ -extern SDIOH_API_RC -sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); - if (fn == NULL) { - sd_err(("%s: interrupt handler is NULL, not registering\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } -#if !defined(OOB_INTR_ONLY) - sd->intr_handler = fn; - sd->intr_handler_arg = argh; - sd->intr_handler_valid = TRUE; - - /* register and unmask irq */ - if (sd->func[2]) { - sdio_claim_host(sd->func[2]); - sdio_claim_irq(sd->func[2], IRQHandlerF2); - sdio_release_host(sd->func[2]); - } - - if (sd->func[1]) { - sdio_claim_host(sd->func[1]); - sdio_claim_irq(sd->func[1], IRQHandler); - sdio_release_host(sd->func[1]); - } -#elif defined(HW_OOB) - sdioh_enable_func_intr(sd); -#endif /* !defined(OOB_INTR_ONLY) */ - - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_interrupt_deregister(sdioh_info_t *sd) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); - -#if !defined(OOB_INTR_ONLY) - if (sd->func[1]) { - /* register and unmask irq */ - sdio_claim_host(sd->func[1]); - sdio_release_irq(sd->func[1]); - sdio_release_host(sd->func[1]); - } - - if (sd->func[2]) { - /* Claim host controller F2 */ - sdio_claim_host(sd->func[2]); - sdio_release_irq(sd->func[2]); - /* Release host controller F2 */ - sdio_release_host(sd->func[2]); - } - - sd->intr_handler_valid = FALSE; - sd->intr_handler = NULL; - sd->intr_handler_arg = NULL; -#elif defined(HW_OOB) - if (dhd_download_fw_on_driverload) - sdioh_disable_func_intr(sd); -#endif /* !defined(OOB_INTR_ONLY) */ - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); - *onoff = sd->client_intr_enabled; - return SDIOH_API_RC_SUCCESS; -} - -#if defined(DHD_DEBUG) -extern bool -sdioh_interrupt_pending(sdioh_info_t *sd) -{ - return (0); -} -#endif - -uint -sdioh_query_iofnum(sdioh_info_t *sd) -{ - return sd->num_funcs; -} - -/* IOVar table */ -enum { - IOV_MSGLEVEL = 1, - IOV_BLOCKMODE, - IOV_BLOCKSIZE, - IOV_DMA, - IOV_USEINTS, - IOV_NUMINTS, - IOV_NUMLOCALINTS, - IOV_HOSTREG, - IOV_DEVREG, - IOV_DIVISOR, - IOV_SDMODE, - IOV_HISPEED, - IOV_HCIREGS, - IOV_POWER, - IOV_CLOCK, - IOV_RXCHAIN -}; - -const bcm_iovar_t sdioh_iovars[] = { - {"sd_msglevel", IOV_MSGLEVEL, 0, 0, IOVT_UINT32, 0 }, - {"sd_blockmode", IOV_BLOCKMODE, 0, 0, IOVT_BOOL, 0 }, - {"sd_blocksize", IOV_BLOCKSIZE, 0, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ - {"sd_dma", IOV_DMA, 0, 0, IOVT_BOOL, 0 }, - {"sd_ints", IOV_USEINTS, 0, 0, IOVT_BOOL, 0 }, - {"sd_numints", IOV_NUMINTS, 0, 0, IOVT_UINT32, 0 }, - {"sd_numlocalints", IOV_NUMLOCALINTS, 0, 0, IOVT_UINT32, 0 }, - {"sd_divisor", IOV_DIVISOR, 0, 0, IOVT_UINT32, 0 }, - {"sd_power", IOV_POWER, 0, 0, IOVT_UINT32, 0 }, - {"sd_clock", IOV_CLOCK, 0, 0, IOVT_UINT32, 0 }, - {"sd_mode", IOV_SDMODE, 0, 0, IOVT_UINT32, 100}, - {"sd_highspeed", IOV_HISPEED, 0, 0, IOVT_UINT32, 0 }, - {"sd_rxchain", IOV_RXCHAIN, 0, 0, IOVT_BOOL, 0 }, - {NULL, 0, 0, 0, 0, 0 } -}; - -int -sdioh_iovar_op(sdioh_info_t *si, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - const bcm_iovar_t *vi = NULL; - int bcmerror = 0; - int val_size; - int32 int_val = 0; - bool bool_val; - uint32 actionid; - - ASSERT(name); - ASSERT(len >= 0); - - /* Get must have return space; Set does not take qualifiers */ - ASSERT(set || (arg && len)); - ASSERT(!set || (!params && !plen)); - - sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); - - if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { - bcmerror = BCME_UNSUPPORTED; - goto exit; - } - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) - goto exit; - - /* Set up params so get and set can share the convenience variables */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - val_size = sizeof(int); - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - bool_val = (int_val != 0) ? TRUE : FALSE; - BCM_REFERENCE(bool_val); - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - switch (actionid) { - case IOV_GVAL(IOV_MSGLEVEL): - int_val = (int32)sd_msglevel; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_MSGLEVEL): - sd_msglevel = int_val; - break; - - case IOV_GVAL(IOV_BLOCKMODE): - int_val = (int32)si->sd_blockmode; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_BLOCKMODE): - si->sd_blockmode = (bool)int_val; - /* Haven't figured out how to make non-block mode with DMA */ - break; - - case IOV_GVAL(IOV_BLOCKSIZE): - if ((uint32)int_val > si->num_funcs) { - bcmerror = BCME_BADARG; - break; - } - int_val = (int32)si->client_block_size[int_val]; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_BLOCKSIZE): - { - uint func = ((uint32)int_val >> 16); - uint blksize = (uint16)int_val; - uint maxsize; - - if (func > si->num_funcs) { - bcmerror = BCME_BADARG; - break; - } - - switch (func) { - case 0: maxsize = 32; break; - case 1: maxsize = BLOCK_SIZE_4318; break; - case 2: maxsize = BLOCK_SIZE_4328; break; - default: maxsize = 0; - } - if (blksize > maxsize) { - bcmerror = BCME_BADARG; - break; - } - if (!blksize) { - blksize = maxsize; - } - - /* Now set it */ - si->client_block_size[func] = blksize; - - if (si->func[func] == NULL) { - sd_err(("%s: SDIO Device not present\n", __FUNCTION__)); - bcmerror = BCME_NORESOURCE; - break; - } - sdio_claim_host(si->func[func]); - bcmerror = sdio_set_block_size(si->func[func], blksize); - if (bcmerror) - sd_err(("%s: Failed to set F%d blocksize to %d(%d)\n", - __FUNCTION__, func, blksize, bcmerror)); - sdio_release_host(si->func[func]); - break; - } - - case IOV_GVAL(IOV_RXCHAIN): - int_val = (int32)si->use_rxchain; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_DMA): - int_val = (int32)si->sd_use_dma; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DMA): - si->sd_use_dma = (bool)int_val; - break; - - case IOV_GVAL(IOV_USEINTS): - int_val = (int32)si->use_client_ints; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_USEINTS): - si->use_client_ints = (bool)int_val; - if (si->use_client_ints) - si->intmask |= CLIENT_INTR; - else - si->intmask &= ~CLIENT_INTR; - - break; - - case IOV_GVAL(IOV_DIVISOR): - int_val = (uint32)sd_divisor; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DIVISOR): - /* set the clock to divisor, if value is non-zero & power of 2 */ - if (int_val && !(int_val & (int_val - 1))) { - sd_divisor = int_val; - sdmmc_set_clock_divisor(si, sd_divisor); - } else { - DHD_ERROR(("%s: Invalid sd_divisor value, should be power of 2!\n", - __FUNCTION__)); - } - break; - - case IOV_GVAL(IOV_POWER): - int_val = (uint32)sd_power; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_POWER): - sd_power = int_val; - break; - - case IOV_GVAL(IOV_CLOCK): - int_val = (uint32)sd_clock; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_CLOCK): - sd_clock = int_val; - break; - - case IOV_GVAL(IOV_SDMODE): - int_val = (uint32)sd_sdmode; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SDMODE): - sd_sdmode = int_val; - break; - - case IOV_GVAL(IOV_HISPEED): - int_val = (uint32)sd_hiok; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_HISPEED): - sd_hiok = int_val; - break; - - case IOV_GVAL(IOV_NUMINTS): - int_val = (int32)si->intrcount; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_NUMLOCALINTS): - int_val = (int32)0; - bcopy(&int_val, arg, val_size); - break; - default: - bcmerror = BCME_UNSUPPORTED; - break; - } -exit: - - return bcmerror; -} - -#if (defined(OOB_INTR_ONLY) && defined(HW_OOB)) || defined(FORCE_WOWLAN) - -SDIOH_API_RC -sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable) -{ - SDIOH_API_RC status; - uint8 data; - - if (enable) -#ifdef CUSTOMER_HW_AMLOGIC - if (wifi_irq_trigger_level() == GPIO_IRQ_LOW) - data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE; - else - data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI; -#else -#ifdef HW_OOB_LOW_LEVEL - data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE; -#else - data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI; -#endif -#endif - else - data = SDIO_SEPINT_ACT_HI; /* disable hw oob interrupt */ - - status = sdioh_request_byte(sd, SDIOH_WRITE, 0, SDIOD_CCCR_BRCM_SEPINT, &data); - return status; -} -#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ - -extern SDIOH_API_RC -sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -{ - SDIOH_API_RC status; - /* No lock needed since sdioh_request_byte does locking */ - status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); - return status; -} - -extern SDIOH_API_RC -sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -{ - /* No lock needed since sdioh_request_byte does locking */ - SDIOH_API_RC status; - status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); - return status; -} - -static int -sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr) -{ - /* read 24 bits and return valid 17 bit addr */ - int i; - uint32 scratch, regdata; - uint8 *ptr = (uint8 *)&scratch; - for (i = 0; i < 3; i++) { - if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, ®data)) != SUCCESS) - sd_err(("%s: Can't read!\n", __FUNCTION__)); - - *ptr++ = (uint8) regdata; - regaddr++; - } - - /* Only the lower 17-bits are valid */ - scratch = ltoh32(scratch); - scratch &= 0x0001FFFF; - return (scratch); -} - -extern SDIOH_API_RC -sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) -{ - uint32 count; - int offset; - uint32 foo; - uint8 *cis = cisd; - - sd_trace(("%s: Func = %d\n", __FUNCTION__, func)); - - if (!sd->func_cis_ptr[func]) { - bzero(cis, length); - sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func)); - return SDIOH_API_RC_FAIL; - } - - sd_trace(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func])); - - for (count = 0; count < length; count++) { - offset = sd->func_cis_ptr[func] + count; - if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) { - sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - *cis = (uint8)(foo & 0xff); - cis++; - } - - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_cisaddr_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 offset) -{ - uint32 foo; - - sd_trace(("%s: Func = %d\n", __FUNCTION__, func)); - - if (!sd->func_cis_ptr[func]) { - sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func)); - return SDIOH_API_RC_FAIL; - } - - sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func])); - - if (sdioh_sdmmc_card_regread (sd, 0, sd->func_cis_ptr[func]+offset, 1, &foo) < 0) { - sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - *cisd = (uint8)(foo & 0xff); - - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) -{ - int err_ret = 0; -#if defined(MMC_SDIO_ABORT) - int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; -#endif - struct timespec now, before; - - if (sd_msglevel & SDH_COST_VAL) - getnstimeofday(&before); - - sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr)); - - DHD_PM_RESUME_WAIT(sdioh_request_byte_wait); - DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); - if(rw) { /* CMD52 Write */ - if (func == 0) { - /* Can only directly write to some F0 registers. Handle F2 enable - * as a special case. - */ - if (regaddr == SDIOD_CCCR_IOEN) { -#if defined(BT_OVER_SDIO) - do { - if (sd->func[3]) { - sd_info(("bcmsdh_sdmmc F3: *byte 0x%x\n", *byte)); - - if (*byte & SDIO_FUNC_ENABLE_3) { - sdio_claim_host(sd->func[3]); - - /* Set Function 3 Block Size */ - err_ret = sdio_set_block_size(sd->func[3], - sd_f3_blocksize); - if (err_ret) { - sd_err(("F3 blocksize set err%d\n", - err_ret)); - } - - /* Enable Function 3 */ - sd_info(("bcmsdh_sdmmc F3: enable F3 fn %p\n", - sd->func[3])); - err_ret = sdio_enable_func(sd->func[3]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: enable F3 err:%d\n", - err_ret)); - } - - sdio_release_host(sd->func[3]); - - break; - } else if (*byte & SDIO_FUNC_DISABLE_3) { - sdio_claim_host(sd->func[3]); - - /* Disable Function 3 */ - sd_info(("bcmsdh_sdmmc F3: disable F3 fn %p\n", - sd->func[3])); - err_ret = sdio_disable_func(sd->func[3]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: Disable F3 err:%d\n", - err_ret)); - } - sdio_release_host(sd->func[3]); - sd->func[3] = NULL; - - break; - } - } -#endif /* defined (BT_OVER_SDIO) */ - if (sd->func[2]) { - sdio_claim_host(sd->func[2]); - if (*byte & SDIO_FUNC_ENABLE_2) { - /* Enable Function 2 */ - err_ret = sdio_enable_func(sd->func[2]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: enable F2 failed:%d\n", - err_ret)); - } - } else { - /* Disable Function 2 */ - err_ret = sdio_disable_func(sd->func[2]); - if (err_ret) { - sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d\n", - err_ret)); - } - } - sdio_release_host(sd->func[2]); - } -#if defined(BT_OVER_SDIO) - } while (0); -#endif /* defined (BT_OVER_SDIO) */ - } -#if defined(MMC_SDIO_ABORT) - /* to allow abort command through F1 */ - else if (regaddr == SDIOD_CCCR_IOABORT) { - while (sdio_abort_retry--) { - if (sd->func[func]) { - sdio_claim_host(sd->func[func]); - /* - * this sdio_f0_writeb() can be replaced with - * another api depending upon MMC driver change. - * As of this time, this is temporaray one - */ - sdio_writeb(sd->func[func], - *byte, regaddr, &err_ret); - sdio_release_host(sd->func[func]); - } - if (!err_ret) - break; - } - } -#endif /* MMC_SDIO_ABORT */ - else if (regaddr < 0xF0) { - sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr)); - } else { - /* Claim host controller, perform F0 write, and release */ - if (sd->func[func]) { - sdio_claim_host(sd->func[func]); - sdio_f0_writeb(sd->func[func], - *byte, regaddr, &err_ret); - sdio_release_host(sd->func[func]); - } - } - } else { - /* Claim host controller, perform Fn write, and release */ - if (sd->func[func]) { - sdio_claim_host(sd->func[func]); - sdio_writeb(sd->func[func], *byte, regaddr, &err_ret); - sdio_release_host(sd->func[func]); - } - } - } else { /* CMD52 Read */ - /* Claim host controller, perform Fn read, and release */ - if (sd->func[func]) { - sdio_claim_host(sd->func[func]); - if (func == 0) { - *byte = sdio_f0_readb(sd->func[func], regaddr, &err_ret); - } else { - *byte = sdio_readb(sd->func[func], regaddr, &err_ret); - } - sdio_release_host(sd->func[func]); - } - } - - if (err_ret) { - if ((regaddr == 0x1001F) && ((err_ret == -ETIMEDOUT) || (err_ret == -EILSEQ))) { - } else { - sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", - rw ? "Write" : "Read", func, regaddr, *byte, err_ret)); - } - } - - if (sd_msglevel & SDH_COST_VAL) { - getnstimeofday(&now); - sd_cost(("%s: rw=%d len=1 cost=%lds %luus\n", __FUNCTION__, - rw, now.tv_sec-before.tv_sec, now.tv_nsec/1000-before.tv_nsec/1000)); - } - - return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -} - -uint -sdioh_set_mode(sdioh_info_t *sd, uint mode) -{ - if (mode == SDPCM_TXGLOM_CPY) - sd->txglom_mode = mode; - else if (mode == SDPCM_TXGLOM_MDESC) - sd->txglom_mode = mode; - - return (sd->txglom_mode); -} - -extern SDIOH_API_RC -sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, - uint32 *word, uint nbytes) -{ - int err_ret = SDIOH_API_RC_FAIL; - int err_ret2 = SDIOH_API_RC_SUCCESS; // terence 20130621: prevent dhd_dpc in dead lock -#if defined(MMC_SDIO_ABORT) - int sdio_abort_retry = MMC_SDIO_ABORT_RETRY_LIMIT; -#endif - struct timespec now, before; - - if (sd_msglevel & SDH_COST_VAL) - getnstimeofday(&before); - - if (func == 0) { - sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", - __FUNCTION__, cmd_type, rw, func, addr, nbytes)); - - DHD_PM_RESUME_WAIT(sdioh_request_word_wait); - DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); - /* Claim host controller */ - sdio_claim_host(sd->func[func]); - - if(rw) { /* CMD52 Write */ - if (nbytes == 4) { - sdio_writel(sd->func[func], *word, addr, &err_ret); - } else if (nbytes == 2) { - sdio_writew(sd->func[func], (*word & 0xFFFF), addr, &err_ret); - } else { - sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes)); - } - } else { /* CMD52 Read */ - if (nbytes == 4) { - *word = sdio_readl(sd->func[func], addr, &err_ret); - } else if (nbytes == 2) { - *word = sdio_readw(sd->func[func], addr, &err_ret) & 0xFFFF; - } else { - sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes)); - } - } - - /* Release host controller */ - sdio_release_host(sd->func[func]); - - if (err_ret) { -#if defined(MMC_SDIO_ABORT) - /* Any error on CMD53 transaction should abort that function using function 0. */ - while (sdio_abort_retry--) { - if (sd->func[0]) { - sdio_claim_host(sd->func[0]); - /* - * this sdio_f0_writeb() can be replaced with another api - * depending upon MMC driver change. - * As of this time, this is temporaray one - */ - sdio_writeb(sd->func[0], - func, SDIOD_CCCR_IOABORT, &err_ret2); - sdio_release_host(sd->func[0]); - } - if (!err_ret2) - break; - } - if (err_ret) -#endif /* MMC_SDIO_ABORT */ - { - sd_err(("bcmsdh_sdmmc: Failed to %s word F%d:@0x%05x=%02x, Err: 0x%08x\n", - rw ? "Write" : "Read", func, addr, *word, err_ret)); - } - } - - if (sd_msglevel & SDH_COST_VAL) { - getnstimeofday(&now); - sd_cost(("%s: rw=%d, len=%d cost=%lds %luus\n", __FUNCTION__, - rw, nbytes, now.tv_sec-before.tv_sec, now.tv_nsec/1000 - before.tv_nsec/1000)); - } - - return (((err_ret == 0)&&(err_ret2 == 0)) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -} - -#ifdef BCMSDIOH_TXGLOM -static SDIOH_API_RC -sdioh_request_packet_chain(sdioh_info_t *sd, uint fix_inc, uint write, uint func, - uint addr, void *pkt) -{ - bool fifo = (fix_inc == SDIOH_DATA_FIX); - int err_ret = 0; - void *pnext; - uint ttl_len, pkt_offset; - uint blk_num; - uint blk_size; - uint max_blk_count; - uint max_req_size; - struct mmc_request mmc_req; - struct mmc_command mmc_cmd; - struct mmc_data mmc_dat; - uint32 sg_count; - struct sdio_func *sdio_func = sd->func[func]; - struct mmc_host *host = sdio_func->card->host; - uint8 *localbuf = NULL; - uint local_plen = 0; - uint pkt_len = 0; - struct timespec now, before; - - sd_trace(("%s: Enter\n", __FUNCTION__)); - ASSERT(pkt); - DHD_PM_RESUME_WAIT(sdioh_request_packet_wait); - DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); - - if (sd_msglevel & SDH_COST_VAL) - getnstimeofday(&before); - - blk_size = sd->client_block_size[func]; - max_blk_count = min(host->max_blk_count, (uint)MAX_IO_RW_EXTENDED_BLK); - max_req_size = min(max_blk_count * blk_size, host->max_req_size); - - pkt_offset = 0; - pnext = pkt; - - ttl_len = 0; - sg_count = 0; - if(sd->txglom_mode == SDPCM_TXGLOM_MDESC) { - while (pnext != NULL) { - ttl_len = 0; - sg_count = 0; - memset(&mmc_req, 0, sizeof(struct mmc_request)); - memset(&mmc_cmd, 0, sizeof(struct mmc_command)); - memset(&mmc_dat, 0, sizeof(struct mmc_data)); - sg_init_table(sd->sg_list, ARRAYSIZE(sd->sg_list)); - - /* Set up scatter-gather DMA descriptors. this loop is to find out the max - * data we can transfer with one command 53. blocks per command is limited by - * host max_req_size and 9-bit max block number. when the total length of this - * packet chain is bigger than max_req_size, use multiple SD_IO_RW_EXTENDED - * commands (each transfer is still block aligned) - */ - while (pnext != NULL && ttl_len < max_req_size) { - int pkt_len; - int sg_data_size; - uint8 *pdata = (uint8*)PKTDATA(sd->osh, pnext); - - ASSERT(pdata != NULL); - pkt_len = PKTLEN(sd->osh, pnext); - sd_trace(("%s[%d] data=%p, len=%d\n", __FUNCTION__, write, pdata, pkt_len)); - /* sg_count is unlikely larger than the array size, and this is - * NOT something we can handle here, but in case it happens, PLEASE put - * a restriction on max tx/glom count (based on host->max_segs). - */ - if (sg_count >= ARRAYSIZE(sd->sg_list)) { - sd_err(("%s: sg list entries exceed limit %d\n", __FUNCTION__, sg_count)); - return (SDIOH_API_RC_FAIL); - } - pdata += pkt_offset; - - sg_data_size = pkt_len - pkt_offset; - if (sg_data_size > max_req_size - ttl_len) - sg_data_size = max_req_size - ttl_len; - /* some platforms put a restriction on the data size of each scatter-gather - * DMA descriptor, use multiple sg buffers when xfer_size is bigger than - * max_seg_size - */ - if (sg_data_size > host->max_seg_size) - sg_data_size = host->max_seg_size; - sg_set_buf(&sd->sg_list[sg_count++], pdata, sg_data_size); - - ttl_len += sg_data_size; - pkt_offset += sg_data_size; - if (pkt_offset == pkt_len) { - pnext = PKTNEXT(sd->osh, pnext); - pkt_offset = 0; - } - } - - if (ttl_len % blk_size != 0) { - sd_err(("%s, data length %d not aligned to block size %d\n", - __FUNCTION__, ttl_len, blk_size)); - return SDIOH_API_RC_FAIL; - } - blk_num = ttl_len / blk_size; - mmc_dat.sg = sd->sg_list; - mmc_dat.sg_len = sg_count; - mmc_dat.blksz = blk_size; - mmc_dat.blocks = blk_num; - mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; - mmc_cmd.opcode = 53; /* SD_IO_RW_EXTENDED */ - mmc_cmd.arg = write ? 1<<31 : 0; - mmc_cmd.arg |= (func & 0x7) << 28; - mmc_cmd.arg |= 1<<27; - mmc_cmd.arg |= fifo ? 0 : 1<<26; - mmc_cmd.arg |= (addr & 0x1FFFF) << 9; - mmc_cmd.arg |= blk_num & 0x1FF; - mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; - mmc_req.cmd = &mmc_cmd; - mmc_req.data = &mmc_dat; - if (!fifo) - addr += ttl_len; - - sdio_claim_host(sdio_func); - mmc_set_data_timeout(&mmc_dat, sdio_func->card); - mmc_wait_for_req(host, &mmc_req); - sdio_release_host(sdio_func); - - err_ret = mmc_cmd.error? mmc_cmd.error : mmc_dat.error; - if (0 != err_ret) { - sd_err(("%s:CMD53 %s failed with code %d\n", - __FUNCTION__, write ? "write" : "read", err_ret)); - return SDIOH_API_RC_FAIL; - } - } - } else if(sd->txglom_mode == SDPCM_TXGLOM_CPY) { - for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { - ttl_len += PKTLEN(sd->osh, pnext); - } - /* Claim host controller */ - sdio_claim_host(sd->func[func]); - for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { - uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext); - pkt_len = PKTLEN(sd->osh, pnext); - - if (!localbuf) { - localbuf = (uint8 *)MALLOC(sd->osh, ttl_len); - if (localbuf == NULL) { - sd_err(("%s: %s TXGLOM: localbuf malloc FAILED\n", - __FUNCTION__, (write) ? "TX" : "RX")); - goto txglomfail; - } - } - - bcopy(buf, (localbuf + local_plen), pkt_len); - local_plen += pkt_len; - if (PKTNEXT(sd->osh, pnext)) - continue; - - buf = localbuf; - pkt_len = local_plen; -txglomfail: - /* Align Patch */ - if (!write || pkt_len < 32) - pkt_len = (pkt_len + 3) & 0xFFFFFFFC; - else if (pkt_len % blk_size) - pkt_len += blk_size - (pkt_len % blk_size); - - if ((write) && (!fifo)) - err_ret = sdio_memcpy_toio( - sd->func[func], - addr, buf, pkt_len); - else if (write) - err_ret = sdio_memcpy_toio( - sd->func[func], - addr, buf, pkt_len); - else if (fifo) - err_ret = sdio_readsb( - sd->func[func], - buf, addr, pkt_len); - else - err_ret = sdio_memcpy_fromio( - sd->func[func], - buf, addr, pkt_len); - - if (err_ret) - sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=%d\n", - __FUNCTION__, - (write) ? "TX" : "RX", - pnext, sg_count, addr, pkt_len, err_ret)); - else - sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n", - __FUNCTION__, - (write) ? "TX" : "RX", - pnext, sg_count, addr, pkt_len)); - - if (!fifo) - addr += pkt_len; - sg_count ++; - } - sdio_release_host(sd->func[func]); - } else { - sd_err(("%s: set to wrong glom mode %d\n", __FUNCTION__, sd->txglom_mode)); - return SDIOH_API_RC_FAIL; - } - - if (localbuf) - MFREE(sd->osh, localbuf, ttl_len); - - if (sd_msglevel & SDH_COST_VAL) { - getnstimeofday(&now); - sd_cost(("%s: rw=%d, ttl_len=%d, cost=%lds %luus\n", __FUNCTION__, - write, ttl_len, now.tv_sec-before.tv_sec, now.tv_nsec/1000-before.tv_nsec/1000)); - } - - sd_trace(("%s: Exit\n", __FUNCTION__)); - return SDIOH_API_RC_SUCCESS; -} -#endif /* BCMSDIOH_TXGLOM */ - -static SDIOH_API_RC -sdioh_buffer_tofrom_bus(sdioh_info_t *sd, uint fix_inc, uint write, uint func, - uint addr, uint8 *buf, uint len) -{ - bool fifo = (fix_inc == SDIOH_DATA_FIX); - int err_ret = 0, try_cnt = 2; - struct timespec now, before; - - sd_trace(("%s: Enter\n", __FUNCTION__)); - ASSERT(buf); - - if (sd_msglevel & SDH_COST_VAL) - getnstimeofday(&before); - - /* NOTE: - * For all writes, each packet length is aligned to 32 (or 4) - * bytes in dhdsdio_txpkt_preprocess, and for glom the last packet length - * is aligned to block boundary. If you want to align each packet to - * a custom size, please do it in dhdsdio_txpkt_preprocess, NOT here - * - * For reads, the alignment is doen in sdioh_request_buffer. - * - */ - while (try_cnt) { - sdio_claim_host(sd->func[func]); - - if ((write) && (!fifo)) - err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, len); - else if (write) - err_ret = sdio_memcpy_toio(sd->func[func], addr, buf, len); - else if (fifo) - err_ret = sdio_readsb(sd->func[func], buf, addr, len); - else - err_ret = sdio_memcpy_fromio(sd->func[func], buf, addr, len); - - sdio_release_host(sd->func[func]); - - try_cnt--; - if (err_ret) { - sd_err(("%s: %s FAILED %p, addr=0x%05x, pkt_len=%d, ERR=%d\n", __FUNCTION__, - (write) ? "TX" : "RX", buf, addr, len, err_ret)); - if (err_ret != -EILSEQ) { - break; - } - } else { - sd_trace(("%s: %s xfr'd %p, addr=0x%05x, len=%d\n", __FUNCTION__, - (write) ? "TX" : "RX", buf, addr, len)); - break; - } - } - - sd_trace(("%s: Exit\n", __FUNCTION__)); - - if (sd_msglevel & SDH_COST_VAL) { - getnstimeofday(&now); - sd_cost(("%s: rw=%d, len=%d cost=%lds %luus\n", __FUNCTION__, - write, len, now.tv_sec-before.tv_sec, now.tv_nsec/1000 - before.tv_nsec/1000)); - } - - return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -} - - -/* - * This function takes a buffer or packet, and fixes everything up so that in the - * end, a DMA-able packet is created. - * - * A buffer does not have an associated packet pointer, and may or may not be aligned. - * A packet may consist of a single packet, or a packet chain. If it is a packet chain, - * then all the packets in the chain must be properly aligned. If the packet data is not - * aligned, then there may only be one packet, and in this case, it is copied to a new - * aligned packet. - * - */ -extern SDIOH_API_RC -sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func, - uint addr, uint reg_width, uint buf_len, uint8 *buffer, void *pkt) -{ - SDIOH_API_RC status; - void *tmppkt; - struct timespec now, before; - - sd_trace(("%s: Enter\n", __FUNCTION__)); - DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait); - DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); - - if (sd_msglevel & SDH_COST_VAL) - getnstimeofday(&before); - - if (pkt) { -#ifdef BCMSDIOH_TXGLOM - /* packet chain, only used for tx/rx glom, all packets length - * are aligned, total length is a block multiple - */ - if (PKTNEXT(sd->osh, pkt)) - return sdioh_request_packet_chain(sd, fix_inc, write, func, addr, pkt); -#endif /* BCMSDIOH_TXGLOM */ - /* non-glom mode, ignore the buffer parameter and use the packet pointer - * (this shouldn't happen) - */ - buffer = PKTDATA(sd->osh, pkt); - buf_len = PKTLEN(sd->osh, pkt); - } - - ASSERT(buffer); - - /* buffer and length are aligned, use it directly so we can avoid memory copy */ - if (((ulong)buffer & DMA_ALIGN_MASK) == 0 && (buf_len & DMA_ALIGN_MASK) == 0) - return sdioh_buffer_tofrom_bus(sd, fix_inc, write, func, addr, buffer, buf_len); - - sd_trace(("%s: [%d] doing memory copy buf=%p, len=%d\n", - __FUNCTION__, write, buffer, buf_len)); - - /* otherwise, a memory copy is needed as the input buffer is not aligned */ - tmppkt = PKTGET_STATIC(sd->osh, buf_len + DEFAULT_SDIO_F2_BLKSIZE, write ? TRUE : FALSE); - if (tmppkt == NULL) { - sd_err(("%s: PKTGET failed: len %d\n", __FUNCTION__, buf_len)); - return SDIOH_API_RC_FAIL; - } - - if (write) - bcopy(buffer, PKTDATA(sd->osh, tmppkt), buf_len); - - status = sdioh_buffer_tofrom_bus(sd, fix_inc, write, func, addr, - PKTDATA(sd->osh, tmppkt), ROUNDUP(buf_len, (DMA_ALIGN_MASK+1))); - - if (!write) - bcopy(PKTDATA(sd->osh, tmppkt), buffer, buf_len); - - PKTFREE_STATIC(sd->osh, tmppkt, write ? TRUE : FALSE); - - if (sd_msglevel & SDH_COST_VAL) { - getnstimeofday(&now); - sd_cost(("%s: len=%d cost=%lds %luus\n", __FUNCTION__, - buf_len, now.tv_sec-before.tv_sec, now.tv_nsec/1000 - before.tv_nsec/1000)); - } - - return status; -} - -/* this function performs "abort" for both of host & device */ -extern int -sdioh_abort(sdioh_info_t *sd, uint func) -{ -#if defined(MMC_SDIO_ABORT) - char t_func = (char) func; -#endif /* defined(MMC_SDIO_ABORT) */ - sd_trace(("%s: Enter\n", __FUNCTION__)); - -#if defined(MMC_SDIO_ABORT) - /* issue abort cmd52 command through F1 */ - sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func); -#endif /* defined(MMC_SDIO_ABORT) */ - - sd_trace(("%s: Exit\n", __FUNCTION__)); - return SDIOH_API_RC_SUCCESS; -} - -/* Reset and re-initialize the device */ -int sdioh_sdio_reset(sdioh_info_t *si) -{ - sd_trace(("%s: Enter\n", __FUNCTION__)); - sd_trace(("%s: Exit\n", __FUNCTION__)); - return SDIOH_API_RC_SUCCESS; -} - -/* Disable device interrupt */ -void -sdioh_sdmmc_devintr_off(sdioh_info_t *sd) -{ - sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); - sd->intmask &= ~CLIENT_INTR; -} - -/* Enable device interrupt */ -void -sdioh_sdmmc_devintr_on(sdioh_info_t *sd) -{ - sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); - sd->intmask |= CLIENT_INTR; -} - -/* Read client card reg */ -int -sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) -{ - - if ((func == 0) || (regsize == 1)) { - uint8 temp = 0; - - sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); - *data = temp; - *data &= 0xff; - sd_data(("%s: byte read data=0x%02x\n", - __FUNCTION__, *data)); - } else { - if (sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize)) { - return BCME_SDIO_ERROR; - } - - if (regsize == 2) - *data &= 0xffff; - - sd_data(("%s: word read data=0x%08x\n", - __FUNCTION__, *data)); - } - - return SUCCESS; -} - -#if !defined(OOB_INTR_ONLY) -/* bcmsdh_sdmmc interrupt handler */ -static void IRQHandler(struct sdio_func *func) -{ - sdioh_info_t *sd; - - sd = sdio_get_drvdata(func); - - ASSERT(sd != NULL); - sdio_release_host(sd->func[0]); - - if (sd->use_client_ints) { - sd->intrcount++; - ASSERT(sd->intr_handler); - ASSERT(sd->intr_handler_arg); - (sd->intr_handler)(sd->intr_handler_arg); - } else { - sd_err(("bcmsdh_sdmmc: ***IRQHandler\n")); - - sd_err(("%s: Not ready for intr: enabled %d, handler %p\n", - __FUNCTION__, sd->client_intr_enabled, sd->intr_handler)); - } - - sdio_claim_host(sd->func[0]); -} - -/* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */ -static void IRQHandlerF2(struct sdio_func *func) -{ - sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n")); -} -#endif /* !defined(OOB_INTR_ONLY) */ - -#ifdef NOTUSED -/* Write client card reg */ -static int -sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) -{ - - if ((func == 0) || (regsize == 1)) { - uint8 temp; - - temp = data & 0xff; - sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp); - sd_data(("%s: byte write data=0x%02x\n", - __FUNCTION__, data)); - } else { - if (regsize == 2) - data &= 0xffff; - - sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize); - - sd_data(("%s: word write data=0x%08x\n", - __FUNCTION__, data)); - } - - return SUCCESS; -} -#endif /* NOTUSED */ - -int -sdioh_start(sdioh_info_t *sd, int stage) -{ - int ret; - - if (!sd) { - sd_err(("%s Failed, sd is NULL\n", __FUNCTION__)); - return (0); - } - - /* Need to do this stages as we can't enable the interrupt till - downloading of the firmware is complete, other wise polling - sdio access will come in way - */ - if (sd->func[0]) { - if (stage == 0) { - /* Since the power to the chip is killed, we will have - re enumerate the device again. Set the block size - and enable the fucntion 1 for in preparation for - downloading the code - */ - /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux - 2.6.27. The implementation prior to that is buggy, and needs broadcom's - patch for it - */ - /* if chip alive, skip do sdio_reset_comm() */ - if (!dhd_chip_alive) { - printk("chip not alive, do sdio_reset_comm\n"); - if ((ret = sdio_reset_comm(sd->func[0]->card))) { - sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret)); - return ret; - } - else { - sd->num_funcs = 2; - sd->sd_blockmode = TRUE; - sd->use_client_ints = TRUE; - sd->client_block_size[0] = 64; - - if (sd->func[1]) { - /* Claim host controller */ - sdio_claim_host(sd->func[1]); - - sd->client_block_size[1] = 64; - ret = sdio_set_block_size(sd->func[1], 64); - if (ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F1 " - "blocksize(%d)\n", ret)); - } - - /* Release host controller F1 */ - sdio_release_host(sd->func[1]); - } - - if (sd->func[2]) { - /* Claim host controller F2 */ - sdio_claim_host(sd->func[2]); - - sd->client_block_size[2] = sd_f2_blocksize; - sd_info(("%s: set sd_f2_blocksize %d\n", __FUNCTION__, sd_f2_blocksize)); - ret = sdio_set_block_size(sd->func[2], sd_f2_blocksize); - if (ret) { - sd_err(("bcmsdh_sdmmc: Failed to set F2 " - "blocksize to %d(%d)\n", sd_f2_blocksize, ret)); - } - - /* Release host controller F2 */ - sdio_release_host(sd->func[2]); - } - - sdioh_sdmmc_card_enablefuncs(sd); - } - } - } else { -#if !defined(OOB_INTR_ONLY) - sdio_claim_host(sd->func[0]); - if (sd->func[2]) - sdio_claim_irq(sd->func[2], IRQHandlerF2); - if (sd->func[1]) - sdio_claim_irq(sd->func[1], IRQHandler); - sdio_release_host(sd->func[0]); -#else /* defined(OOB_INTR_ONLY) */ -#if defined(HW_OOB) - sdioh_enable_func_intr(sd); -#endif - bcmsdh_oob_intr_set(sd->bcmsdh, TRUE); -#endif /* !defined(OOB_INTR_ONLY) */ - } - } - else - sd_err(("%s Failed\n", __FUNCTION__)); - - return (0); -} - -int -sdioh_stop(sdioh_info_t *sd) -{ - /* MSM7201A Android sdio stack has bug with interrupt - So internaly within SDIO stack they are polling - which cause issue when device is turned off. So - unregister interrupt with SDIO stack to stop the - polling - */ - if (sd->func[0]) { -#if !defined(OOB_INTR_ONLY) - sdio_claim_host(sd->func[0]); - if (sd->func[1]) - sdio_release_irq(sd->func[1]); - if (sd->func[2]) - sdio_release_irq(sd->func[2]); - sdio_release_host(sd->func[0]); -#else /* defined(OOB_INTR_ONLY) */ -#if defined(HW_OOB) - sdioh_disable_func_intr(sd); -#endif - bcmsdh_oob_intr_set(sd->bcmsdh, FALSE); -#endif /* !defined(OOB_INTR_ONLY) */ - } - else - sd_err(("%s Failed\n", __FUNCTION__)); - return (0); -} - -int -sdioh_waitlockfree(sdioh_info_t *sd) -{ - return (1); -} - - -SDIOH_API_RC -sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) -{ - return SDIOH_API_RC_FAIL; -} - -SDIOH_API_RC -sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) -{ - return SDIOH_API_RC_FAIL; -} - -bool -sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) -{ - return FALSE; -} - -SDIOH_API_RC -sdioh_gpio_init(sdioh_info_t *sd) -{ - return SDIOH_API_RC_FAIL; -} - -uint -sdmmc_get_clock_rate(sdioh_info_t *sd) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) - return 0; -#else - struct sdio_func *sdio_func = sd->func[0]; - struct mmc_host *host = sdio_func->card->host; - return mmc_host_clk_rate(host); -#endif -} - - -void -sdmmc_set_clock_rate(sdioh_info_t *sd, uint hz) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) - return; -#else - struct sdio_func *sdio_func = sd->func[0]; - struct mmc_host *host = sdio_func->card->host; - struct mmc_ios *ios = &host->ios; - - mmc_host_clk_hold(host); - DHD_INFO(("%s: Before change: sd clock rate is %u\n", __FUNCTION__, ios->clock)); - if (hz < host->f_min) { - DHD_ERROR(("%s: Intended rate is below min rate, setting to min\n", __FUNCTION__)); - hz = host->f_min; - } - - if (hz > host->f_max) { - DHD_ERROR(("%s: Intended rate exceeds max rate, setting to max\n", __FUNCTION__)); - hz = host->f_max; - } - ios->clock = hz; - host->ops->set_ios(host, ios); - DHD_ERROR(("%s: After change: sd clock rate is %u\n", __FUNCTION__, ios->clock)); - mmc_host_clk_release(host); -#endif -} - -void -sdmmc_set_clock_divisor(sdioh_info_t *sd, uint sd_div) -{ - uint hz; - uint old_div = sdmmc_get_clock_rate(sd); - if (old_div == sd_div) { - return; - } - - hz = sd->sd_clk_rate / sd_div; - sdmmc_set_clock_rate(sd, hz); -}
diff --git a/bcmdhd.1.579.77.41.x/bcmsdh_sdmmc_linux.c b/bcmdhd.1.579.77.41.x/bcmsdh_sdmmc_linux.c deleted file mode 100644 index bc6c000..0000000 --- a/bcmdhd.1.579.77.41.x/bcmsdh_sdmmc_linux.c +++ /dev/null
@@ -1,416 +0,0 @@ -/* - * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Proprietary,Open:>> - * - * $Id: bcmsdh_sdmmc_linux.c 644124 2016-06-17 07:59:34Z $ - */ - -#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> - -#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 - -#if !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) -#define SDIO_DEVICE_ID_BROADCOM_4325_SDGWB 0x0492 /* BCM94325SDGWB */ -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4325) -#define SDIO_DEVICE_ID_BROADCOM_4325 0x0493 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4329) -#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4319) -#define SDIO_DEVICE_ID_BROADCOM_4319 0x4319 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4319) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4330) -#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4330) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4334) -#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4334) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_4324) -#define SDIO_DEVICE_ID_BROADCOM_4324 0x4324 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4324) */ -#if !defined(SDIO_DEVICE_ID_BROADCOM_43239) -#define SDIO_DEVICE_ID_BROADCOM_43239 43239 -#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_43239) */ - -extern void wl_cfg80211_set_parent_dev(void *dev); -extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); -extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); -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_info(("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_info(("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 - - /* 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); -#ifndef RMMOD_KEEP_F2 - sdioh_detach(osh, sdioh); -#endif - 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_info(("%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, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4324) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, 0xa9bf) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, 0xa804) }, - { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) }, - { 0, 0, 0, 0 /* end: all zeroes */ - }, -}; - -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; - - DHD_TRACE(("%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) { - DHD_ERROR(("%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(); - - DHD_TRACE(("%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); - - DHD_TRACE(("%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(); - DHD_TRACE(("%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) { - DHD_INFO(("dummy probe func %d\n",func->num)); - if (func->num != 2) - return 0; - } - - if (notify_semaphore){ - DHD_INFO(("notify semahore\n")); - 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); -}
diff --git a/bcmdhd.1.579.77.41.x/bcmsdspi.c b/bcmdhd.1.579.77.41.x/bcmsdspi.c deleted file mode 100644 index 8f2a9f8..0000000 --- a/bcmdhd.1.579.77.41.x/bcmsdspi.c +++ /dev/null
@@ -1,1640 +0,0 @@ -/* - * Broadcom BCMSDH to SPI Protocol Conversion Layer - * - * Copyright (C) 1999-2016, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: bcmsdspi.c 514727 2014-11-12 03:02:48Z $ - */ - -#include <typedefs.h> - -#include <bcmdevs.h> -#include <bcmendian.h> -#include <bcmutils.h> -#include <osl.h> -#include <siutils.h> -#include <sdio.h> /* SDIO Device and Protocol Specs */ -#include <sdioh.h> /* Standard SDIO Host Controller Specification */ -#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */ -#include <sdiovar.h> /* ioctl/iovars */ - -#include <pcicfg.h> - - -#include <bcmsdspi.h> -#include <bcmspi.h> - -#include <proto/sdspi.h> - -#define SD_PAGE 4096 - - - -/* Globals */ - -uint sd_msglevel = SDH_ERROR_VAL; -uint sd_hiok = FALSE; /* Use hi-speed mode if available? */ -uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */ -uint sd_f2_blocksize = 512; /* Default blocksize */ - -uint sd_divisor = 2; /* Default 33MHz/2 = 16MHz for dongle */ -uint sd_power = 1; /* Default to SD Slot powered ON */ -uint sd_clock = 1; /* Default to SD Clock turned ON */ -uint sd_crc = 0; /* Default to SPI CRC Check turned OFF */ -uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */ - -uint sd_toctl = 7; - -/* Prototypes */ -static bool sdspi_start_power(sdioh_info_t *sd); -static int sdspi_set_highspeed_mode(sdioh_info_t *sd, bool HSMode); -static int sdspi_card_enablefuncs(sdioh_info_t *sd); -static void sdspi_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count); -static int sdspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd, uint32 arg, - uint32 *data, uint32 datalen); -static int sdspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, - int regsize, uint32 *data); -static int sdspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, - int regsize, uint32 data); -static int sdspi_driver_init(sdioh_info_t *sd); -static bool sdspi_reset(sdioh_info_t *sd, bool host_reset, bool client_reset); -static int sdspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, - uint32 addr, int nbytes, uint32 *data); -static int sdspi_abort(sdioh_info_t *sd, uint func); - -static int set_client_block_size(sdioh_info_t *sd, int func, int blocksize); - -static uint8 sdspi_crc7(unsigned char* p, uint32 len); -static uint16 sdspi_crc16(unsigned char* p, uint32 len); -static int sdspi_crc_onoff(sdioh_info_t *sd, bool use_crc); - -/* - * Public entry points & extern's - */ -extern sdioh_info_t * -sdioh_attach(osl_t *osh, void *bar0, uint irq) -{ - sdioh_info_t *sd; - - sd_trace(("%s\n", __FUNCTION__)); - if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { - sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh))); - return NULL; - } - bzero((char *)sd, sizeof(sdioh_info_t)); - sd->osh = osh; - - if (spi_osinit(sd) != 0) { - sd_err(("%s: spi_osinit() failed\n", __FUNCTION__)); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return NULL; - } - - sd->bar0 = (uintptr)bar0; - sd->irq = irq; - sd->intr_handler = NULL; - sd->intr_handler_arg = NULL; - sd->intr_handler_valid = FALSE; - - /* Set defaults */ - sd->sd_blockmode = FALSE; - sd->use_client_ints = TRUE; - sd->sd_use_dma = FALSE; /* DMA Not supported */ - - /* Haven't figured out how to make bytemode work with dma */ - if (!sd->sd_blockmode) - sd->sd_use_dma = 0; - - if (!spi_hw_attach(sd)) { - sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__)); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return NULL; - } - - if (sdspi_driver_init(sd) != SUCCESS) { - if (sdspi_driver_init(sd) != SUCCESS) { - sd_err(("%s:sdspi_driver_init() failed()\n", __FUNCTION__)); - spi_hw_detach(sd); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return (NULL); - } - } - - if (spi_register_irq(sd, irq) != SUCCESS) { - sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq)); - spi_hw_detach(sd); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return (NULL); - } - - sd_trace(("%s: Done\n", __FUNCTION__)); - return sd; -} - -extern SDIOH_API_RC -sdioh_detach(osl_t *osh, sdioh_info_t *sd) -{ - sd_trace(("%s\n", __FUNCTION__)); - - if (sd) { - if (sd->card_init_done) - sdspi_reset(sd, 1, 1); - - sd_info(("%s: detaching from hardware\n", __FUNCTION__)); - spi_free_irq(sd->irq, sd); - spi_hw_detach(sd); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - } - - return SDIOH_API_RC_SUCCESS; -} - -/* Configure callback to client when we recieve client interrupt */ -extern SDIOH_API_RC -sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); - - sd->intr_handler = fn; - sd->intr_handler_arg = argh; - sd->intr_handler_valid = TRUE; - - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_interrupt_deregister(sdioh_info_t *sd) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); - - sd->intr_handler_valid = FALSE; - sd->intr_handler = NULL; - sd->intr_handler_arg = NULL; - - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); - - *onoff = sd->client_intr_enabled; - - return SDIOH_API_RC_SUCCESS; -} - -#if defined(DHD_DEBUG) -extern bool -sdioh_interrupt_pending(sdioh_info_t *sd) -{ - return 0; -} -#endif - -uint -sdioh_query_iofnum(sdioh_info_t *sd) -{ - return sd->num_funcs; -} - -/* IOVar table */ -enum { - IOV_MSGLEVEL = 1, - IOV_BLOCKMODE, - IOV_BLOCKSIZE, - IOV_DMA, - IOV_USEINTS, - IOV_NUMINTS, - IOV_NUMLOCALINTS, - IOV_HOSTREG, - IOV_DEVREG, - IOV_DIVISOR, - IOV_SDMODE, - IOV_HISPEED, - IOV_HCIREGS, - IOV_POWER, - IOV_CLOCK, - IOV_CRC -}; - -const bcm_iovar_t sdioh_iovars[] = { - {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, - {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 }, - {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ - {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, - {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, - {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, - {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, - {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, - {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, - {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, - {"sd_crc", IOV_CRC, 0, IOVT_UINT32, 0 }, - {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, - {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0}, - {NULL, 0, 0, 0, 0 } -}; - -int -sdioh_iovar_op(sdioh_info_t *si, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - const bcm_iovar_t *vi = NULL; - int bcmerror = 0; - int val_size; - int32 int_val = 0; - bool bool_val; - uint32 actionid; - - ASSERT(name); - ASSERT(len >= 0); - - /* Get must have return space; Set does not take qualifiers */ - ASSERT(set || (arg && len)); - ASSERT(!set || (!params && !plen)); - - sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); - - if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { - bcmerror = BCME_UNSUPPORTED; - goto exit; - } - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) - goto exit; - - /* Set up params so get and set can share the convenience variables */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - val_size = sizeof(int); - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - bool_val = (int_val != 0) ? TRUE : FALSE; - BCM_REFERENCE(bool_val); - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - switch (actionid) { - case IOV_GVAL(IOV_MSGLEVEL): - int_val = (int32)sd_msglevel; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_MSGLEVEL): - sd_msglevel = int_val; - break; - - case IOV_GVAL(IOV_BLOCKMODE): - int_val = (int32)si->sd_blockmode; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_BLOCKMODE): - si->sd_blockmode = (bool)int_val; - /* Haven't figured out how to make non-block mode with DMA */ - if (!si->sd_blockmode) - si->sd_use_dma = 0; - break; - - case IOV_GVAL(IOV_BLOCKSIZE): - if ((uint32)int_val > si->num_funcs) { - bcmerror = BCME_BADARG; - break; - } - int_val = (int32)si->client_block_size[int_val]; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_BLOCKSIZE): - { - uint func = ((uint32)int_val >> 16); - uint blksize = (uint16)int_val; - uint maxsize; - - if (func > si->num_funcs) { - bcmerror = BCME_BADARG; - break; - } - - switch (func) { - case 0: maxsize = 32; break; - case 1: maxsize = BLOCK_SIZE_4318; break; - case 2: maxsize = BLOCK_SIZE_4328; break; - default: maxsize = 0; - } - if (blksize > maxsize) { - bcmerror = BCME_BADARG; - break; - } - if (!blksize) { - blksize = maxsize; - } - - /* Now set it */ - spi_lock(si); - bcmerror = set_client_block_size(si, func, blksize); - spi_unlock(si); - break; - } - - case IOV_GVAL(IOV_DMA): - int_val = (int32)si->sd_use_dma; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DMA): - si->sd_use_dma = (bool)int_val; - break; - - case IOV_GVAL(IOV_USEINTS): - int_val = (int32)si->use_client_ints; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_USEINTS): - break; - - case IOV_GVAL(IOV_DIVISOR): - int_val = (uint32)sd_divisor; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DIVISOR): - sd_divisor = int_val; - if (!spi_start_clock(si, (uint16)sd_divisor)) { - sd_err(("set clock failed!\n")); - bcmerror = BCME_ERROR; - } - break; - - case IOV_GVAL(IOV_POWER): - int_val = (uint32)sd_power; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_POWER): - sd_power = int_val; - break; - - case IOV_GVAL(IOV_CLOCK): - int_val = (uint32)sd_clock; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_CLOCK): - sd_clock = int_val; - break; - - case IOV_GVAL(IOV_CRC): - int_val = (uint32)sd_crc; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_CRC): - /* Apply new setting, but don't change sd_crc until - * after the CRC-mode is selected in the device. This - * is required because the software must generate a - * correct CRC for the CMD59 in order to be able to - * turn OFF the CRC. - */ - sdspi_crc_onoff(si, int_val ? 1 : 0); - sd_crc = int_val; - break; - - case IOV_GVAL(IOV_SDMODE): - int_val = (uint32)sd_sdmode; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SDMODE): - sd_sdmode = int_val; - break; - - case IOV_GVAL(IOV_HISPEED): - int_val = (uint32)sd_hiok; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_HISPEED): - sd_hiok = int_val; - - if (!sdspi_set_highspeed_mode(si, (bool)sd_hiok)) { - sd_err(("Failed changing highspeed mode to %d.\n", sd_hiok)); - bcmerror = BCME_ERROR; - return ERROR; - } - break; - - case IOV_GVAL(IOV_NUMINTS): - int_val = (int32)si->intrcount; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_NUMLOCALINTS): - int_val = (int32)si->local_intrcount; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_HOSTREG): - { - break; - } - - case IOV_SVAL(IOV_HOSTREG): - { - sd_err(("IOV_HOSTREG unsupported\n")); - break; - } - - case IOV_GVAL(IOV_DEVREG): - { - sdreg_t *sd_ptr = (sdreg_t *)params; - uint8 data; - - if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { - bcmerror = BCME_SDIO_ERROR; - break; - } - - int_val = (int)data; - bcopy(&int_val, arg, sizeof(int_val)); - break; - } - - case IOV_SVAL(IOV_DEVREG): - { - sdreg_t *sd_ptr = (sdreg_t *)params; - uint8 data = (uint8)sd_ptr->value; - - if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { - bcmerror = BCME_SDIO_ERROR; - break; - } - break; - } - - - default: - bcmerror = BCME_UNSUPPORTED; - break; - } -exit: - - return bcmerror; -} - -extern SDIOH_API_RC -sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -{ - SDIOH_API_RC status; - /* No lock needed since sdioh_request_byte does locking */ - status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); - return status; -} - -extern SDIOH_API_RC -sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -{ - /* No lock needed since sdioh_request_byte does locking */ - SDIOH_API_RC status; - status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); - return status; -} - -extern SDIOH_API_RC -sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) -{ - uint32 count; - int offset; - uint32 foo; - uint8 *cis = cisd; - - sd_trace(("%s: Func = %d\n", __FUNCTION__, func)); - - if (!sd->func_cis_ptr[func]) { - bzero(cis, length); - return SDIOH_API_RC_FAIL; - } - - spi_lock(sd); - *cis = 0; - for (count = 0; count < length; count++) { - offset = sd->func_cis_ptr[func] + count; - if (sdspi_card_regread (sd, 0, offset, 1, &foo) < 0) { - sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); - spi_unlock(sd); - return SDIOH_API_RC_FAIL; - } - *cis = (uint8)(foo & 0xff); - cis++; - } - spi_unlock(sd); - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) -{ - int status; - uint32 cmd_arg; - uint32 rsp5; - - spi_lock(sd); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, rw == SDIOH_READ ? 0 : 1); - cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0); - cmd_arg = SFIELD(cmd_arg, CMD52_DATA, rw == SDIOH_READ ? 0 : *byte); - - sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x\n", __FUNCTION__, rw, func, regaddr)); - - if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, - SDIOH_CMD_52, cmd_arg, NULL, 0)) != SUCCESS) { - spi_unlock(sd); - return status; - } - - sdspi_cmd_getrsp(sd, &rsp5, 1); - if (rsp5 != 0x00) { - sd_err(("%s: rsp5 flags is 0x%x func=%d\n", - __FUNCTION__, rsp5, func)); - /* ASSERT(0); */ - spi_unlock(sd); - return SDIOH_API_RC_FAIL; - } - - if (rw == SDIOH_READ) - *byte = sd->card_rsp_data >> 24; - - spi_unlock(sd); - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, - uint32 *word, uint nbytes) -{ - int status; - - spi_lock(sd); - - if (rw == SDIOH_READ) - status = sdspi_card_regread(sd, func, addr, nbytes, word); - else - status = sdspi_card_regwrite(sd, func, addr, nbytes, *word); - - spi_unlock(sd); - return (status == SUCCESS ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -} - -extern SDIOH_API_RC -sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func, - uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) -{ - int len; - int buflen = (int)buflen_u; - bool fifo = (fix_inc == SDIOH_DATA_FIX); - - - spi_lock(sd); - - ASSERT(reg_width == 4); - ASSERT(buflen_u < (1 << 30)); - ASSERT(sd->client_block_size[func]); - - sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n", - __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W', - buflen_u, sd->r_cnt, sd->t_cnt, pkt)); - - /* Break buffer down into blocksize chunks: - * Bytemode: 1 block at a time. - */ - while (buflen > 0) { - if (sd->sd_blockmode) { - /* Max xfer is Page size */ - len = MIN(SD_PAGE, buflen); - - /* Round down to a block boundry */ - if (buflen > sd->client_block_size[func]) - len = (len/sd->client_block_size[func]) * - sd->client_block_size[func]; - } else { - /* Byte mode: One block at a time */ - len = MIN(sd->client_block_size[func], buflen); - } - - if (sdspi_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) { - spi_unlock(sd); - return SDIOH_API_RC_FAIL; - } - buffer += len; - buflen -= len; - if (!fifo) - addr += len; - } - spi_unlock(sd); - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_sleep(sdioh_info_t *sd, bool enab) -{ - return SDIOH_API_RC_FAIL; -} - -static int -sdspi_abort(sdioh_info_t *sd, uint func) -{ - uint8 spi_databuf[] = { 0x74, 0x80, 0x00, 0x0C, 0xFF, 0x95, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - uint8 spi_rspbuf[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - int err = 0; - - sd_err(("Sending SPI Abort to F%d\n", func)); - spi_databuf[4] = func & 0x7; - /* write to function 0, addr 6 (IOABORT) func # in 3 LSBs. */ - spi_sendrecv(sd, spi_databuf, spi_rspbuf, sizeof(spi_databuf)); - - return err; -} - -extern int -sdioh_abort(sdioh_info_t *sd, uint fnum) -{ - int ret; - - spi_lock(sd); - ret = sdspi_abort(sd, fnum); - spi_unlock(sd); - - return ret; -} - -int -sdioh_start(sdioh_info_t *sd, int stage) -{ - return SUCCESS; -} - -int -sdioh_stop(sdioh_info_t *sd) -{ - return SUCCESS; -} - -int -sdioh_waitlockfree(sdioh_info_t *sd) -{ - return SUCCESS; -} - - -/* - * Private/Static work routines - */ -static bool -sdspi_reset(sdioh_info_t *sd, bool host_reset, bool client_reset) -{ - if (!sd) - return TRUE; - - spi_lock(sd); - /* Reset client card */ - if (client_reset && (sd->adapter_slot != -1)) { - if (sdspi_card_regwrite(sd, 0, SDIOD_CCCR_IOABORT, 1, 0x8) != SUCCESS) - sd_err(("%s: Cannot write to card reg 0x%x\n", - __FUNCTION__, SDIOD_CCCR_IOABORT)); - else - sd->card_rca = 0; - } - - /* The host reset is a NOP in the sd-spi case. */ - if (host_reset) { - sd->sd_mode = SDIOH_MODE_SPI; - } - spi_unlock(sd); - return TRUE; -} - -static int -sdspi_host_init(sdioh_info_t *sd) -{ - sdspi_reset(sd, 1, 0); - - /* Default power on mode is SD1 */ - sd->sd_mode = SDIOH_MODE_SPI; - sd->polled_mode = TRUE; - sd->host_init_done = TRUE; - sd->card_init_done = FALSE; - sd->adapter_slot = 1; - - return (SUCCESS); -} - -#define CMD0_RETRIES 3 -#define CMD5_RETRIES 10 - -static int -get_ocr(sdioh_info_t *sd, uint32 *cmd_arg, uint32 *cmd_rsp) -{ - uint32 rsp5; - int retries, status; - - /* First issue a CMD0 to get the card into SPI mode. */ - for (retries = 0; retries <= CMD0_RETRIES; retries++) { - if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, - SDIOH_CMD_0, *cmd_arg, NULL, 0)) != SUCCESS) { - sd_err(("%s: No response to CMD0\n", __FUNCTION__)); - continue; - } - - sdspi_cmd_getrsp(sd, &rsp5, 1); - - if (GFIELD(rsp5, SPI_RSP_ILL_CMD)) { - printf("%s: Card already initialized (continuing)\n", __FUNCTION__); - break; - } - - if (GFIELD(rsp5, SPI_RSP_IDLE)) { - printf("%s: Card in SPI mode\n", __FUNCTION__); - break; - } - } - - if (retries > CMD0_RETRIES) { - sd_err(("%s: Too many retries for CMD0\n", __FUNCTION__)); - return ERROR; - } - - /* Get the Card's Operation Condition. */ - /* Occasionally the board takes a while to become ready. */ - for (retries = 0; retries <= CMD5_RETRIES; retries++) { - if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, - SDIOH_CMD_5, *cmd_arg, NULL, 0)) != SUCCESS) { - sd_err(("%s: No response to CMD5\n", __FUNCTION__)); - continue; - } - - printf("CMD5 response data was: 0x%08x\n", sd->card_rsp_data); - - if (GFIELD(sd->card_rsp_data, RSP4_CARD_READY)) { - printf("%s: Card ready\n", __FUNCTION__); - break; - } - } - - if (retries > CMD5_RETRIES) { - sd_err(("%s: Too many retries for CMD5\n", __FUNCTION__)); - return ERROR; - } - - *cmd_rsp = sd->card_rsp_data; - - sdspi_crc_onoff(sd, sd_crc ? 1 : 0); - - return (SUCCESS); -} - -static int -sdspi_crc_onoff(sdioh_info_t *sd, bool use_crc) -{ - uint32 args; - int status; - - args = use_crc ? 1 : 0; - if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, - SDIOH_CMD_59, args, NULL, 0)) != SUCCESS) { - sd_err(("%s: No response to CMD59\n", __FUNCTION__)); - } - - sd_info(("CMD59 response data was: 0x%08x\n", sd->card_rsp_data)); - - sd_err(("SD-SPI CRC turned %s\n", use_crc ? "ON" : "OFF")); - return (SUCCESS); -} - -static int -sdspi_client_init(sdioh_info_t *sd) -{ - uint8 fn_ints; - - sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot)); - - /* Start at ~400KHz clock rate for initialization */ - if (!spi_start_clock(sd, 128)) { - sd_err(("spi_start_clock failed\n")); - return ERROR; - } - - if (!sdspi_start_power(sd)) { - sd_err(("sdspi_start_power failed\n")); - return ERROR; - } - - if (sd->num_funcs == 0) { - sd_err(("%s: No IO funcs!\n", __FUNCTION__)); - return ERROR; - } - - sdspi_card_enablefuncs(sd); - - set_client_block_size(sd, 1, BLOCK_SIZE_4318); - fn_ints = INTR_CTL_FUNC1_EN; - - if (sd->num_funcs >= 2) { - set_client_block_size(sd, 2, sd_f2_blocksize /* BLOCK_SIZE_4328 */); - fn_ints |= INTR_CTL_FUNC2_EN; - } - - - /* Enable/Disable Client interrupts */ - /* Turn on here but disable at host controller */ - if (sdspi_card_regwrite(sd, 0, SDIOD_CCCR_INTEN, 1, - (fn_ints | INTR_CTL_MASTER_EN)) != SUCCESS) { - sd_err(("%s: Could not enable ints in CCCR\n", __FUNCTION__)); - return ERROR; - } - - /* Switch to High-speed clocking mode if both host and device support it */ - sdspi_set_highspeed_mode(sd, (bool)sd_hiok); - - /* After configuring for High-Speed mode, set the desired clock rate. */ - if (!spi_start_clock(sd, (uint16)sd_divisor)) { - sd_err(("spi_start_clock failed\n")); - return ERROR; - } - - sd->card_init_done = TRUE; - - return SUCCESS; -} - -static int -sdspi_set_highspeed_mode(sdioh_info_t *sd, bool HSMode) -{ - uint32 regdata; - int status; - bool hsmode; - - if (HSMode == TRUE) { - - sd_err(("Attempting to enable High-Speed mode.\n")); - - if ((status = sdspi_card_regread(sd, 0, SDIOD_CCCR_SPEED_CONTROL, - 1, ®data)) != SUCCESS) { - return status; - } - if (regdata & SDIO_SPEED_SHS) { - sd_err(("Device supports High-Speed mode.\n")); - - regdata |= SDIO_SPEED_EHS; - - sd_err(("Writing %08x to Card at %08x\n", - regdata, SDIOD_CCCR_SPEED_CONTROL)); - if ((status = sdspi_card_regwrite(sd, 0, SDIOD_CCCR_SPEED_CONTROL, - 1, regdata)) != BCME_OK) { - return status; - } - - hsmode = 1; - - sd_err(("High-speed clocking mode enabled.\n")); - } - else { - sd_err(("Device does not support High-Speed Mode.\n")); - hsmode = 0; - } - } else { - if ((status = sdspi_card_regread(sd, 0, SDIOD_CCCR_SPEED_CONTROL, - 1, ®data)) != SUCCESS) { - return status; - } - - regdata = ~SDIO_SPEED_EHS; - - sd_err(("Writing %08x to Card at %08x\n", - regdata, SDIOD_CCCR_SPEED_CONTROL)); - if ((status = sdspi_card_regwrite(sd, 0, SDIOD_CCCR_SPEED_CONTROL, - 1, regdata)) != BCME_OK) { - return status; - } - - sd_err(("Low-speed clocking mode enabled.\n")); - hsmode = 0; - } - - spi_controller_highspeed_mode(sd, hsmode); - - return TRUE; -} - -bool -sdspi_start_power(sdioh_info_t *sd) -{ - uint32 cmd_arg; - uint32 cmd_rsp; - - sd_trace(("%s\n", __FUNCTION__)); - - /* Get the Card's Operation Condition. Occasionally the board - * takes a while to become ready - */ - - cmd_arg = 0; - if (get_ocr(sd, &cmd_arg, &cmd_rsp) != SUCCESS) { - sd_err(("%s: Failed to get OCR; bailing\n", __FUNCTION__)); - return FALSE; - } - - sd_err(("mem_present = %d\n", GFIELD(cmd_rsp, RSP4_MEM_PRESENT))); - sd_err(("num_funcs = %d\n", GFIELD(cmd_rsp, RSP4_NUM_FUNCS))); - sd_err(("card_ready = %d\n", GFIELD(cmd_rsp, RSP4_CARD_READY))); - sd_err(("OCR = 0x%x\n", GFIELD(cmd_rsp, RSP4_IO_OCR))); - - /* Verify that the card supports I/O mode */ - if (GFIELD(cmd_rsp, RSP4_NUM_FUNCS) == 0) { - sd_err(("%s: Card does not support I/O\n", __FUNCTION__)); - return ERROR; - } - - sd->num_funcs = GFIELD(cmd_rsp, RSP4_NUM_FUNCS); - - /* Examine voltage: Arasan only supports 3.3 volts, - * so look for 3.2-3.3 Volts and also 3.3-3.4 volts. - */ - - if ((GFIELD(cmd_rsp, RSP4_IO_OCR) & (0x3 << 20)) == 0) { - sd_err(("This client does not support 3.3 volts!\n")); - return ERROR; - } - - - return TRUE; -} - -static int -sdspi_driver_init(sdioh_info_t *sd) -{ - sd_trace(("%s\n", __FUNCTION__)); - - if ((sdspi_host_init(sd)) != SUCCESS) { - return ERROR; - } - - if (sdspi_client_init(sd) != SUCCESS) { - return ERROR; - } - - return SUCCESS; -} - -static int -sdspi_card_enablefuncs(sdioh_info_t *sd) -{ - int status; - uint32 regdata; - uint32 regaddr, fbraddr; - uint8 func; - uint8 *ptr; - - sd_trace(("%s\n", __FUNCTION__)); - /* Get the Card's common CIS address */ - ptr = (uint8 *) &sd->com_cis_ptr; - for (regaddr = SDIOD_CCCR_CISPTR_0; regaddr <= SDIOD_CCCR_CISPTR_2; regaddr++) { - if ((status = sdspi_card_regread (sd, 0, regaddr, 1, ®data)) != SUCCESS) - return status; - - *ptr++ = (uint8) regdata; - } - - /* Only the lower 17-bits are valid */ - sd->com_cis_ptr &= 0x0001FFFF; - sd->func_cis_ptr[0] = sd->com_cis_ptr; - sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); - - /* Get the Card's function CIS (for each function) */ - for (fbraddr = SDIOD_FBR_STARTADDR, func = 1; - func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { - ptr = (uint8 *) &sd->func_cis_ptr[func]; - for (regaddr = SDIOD_FBR_CISPTR_0; regaddr <= SDIOD_FBR_CISPTR_2; regaddr++) { - if ((status = sdspi_card_regread (sd, 0, regaddr + fbraddr, 1, ®data)) - != SUCCESS) - return status; - - *ptr++ = (uint8) regdata; - } - - /* Only the lower 17-bits are valid */ - sd->func_cis_ptr[func] &= 0x0001FFFF; - sd_info(("%s: Function %d CIS Ptr = 0x%x\n", - __FUNCTION__, func, sd->func_cis_ptr[func])); - } - - sd_info(("%s: write ESCI bit\n", __FUNCTION__)); - /* Enable continuous SPI interrupt (ESCI bit) */ - sdspi_card_regwrite(sd, 0, SDIOD_CCCR_BICTRL, 1, 0x60); - - sd_info(("%s: enable f1\n", __FUNCTION__)); - /* Enable function 1 on the card */ - regdata = SDIO_FUNC_ENABLE_1; - if ((status = sdspi_card_regwrite(sd, 0, SDIOD_CCCR_IOEN, 1, regdata)) != SUCCESS) - return status; - - sd_info(("%s: done\n", __FUNCTION__)); - return SUCCESS; -} - -/* Read client card reg */ -static int -sdspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) -{ - int status; - uint32 cmd_arg; - uint32 rsp5; - - cmd_arg = 0; - - if ((func == 0) || (regsize == 1)) { - cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, SDIOH_XFER_TYPE_READ); - cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0); - cmd_arg = SFIELD(cmd_arg, CMD52_DATA, 0); - - if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_52, cmd_arg, NULL, 0)) - != SUCCESS) - return status; - - sdspi_cmd_getrsp(sd, &rsp5, 1); - - if (rsp5 != 0x00) - sd_err(("%s: rsp5 flags is 0x%x\t %d\n", - __FUNCTION__, rsp5, func)); - - *data = sd->card_rsp_data >> 24; - } else { - cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, regsize); - cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1); - cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0); - cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_READ); - - sd->data_xfer_count = regsize; - - /* sdspi_cmd_issue() returns with the command complete bit - * in the ISR already cleared - */ - if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_53, cmd_arg, NULL, 0)) - != SUCCESS) - return status; - - sdspi_cmd_getrsp(sd, &rsp5, 1); - - if (rsp5 != 0x00) - sd_err(("%s: rsp5 flags is 0x%x\t %d\n", - __FUNCTION__, rsp5, func)); - - *data = sd->card_rsp_data; - if (regsize == 2) { - *data &= 0xffff; - } - - sd_info(("%s: CMD53 func %d, addr 0x%x, size %d, data 0x%08x\n", - __FUNCTION__, func, regaddr, regsize, *data)); - - - } - - return SUCCESS; -} - -/* write a client register */ -static int -sdspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) -{ - int status; - uint32 cmd_arg, rsp5, flags; - - cmd_arg = 0; - - if ((func == 0) || (regsize == 1)) { - cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, SDIOH_XFER_TYPE_WRITE); - cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0); - cmd_arg = SFIELD(cmd_arg, CMD52_DATA, data & 0xff); - if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_52, cmd_arg, NULL, 0)) - != SUCCESS) - return status; - - sdspi_cmd_getrsp(sd, &rsp5, 1); - flags = GFIELD(rsp5, RSP5_FLAGS); - if (flags && (flags != 0x10)) - sd_err(("%s: rsp5.rsp5.flags = 0x%x, expecting 0x10\n", - __FUNCTION__, flags)); - } - else { - cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, regsize); - cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1); - cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0); - cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_WRITE); - - sd->data_xfer_count = regsize; - sd->cmd53_wr_data = data; - - sd_info(("%s: CMD53 func %d, addr 0x%x, size %d, data 0x%08x\n", - __FUNCTION__, func, regaddr, regsize, data)); - - /* sdspi_cmd_issue() returns with the command complete bit - * in the ISR already cleared - */ - if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_53, cmd_arg, NULL, 0)) - != SUCCESS) - return status; - - sdspi_cmd_getrsp(sd, &rsp5, 1); - - if (rsp5 != 0x00) - sd_err(("%s: rsp5 flags = 0x%x, expecting 0x00\n", - __FUNCTION__, rsp5)); - - } - return SUCCESS; -} - -void -sdspi_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count /* num 32 bit words */) -{ - *rsp_buffer = sd->card_response; -} - -int max_errors = 0; - -#define SPI_MAX_PKT_LEN 768 -uint8 spi_databuf[SPI_MAX_PKT_LEN]; -uint8 spi_rspbuf[SPI_MAX_PKT_LEN]; - -/* datalen is used for CMD53 length only (0 for sd->data_xfer_count) */ -static int -sdspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd, uint32 arg, - uint32 *data, uint32 datalen) -{ - uint32 cmd_reg; - uint32 cmd_arg = arg; - uint8 cmd_crc = 0x95; /* correct CRC for CMD0 and don't care for others. */ - uint16 dat_crc; - uint8 cmd52data = 0; - uint32 i, j; - uint32 spi_datalen = 0; - uint32 spi_pre_cmd_pad = 0; - uint32 spi_max_response_pad = 128; - - cmd_reg = 0; - cmd_reg = SFIELD(cmd_reg, SPI_DIR, 1); - cmd_reg = SFIELD(cmd_reg, SPI_CMD_INDEX, cmd); - - if (GFIELD(cmd_arg, CMD52_RW_FLAG) == 1) { /* Same for CMD52 and CMD53 */ - cmd_reg = SFIELD(cmd_reg, SPI_RW, 1); - } - - switch (cmd) { - case SDIOH_CMD_59: /* CRC_ON_OFF (SPI Mode Only) - Response R1 */ - cmd52data = arg & 0x1; - case SDIOH_CMD_0: /* Set Card to Idle State - No Response */ - case SDIOH_CMD_5: /* Send Operation condition - Response R4 */ - sd_trace(("%s: CMD%d\n", __FUNCTION__, cmd)); - spi_datalen = 44; - spi_pre_cmd_pad = 12; - spi_max_response_pad = 28; - break; - - case SDIOH_CMD_3: /* Ask card to send RCA - Response R6 */ - case SDIOH_CMD_7: /* Select card - Response R1 */ - case SDIOH_CMD_15: /* Set card to inactive state - Response None */ - sd_err(("%s: CMD%d is invalid for SPI Mode.\n", __FUNCTION__, cmd)); - return ERROR; - break; - - case SDIOH_CMD_52: /* IO R/W Direct (single byte) - Response R5 */ - cmd52data = GFIELD(cmd_arg, CMD52_DATA); - cmd_arg = arg; - cmd_reg = SFIELD(cmd_reg, SPI_FUNC, GFIELD(cmd_arg, CMD52_FUNCTION)); - cmd_reg = SFIELD(cmd_reg, SPI_ADDR, GFIELD(cmd_arg, CMD52_REG_ADDR)); - /* Display trace for byte write */ - if (GFIELD(cmd_arg, CMD52_RW_FLAG) == 1) { - sd_trace(("%s: CMD52: Wr F:%d @0x%04x=%02x\n", - __FUNCTION__, - GFIELD(cmd_arg, CMD52_FUNCTION), - GFIELD(cmd_arg, CMD52_REG_ADDR), - cmd52data)); - } - - spi_datalen = 32; - spi_max_response_pad = 28; - - break; - case SDIOH_CMD_53: /* IO R/W Extended (multiple bytes/blocks) */ - cmd_arg = arg; - cmd_reg = SFIELD(cmd_reg, SPI_FUNC, GFIELD(cmd_arg, CMD53_FUNCTION)); - cmd_reg = SFIELD(cmd_reg, SPI_ADDR, GFIELD(cmd_arg, CMD53_REG_ADDR)); - cmd_reg = SFIELD(cmd_reg, SPI_BLKMODE, 0); - cmd_reg = SFIELD(cmd_reg, SPI_OPCODE, GFIELD(cmd_arg, CMD53_OP_CODE)); - cmd_reg = SFIELD(cmd_reg, SPI_STUFF0, (sd->data_xfer_count>>8)); - cmd52data = (uint8)sd->data_xfer_count; - - /* Set upper bit in byte count if necessary, but don't set it for 512 bytes. */ - if ((sd->data_xfer_count > 255) && (sd->data_xfer_count < 512)) { - cmd_reg |= 1; - } - - if (GFIELD(cmd_reg, SPI_RW) == 1) { /* Write */ - spi_max_response_pad = 32; - spi_datalen = (sd->data_xfer_count + spi_max_response_pad) & 0xFFFC; - } else { /* Read */ - - spi_max_response_pad = 32; - spi_datalen = (sd->data_xfer_count + spi_max_response_pad) & 0xFFFC; - } - sd_trace(("%s: CMD53: %s F:%d @0x%04x len=0x%02x\n", - __FUNCTION__, - (GFIELD(cmd_reg, SPI_RW) == 1 ? "Wr" : "Rd"), - GFIELD(cmd_arg, CMD53_FUNCTION), - GFIELD(cmd_arg, CMD53_REG_ADDR), - cmd52data)); - break; - - default: - sd_err(("%s: Unknown command %d\n", __FUNCTION__, cmd)); - return ERROR; - } - - /* Set up and issue the SDIO command */ - memset(spi_databuf, SDSPI_IDLE_PAD, spi_datalen); - spi_databuf[spi_pre_cmd_pad + 0] = (cmd_reg & 0xFF000000) >> 24; - spi_databuf[spi_pre_cmd_pad + 1] = (cmd_reg & 0x00FF0000) >> 16; - spi_databuf[spi_pre_cmd_pad + 2] = (cmd_reg & 0x0000FF00) >> 8; - spi_databuf[spi_pre_cmd_pad + 3] = (cmd_reg & 0x000000FF); - spi_databuf[spi_pre_cmd_pad + 4] = cmd52data; - - /* Generate CRC7 for command, if CRC is enabled, otherwise, a - * default CRC7 of 0x95, which is correct for CMD0, is used. - */ - if (sd_crc) { - cmd_crc = sdspi_crc7(&spi_databuf[spi_pre_cmd_pad], 5); - } - spi_databuf[spi_pre_cmd_pad + 5] = cmd_crc; -#define SPI_STOP_TRAN 0xFD - - /* for CMD53 Write, put the data into the output buffer */ - if ((cmd == SDIOH_CMD_53) && (GFIELD(cmd_arg, CMD53_RW_FLAG) == 1)) { - if (datalen != 0) { - spi_databuf[spi_pre_cmd_pad + 9] = SDSPI_IDLE_PAD; - spi_databuf[spi_pre_cmd_pad + 10] = SDSPI_START_BLOCK; - - for (i = 0; i < sd->data_xfer_count; i++) { - spi_databuf[i + 11 + spi_pre_cmd_pad] = ((uint8 *)data)[i]; - } - if (sd_crc) { - dat_crc = sdspi_crc16(&spi_databuf[spi_pre_cmd_pad+11], i); - } else { - dat_crc = 0xAAAA; - } - spi_databuf[i + 11 + spi_pre_cmd_pad] = (dat_crc >> 8) & 0xFF; - spi_databuf[i + 12 + spi_pre_cmd_pad] = dat_crc & 0xFF; - } else if (sd->data_xfer_count == 2) { - spi_databuf[spi_pre_cmd_pad + 9] = SDSPI_IDLE_PAD; - spi_databuf[spi_pre_cmd_pad + 10] = SDSPI_START_BLOCK; - spi_databuf[spi_pre_cmd_pad + 11] = sd->cmd53_wr_data & 0xFF; - spi_databuf[spi_pre_cmd_pad + 12] = (sd->cmd53_wr_data & 0x0000FF00) >> 8; - if (sd_crc) { - dat_crc = sdspi_crc16(&spi_databuf[spi_pre_cmd_pad+11], 2); - } else { - dat_crc = 0x22AA; - } - spi_databuf[spi_pre_cmd_pad + 13] = (dat_crc >> 8) & 0xFF; - spi_databuf[spi_pre_cmd_pad + 14] = (dat_crc & 0xFF); - } else if (sd->data_xfer_count == 4) { - spi_databuf[spi_pre_cmd_pad + 9] = SDSPI_IDLE_PAD; - spi_databuf[spi_pre_cmd_pad + 10] = SDSPI_START_BLOCK; - spi_databuf[spi_pre_cmd_pad + 11] = sd->cmd53_wr_data & 0xFF; - spi_databuf[spi_pre_cmd_pad + 12] = (sd->cmd53_wr_data & 0x0000FF00) >> 8; - spi_databuf[spi_pre_cmd_pad + 13] = (sd->cmd53_wr_data & 0x00FF0000) >> 16; - spi_databuf[spi_pre_cmd_pad + 14] = (sd->cmd53_wr_data & 0xFF000000) >> 24; - if (sd_crc) { - dat_crc = sdspi_crc16(&spi_databuf[spi_pre_cmd_pad+11], 4); - } else { - dat_crc = 0x44AA; - } - spi_databuf[spi_pre_cmd_pad + 15] = (dat_crc >> 8) & 0xFF; - spi_databuf[spi_pre_cmd_pad + 16] = (dat_crc & 0xFF); - } else { - printf("CMD53 Write: size %d unsupported\n", sd->data_xfer_count); - } - } - - spi_sendrecv(sd, spi_databuf, spi_rspbuf, spi_datalen); - - for (i = spi_pre_cmd_pad + SDSPI_COMMAND_LEN; i < spi_max_response_pad; i++) {//for cmd0, we check spi_rspbuf[18] ~ spi_rspbuf[28] - if ((spi_rspbuf[i] & SDSPI_START_BIT_MASK) == 0) { - break; - } - } - - if (i == spi_max_response_pad) {//28 for cmd0 - sd_err(("%s: Did not get a response for CMD%d\n", __FUNCTION__, cmd)); - return ERROR; - } - - /* Extract the response. */ - sd->card_response = spi_rspbuf[i]; - - /* for CMD53 Read, find the start of the response data... */ - if ((cmd == SDIOH_CMD_53) && (GFIELD(cmd_arg, CMD52_RW_FLAG) == 0)) { - for (; i < spi_max_response_pad; i++) { - if (spi_rspbuf[i] == SDSPI_START_BLOCK) { - break; - } - } - - if (i == spi_max_response_pad) { - printf("Did not get a start of data phase for CMD%d\n", cmd); - max_errors++; - sdspi_abort(sd, GFIELD(cmd_arg, CMD53_FUNCTION)); - } - sd->card_rsp_data = spi_rspbuf[i+1]; - sd->card_rsp_data |= spi_rspbuf[i+2] << 8; - sd->card_rsp_data |= spi_rspbuf[i+3] << 16; - sd->card_rsp_data |= spi_rspbuf[i+4] << 24; - - if (datalen != 0) { - i++; - for (j = 0; j < sd->data_xfer_count; j++) { - ((uint8 *)data)[j] = spi_rspbuf[i+j]; - } - if (sd_crc) { - uint16 recv_crc; - - recv_crc = spi_rspbuf[i+j] << 8 | spi_rspbuf[i+j+1]; - dat_crc = sdspi_crc16((uint8 *)data, datalen); - if (dat_crc != recv_crc) { - sd_err(("%s: Incorrect data CRC: expected 0x%04x, " - "received 0x%04x\n", - __FUNCTION__, dat_crc, recv_crc)); - } - } - } - return SUCCESS; - } - - sd->card_rsp_data = spi_rspbuf[i+4]; - sd->card_rsp_data |= spi_rspbuf[i+3] << 8; - sd->card_rsp_data |= spi_rspbuf[i+2] << 16; - sd->card_rsp_data |= spi_rspbuf[i+1] << 24; - - /* Display trace for byte read */ - if ((cmd == SDIOH_CMD_52) && (GFIELD(cmd_arg, CMD52_RW_FLAG) == 0)) { - sd_trace(("%s: CMD52: Rd F:%d @0x%04x=%02x\n", - __FUNCTION__, - GFIELD(cmd_arg, CMD53_FUNCTION), - GFIELD(cmd_arg, CMD53_REG_ADDR), - sd->card_rsp_data >> 24)); - } - - return SUCCESS; -} - -/* - * On entry: if single-block or non-block, buffer size <= block size. - * If multi-block, buffer size is unlimited. - * Question is how to handle the left-overs in either single- or multi-block. - * I think the caller should break the buffer up so this routine will always - * use block size == buffer size to handle the end piece of the buffer - */ - -static int -sdspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, uint32 addr, int nbytes, uint32 *data) -{ - int status; - uint32 cmd_arg; - uint32 rsp5; - int num_blocks, blocksize; - bool local_blockmode, local_dma; - bool read = rw == SDIOH_READ ? 1 : 0; - - ASSERT(nbytes); - - cmd_arg = 0; - sd_data(("%s: %s 53 func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", - __FUNCTION__, read ? "Rd" : "Wr", func, fifo ? "FIXED" : "INCR", - addr, nbytes, sd->r_cnt, sd->t_cnt)); - - if (read) sd->r_cnt++; else sd->t_cnt++; - - local_blockmode = sd->sd_blockmode; - local_dma = sd->sd_use_dma; - - /* Don't bother with block mode on small xfers */ - if (nbytes < sd->client_block_size[func]) { - sd_info(("setting local blockmode to false: nbytes (%d) != block_size (%d)\n", - nbytes, sd->client_block_size[func])); - local_blockmode = FALSE; - local_dma = FALSE; - } - - if (local_blockmode) { - blocksize = MIN(sd->client_block_size[func], nbytes); - num_blocks = nbytes/blocksize; - cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, num_blocks); - cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 1); - } else { - num_blocks = 1; - blocksize = nbytes; - cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, nbytes); - cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0); - } - - if (fifo) - cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 0); - else - cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1); - - cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, addr); - if (read) - cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_READ); - else - cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_WRITE); - - sd->data_xfer_count = nbytes; - if ((func == 2) && (fifo == 1)) { - sd_data(("%s: %s 53 func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", - __FUNCTION__, read ? "Rd" : "Wr", func, fifo ? "FIXED" : "INCR", - addr, nbytes, sd->r_cnt, sd->t_cnt)); - } - - /* sdspi_cmd_issue() returns with the command complete bit - * in the ISR already cleared - */ - if ((status = sdspi_cmd_issue(sd, local_dma, - SDIOH_CMD_53, cmd_arg, - data, nbytes)) != SUCCESS) { - sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__, (read ? "read" : "write"))); - return status; - } - - sdspi_cmd_getrsp(sd, &rsp5, 1); - - if (rsp5 != 0x00) { - sd_err(("%s: rsp5 flags = 0x%x, expecting 0x00\n", - __FUNCTION__, rsp5)); - return ERROR; - } - - return SUCCESS; -} - -static int -set_client_block_size(sdioh_info_t *sd, int func, int block_size) -{ - int base; - int err = 0; - - sd_err(("%s: Setting block size %d, func %d\n", __FUNCTION__, block_size, func)); - sd->client_block_size[func] = block_size; - - /* Set the block size in the SDIO Card register */ - base = func * SDIOD_FBR_SIZE; - err = sdspi_card_regwrite(sd, 0, base + SDIOD_CCCR_BLKSIZE_0, 1, block_size & 0xff); - if (!err) { - err = sdspi_card_regwrite(sd, 0, base + SDIOD_CCCR_BLKSIZE_1, 1, - (block_size >> 8) & 0xff); - } - - /* - * Do not set the block size in the SDIO Host register; that - * is func dependent and will get done on an individual - * transaction basis. - */ - - return (err ? BCME_SDIO_ERROR : 0); -} - -/* Reset and re-initialize the device */ -int -sdioh_sdio_reset(sdioh_info_t *si) -{ - si->card_init_done = FALSE; - return sdspi_client_init(si); -} - -SDIOH_API_RC -sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) -{ - return SDIOH_API_RC_FAIL; -} - -SDIOH_API_RC -sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) -{ - return SDIOH_API_RC_FAIL; -} - -bool -sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) -{ - return FALSE; -} - -SDIOH_API_RC -sdioh_gpio_init(sdioh_info_t *sd) -{ - return SDIOH_API_RC_FAIL; -} - -#define CRC7_POLYNOM 0x09 -#define CRC7_CRCHIGHBIT 0x40 - -static uint8 sdspi_crc7(unsigned char* p, uint32 len) -{ - uint8 c, j, bit, crc = 0; - uint32 i; - - for (i = 0; i < len; i++) { - c = *p++; - for (j = 0x80; j; j >>= 1) { - bit = crc & CRC7_CRCHIGHBIT; - crc <<= 1; - if (c & j) bit ^= CRC7_CRCHIGHBIT; - if (bit) crc ^= CRC7_POLYNOM; - } - } - - /* Convert the CRC7 to an 8-bit SD CRC */ - crc = (crc << 1) | 1; - - return (crc); -} - -#define CRC16_POLYNOM 0x1021 -#define CRC16_CRCHIGHBIT 0x8000 - -static uint16 sdspi_crc16(unsigned char* p, uint32 len) -{ - uint32 i; - uint16 j, c, bit; - uint16 crc = 0; - - for (i = 0; i < len; i++) { - c = *p++; - for (j = 0x80; j; j >>= 1) { - bit = crc & CRC16_CRCHIGHBIT; - crc <<= 1; - if (c & j) bit ^= CRC16_CRCHIGHBIT; - if (bit) crc ^= CRC16_POLYNOM; - } - } - - return (crc); -}
diff --git a/bcmdhd.1.579.77.41.x/bcmsdspi_linux.c b/bcmdhd.1.579.77.41.x/bcmsdspi_linux.c deleted file mode 100644 index b7091e5..0000000 --- a/bcmdhd.1.579.77.41.x/bcmsdspi_linux.c +++ /dev/null
@@ -1,252 +0,0 @@ -/* - * Broadcom SPI Host Controller Driver - Linux Per-port - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: 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 */ - -#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> - -extern uint sd_crc; -module_param(sd_crc, uint, 0); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define KERNEL26 -#endif - -struct sdos_info { - sdioh_info_t *sd; - spinlock_t lock; - wait_queue_head_t intr_wait_queue; -}; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define BLOCKABLE() (!in_atomic()) -#else -#define BLOCKABLE() (!in_interrupt()) -#endif - -/* Interrupt handler */ -static irqreturn_t -sdspi_isr(int irq, void *dev_id -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) -, struct pt_regs *ptregs -#endif -) -{ - sdioh_info_t *sd; - struct sdos_info *sdos; - bool ours; - - sd = (sdioh_info_t *)dev_id; - sd->local_intrcount++; - - if (!sd->card_init_done) { - sd_err(("%s: Hey Bogus intr...not even initted: irq %d\n", __FUNCTION__, irq)); - return IRQ_RETVAL(FALSE); - } else { - ours = spi_check_client_intr(sd, NULL); - - /* For local interrupts, wake the waiting process */ - if (ours && sd->got_hcint) { - sdos = (struct sdos_info *)sd->sdos_info; - wake_up_interruptible(&sdos->intr_wait_queue); - } - - return IRQ_RETVAL(ours); - } -} - - -/* Register with Linux for interrupts */ -int -spi_register_irq(sdioh_info_t *sd, uint irq) -{ - 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; - } - return SUCCESS; -} - -/* Free Linux irq */ -void -spi_free_irq(uint irq, sdioh_info_t *sd) -{ - free_irq(irq, sd); -} - -/* Map Host controller registers */ -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); -} - -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); - init_waitqueue_head(&sdos->intr_wait_queue); - 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; - } - - if (enable && !(sd->intr_handler && sd->intr_handler_arg)) { - sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__)); - return SDIOH_API_RC_FAIL; - } - - /* Ensure atomicity for enable/disable calls */ - spin_lock_irqsave(&sdos->lock, flags); - - sd->client_intr_enabled = enable; - if (enable && !sd->lockcount) - spi_devintr_on(sd); - else - spi_devintr_off(sd); - - 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); - } - spi_devintr_off(sd); - 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) { - spi_devintr_on(sd); - } - spin_unlock_irqrestore(&sdos->lock, flags); -} - -void spi_waitbits(sdioh_info_t *sd, bool yield) -{ -#ifndef BCMSDYIELD - ASSERT(!yield); -#endif - sd_trace(("%s: yield %d canblock %d\n", - __FUNCTION__, yield, BLOCKABLE())); - - /* Clear the "interrupt happened" flag and last intrstatus */ - sd->got_hcint = FALSE; - -#ifdef BCMSDYIELD - if (yield && BLOCKABLE()) { - struct sdos_info *sdos; - sdos = (struct sdos_info *)sd->sdos_info; - /* Wait for the indication, the interrupt will be masked when the ISR fires. */ - wait_event_interruptible(sdos->intr_wait_queue, (sd->got_hcint)); - } else -#endif /* BCMSDYIELD */ - { - spi_spinbits(sd); - } - -}
diff --git a/bcmdhd.1.579.77.41.x/bcmspibrcm.c b/bcmdhd.1.579.77.41.x/bcmspibrcm.c deleted file mode 100644 index 1bbff16..0000000 --- a/bcmdhd.1.579.77.41.x/bcmspibrcm.c +++ /dev/null
@@ -1,1764 +0,0 @@ -/* - * Broadcom BCMSDH to gSPI Protocol Conversion Layer - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: bcmspibrcm.c 611787 2016-01-12 06:07:27Z $ - */ - -#define HSMODE - -#include <typedefs.h> - -#include <bcmdevs.h> -#include <bcmendian.h> -#include <bcmutils.h> -#include <osl.h> -#include <hndsoc.h> -#include <siutils.h> -#include <sbchipc.h> -#include <sbsdio.h> /* SDIO device core hardware definitions. */ -#include <spid.h> - -#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */ -#include <sdiovar.h> /* ioctl/iovars */ -#include <sdio.h> /* SDIO Device and Protocol Specs */ - -#include <pcicfg.h> - - -#include <bcmspibrcm.h> -#include <bcmspi.h> - -/* these are for the older cores... for newer cores we have control for each of them */ -#define F0_RESPONSE_DELAY 16 -#define F1_RESPONSE_DELAY 16 -#define F2_RESPONSE_DELAY F0_RESPONSE_DELAY - - -#define GSPI_F0_RESP_DELAY 0 -#define GSPI_F1_RESP_DELAY F1_RESPONSE_DELAY -#define GSPI_F2_RESP_DELAY 0 -#define GSPI_F3_RESP_DELAY 0 - -#define CMDLEN 4 - -/* Globals */ -#if defined(DHD_DEBUG) -uint sd_msglevel = SDH_ERROR_VAL; -#else -uint sd_msglevel = 0; -#endif - -uint sd_hiok = FALSE; /* Use hi-speed mode if available? */ -uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */ -uint sd_f2_blocksize = 64; /* Default blocksize */ - - -uint sd_divisor = 2; -uint sd_power = 1; /* Default to SD Slot powered ON */ -uint sd_clock = 1; /* Default to SD Clock turned ON */ -uint sd_crc = 0; /* Default to SPI CRC Check turned OFF */ -uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */ - -uint8 spi_outbuf[SPI_MAX_PKT_LEN]; -uint8 spi_inbuf[SPI_MAX_PKT_LEN]; - -/* 128bytes buffer is enough to clear data-not-available and program response-delay F0 bits - * assuming we will not exceed F0 response delay > 100 bytes at 48MHz. - */ -#define BUF2_PKT_LEN 128 -uint8 spi_outbuf2[BUF2_PKT_LEN]; -uint8 spi_inbuf2[BUF2_PKT_LEN]; - -#define SPISWAP_WD4(x) bcmswap32(x); -#define SPISWAP_WD2(x) (bcmswap16(x & 0xffff)) | \ - (bcmswap16((x & 0xffff0000) >> 16) << 16); - -/* Prototypes */ -static bool bcmspi_test_card(sdioh_info_t *sd); -static bool bcmspi_host_device_init_adapt(sdioh_info_t *sd); -static int bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode); -static int bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, - uint32 *data, uint32 datalen); -static int bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, - int regsize, uint32 *data); -static int bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, - int regsize, uint32 data); -static int bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, - uint8 *data); -static int bcmspi_driver_init(sdioh_info_t *sd); -static int bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, - uint32 addr, int nbytes, uint32 *data); -static int bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, - uint32 *data); -static void bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer); -static int bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg); - -/* - * Public entry points & extern's - */ -extern sdioh_info_t * -sdioh_attach(osl_t *osh, void *bar0, uint irq) -{ - sdioh_info_t *sd; - - sd_trace(("%s\n", __FUNCTION__)); - if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) { - sd_err(("%s: out of memory, malloced %d bytes\n", __FUNCTION__, MALLOCED(osh))); - return NULL; - } - bzero((char *)sd, sizeof(sdioh_info_t)); - sd->osh = osh; - if (spi_osinit(sd) != 0) { - sd_err(("%s: spi_osinit() failed\n", __FUNCTION__)); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return NULL; - } - - sd->bar0 = bar0; - sd->irq = irq; - sd->intr_handler = NULL; - sd->intr_handler_arg = NULL; - sd->intr_handler_valid = FALSE; - - /* Set defaults */ - sd->use_client_ints = TRUE; - sd->sd_use_dma = FALSE; /* DMA Not supported */ - - /* Spi device default is 16bit mode, change to 4 when device is changed to 32bit - * mode - */ - sd->wordlen = 2; - - - if (!spi_hw_attach(sd)) { - sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__)); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return (NULL); - } - - if (bcmspi_driver_init(sd) != SUCCESS) { - sd_err(("%s: bcmspi_driver_init() failed()\n", __FUNCTION__)); - spi_hw_detach(sd); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return (NULL); - } - - if (spi_register_irq(sd, irq) != SUCCESS) { - sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq)); - spi_hw_detach(sd); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - return (NULL); - } - - sd_trace(("%s: Done\n", __FUNCTION__)); - - return sd; -} - -extern SDIOH_API_RC -sdioh_detach(osl_t *osh, sdioh_info_t *sd) -{ - sd_trace(("%s\n", __FUNCTION__)); - if (sd) { - sd_err(("%s: detaching from hardware\n", __FUNCTION__)); - spi_free_irq(sd->irq, sd); - spi_hw_detach(sd); - spi_osfree(sd); - MFREE(sd->osh, sd, sizeof(sdioh_info_t)); - } - return SDIOH_API_RC_SUCCESS; -} - -/* Configure callback to client when we recieve client interrupt */ -extern SDIOH_API_RC -sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); -#if !defined(OOB_INTR_ONLY) - sd->intr_handler = fn; - sd->intr_handler_arg = argh; - sd->intr_handler_valid = TRUE; -#endif /* !defined(OOB_INTR_ONLY) */ - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_interrupt_deregister(sdioh_info_t *sd) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); -#if !defined(OOB_INTR_ONLY) - sd->intr_handler_valid = FALSE; - sd->intr_handler = NULL; - sd->intr_handler_arg = NULL; -#endif /* !defined(OOB_INTR_ONLY) */ - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff) -{ - sd_trace(("%s: Entering\n", __FUNCTION__)); - *onoff = sd->client_intr_enabled; - return SDIOH_API_RC_SUCCESS; -} - -#if defined(DHD_DEBUG) -extern bool -sdioh_interrupt_pending(sdioh_info_t *sd) -{ - return 0; -} -#endif - -/* Provide dstatus bits of spi-transaction for dhd layers. */ -extern uint32 -sdioh_get_dstatus(sdioh_info_t *sd) -{ - return sd->card_dstatus; -} - -extern void -sdioh_chipinfo(sdioh_info_t *sd, uint32 chip, uint32 chiprev) -{ - sd->chip = chip; - sd->chiprev = chiprev; -} - -extern void -sdioh_dwordmode(sdioh_info_t *sd, bool set) -{ - uint8 reg = 0; - int status; - - if ((status = sdioh_request_byte(sd, SDIOH_READ, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != - SUCCESS) { - sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); - return; - } - - if (set) { - reg |= DWORD_PKT_LEN_EN; - sd->dwordmode = TRUE; - sd->client_block_size[SPI_FUNC_2] = 4096; /* h2spi's limit is 4KB, we support 8KB */ - } else { - reg &= ~DWORD_PKT_LEN_EN; - sd->dwordmode = FALSE; - sd->client_block_size[SPI_FUNC_2] = 2048; - } - - if ((status = sdioh_request_byte(sd, SDIOH_WRITE, SPI_FUNC_0, SPID_STATUS_ENABLE, ®)) != - SUCCESS) { - sd_err(("%s: Failed to set dwordmode in gSPI\n", __FUNCTION__)); - return; - } -} - - -uint -sdioh_query_iofnum(sdioh_info_t *sd) -{ - return sd->num_funcs; -} - -/* IOVar table */ -enum { - IOV_MSGLEVEL = 1, - IOV_BLOCKMODE, - IOV_BLOCKSIZE, - IOV_DMA, - IOV_USEINTS, - IOV_NUMINTS, - IOV_NUMLOCALINTS, - IOV_HOSTREG, - IOV_DEVREG, - IOV_DIVISOR, - IOV_SDMODE, - IOV_HISPEED, - IOV_HCIREGS, - IOV_POWER, - IOV_CLOCK, - IOV_SPIERRSTATS, - IOV_RESP_DELAY_ALL -}; - -const bcm_iovar_t sdioh_iovars[] = { - {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, - {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */ - {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 }, - {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 }, - {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 }, - {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 }, - {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 }, - {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 }, - {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 }, - {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}, - {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0}, - {"spi_errstats", IOV_SPIERRSTATS, 0, IOVT_BUFFER, sizeof(struct spierrstats_t) }, - {"spi_respdelay", IOV_RESP_DELAY_ALL, 0, IOVT_BOOL, 0 }, - {NULL, 0, 0, 0, 0 } -}; - -int -sdioh_iovar_op(sdioh_info_t *si, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - const bcm_iovar_t *vi = NULL; - int bcmerror = 0; - int val_size; - int32 int_val = 0; - bool bool_val; - uint32 actionid; -/* - sdioh_regs_t *regs; -*/ - - ASSERT(name); - ASSERT(len >= 0); - - /* Get must have return space; Set does not take qualifiers */ - ASSERT(set || (arg && len)); - ASSERT(!set || (!params && !plen)); - - sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); - - if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { - bcmerror = BCME_UNSUPPORTED; - goto exit; - } - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) - goto exit; - - /* Set up params so get and set can share the convenience variables */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - val_size = sizeof(int); - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - bool_val = (int_val != 0) ? TRUE : FALSE; - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - switch (actionid) { - case IOV_GVAL(IOV_MSGLEVEL): - int_val = (int32)sd_msglevel; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_MSGLEVEL): - sd_msglevel = int_val; - break; - - case IOV_GVAL(IOV_BLOCKSIZE): - if ((uint32)int_val > si->num_funcs) { - bcmerror = BCME_BADARG; - break; - } - int_val = (int32)si->client_block_size[int_val]; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_DMA): - int_val = (int32)si->sd_use_dma; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DMA): - si->sd_use_dma = (bool)int_val; - break; - - case IOV_GVAL(IOV_USEINTS): - int_val = (int32)si->use_client_ints; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_USEINTS): - break; - - case IOV_GVAL(IOV_DIVISOR): - int_val = (uint32)sd_divisor; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DIVISOR): - sd_divisor = int_val; - if (!spi_start_clock(si, (uint16)sd_divisor)) { - sd_err(("%s: set clock failed\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - } - break; - - case IOV_GVAL(IOV_POWER): - int_val = (uint32)sd_power; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_POWER): - sd_power = int_val; - break; - - case IOV_GVAL(IOV_CLOCK): - int_val = (uint32)sd_clock; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_CLOCK): - sd_clock = int_val; - break; - - case IOV_GVAL(IOV_SDMODE): - int_val = (uint32)sd_sdmode; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SDMODE): - sd_sdmode = int_val; - break; - - case IOV_GVAL(IOV_HISPEED): - int_val = (uint32)sd_hiok; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_HISPEED): - sd_hiok = int_val; - - if (!bcmspi_set_highspeed_mode(si, (bool)sd_hiok)) { - sd_err(("%s: Failed changing highspeed mode to %d.\n", - __FUNCTION__, sd_hiok)); - bcmerror = BCME_ERROR; - return ERROR; - } - break; - - case IOV_GVAL(IOV_NUMINTS): - int_val = (int32)si->intrcount; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_NUMLOCALINTS): - int_val = (int32)si->local_intrcount; - bcopy(&int_val, arg, val_size); - break; - case IOV_GVAL(IOV_DEVREG): - { - sdreg_t *sd_ptr = (sdreg_t *)params; - uint8 data; - - if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { - bcmerror = BCME_SDIO_ERROR; - break; - } - - int_val = (int)data; - bcopy(&int_val, arg, sizeof(int_val)); - break; - } - - case IOV_SVAL(IOV_DEVREG): - { - sdreg_t *sd_ptr = (sdreg_t *)params; - uint8 data = (uint8)sd_ptr->value; - - if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { - bcmerror = BCME_SDIO_ERROR; - break; - } - break; - } - - - case IOV_GVAL(IOV_SPIERRSTATS): - { - bcopy(&si->spierrstats, arg, sizeof(struct spierrstats_t)); - break; - } - - case IOV_SVAL(IOV_SPIERRSTATS): - { - bzero(&si->spierrstats, sizeof(struct spierrstats_t)); - break; - } - - case IOV_GVAL(IOV_RESP_DELAY_ALL): - int_val = (int32)si->resp_delay_all; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_RESP_DELAY_ALL): - si->resp_delay_all = (bool)int_val; - int_val = STATUS_ENABLE|INTR_WITH_STATUS; - if (si->resp_delay_all) - int_val |= RESP_DELAY_ALL; - else { - if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_RESPONSE_DELAY, 1, - F1_RESPONSE_DELAY) != SUCCESS) { - sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; - break; - } - } - - if (bcmspi_card_regwrite(si, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, int_val) - != SUCCESS) { - sd_err(("%s: Unable to set response delay.\n", __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; - break; - } - break; - - default: - bcmerror = BCME_UNSUPPORTED; - break; - } -exit: - - return bcmerror; -} - -extern SDIOH_API_RC -sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -{ - SDIOH_API_RC status; - /* No lock needed since sdioh_request_byte does locking */ - status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); - return status; -} - -extern SDIOH_API_RC -sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) -{ - /* No lock needed since sdioh_request_byte does locking */ - SDIOH_API_RC status; - - if ((fnc_num == SPI_FUNC_1) && (addr == SBSDIO_FUNC1_FRAMECTRL)) { - uint8 dummy_data; - status = sdioh_cfg_read(sd, fnc_num, addr, &dummy_data); - if (status) { - sd_err(("sdioh_cfg_read() failed.\n")); - return status; - } - } - - status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); - return status; -} - -extern SDIOH_API_RC -sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) -{ - uint32 count; - int offset; - uint32 cis_byte; - uint16 *cis = (uint16 *)cisd; - uint bar0 = SI_ENUM_BASE; - int status; - uint8 data; - - sd_trace(("%s: Func %d\n", __FUNCTION__, func)); - - spi_lock(sd); - - /* Set sb window address to 0x18000000 */ - data = (bar0 >> 8) & SBSDIO_SBADDRLOW_MASK; - status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, &data); - if (status == SUCCESS) { - data = (bar0 >> 16) & SBSDIO_SBADDRMID_MASK; - status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, &data); - } else { - sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); - spi_unlock(sd); - return (BCME_ERROR); - } - if (status == SUCCESS) { - data = (bar0 >> 24) & SBSDIO_SBADDRHIGH_MASK; - status = bcmspi_card_bytewrite(sd, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, &data); - } else { - sd_err(("%s: Unable to set sb-addr-windows\n", __FUNCTION__)); - spi_unlock(sd); - return (BCME_ERROR); - } - - offset = CC_SROM_OTP; /* OTP offset in chipcommon. */ - for (count = 0; count < length/2; count++) { - if (bcmspi_card_regread (sd, SDIO_FUNC_1, offset, 2, &cis_byte) < 0) { - sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); - spi_unlock(sd); - return (BCME_ERROR); - } - - *cis = (uint16)cis_byte; - cis++; - offset += 2; - } - - spi_unlock(sd); - - return (BCME_OK); -} - -extern SDIOH_API_RC -sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) -{ - int status; - uint32 cmd_arg; - uint32 dstatus; - uint32 data = (uint32)(*byte); - - spi_lock(sd); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, rw == SDIOH_READ ? 0 : 1); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); - - if (rw == SDIOH_READ) { - sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x\n", - __FUNCTION__, cmd_arg, func, regaddr)); - } else { - sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x data=0x%x\n", - __FUNCTION__, cmd_arg, func, regaddr, data)); - } - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, 1)) != SUCCESS) { - spi_unlock(sd); - return status; - } - - if (rw == SDIOH_READ) { - *byte = (uint8)data; - sd_trace(("%s: RD result=0x%x\n", __FUNCTION__, *byte)); - } - - bcmspi_cmd_getdstatus(sd, &dstatus); - if (dstatus) - sd_trace(("dstatus=0x%x\n", dstatus)); - - spi_unlock(sd); - return SDIOH_API_RC_SUCCESS; -} - -extern SDIOH_API_RC -sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, - uint32 *word, uint nbytes) -{ - int status; - - spi_lock(sd); - - if (rw == SDIOH_READ) - status = bcmspi_card_regread(sd, func, addr, nbytes, word); - else - status = bcmspi_card_regwrite(sd, func, addr, nbytes, *word); - - spi_unlock(sd); - return (status == SUCCESS ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); -} - -extern SDIOH_API_RC -sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func, - uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) -{ - int len; - int buflen = (int)buflen_u; - bool fifo = (fix_inc == SDIOH_DATA_FIX); - - spi_lock(sd); - - ASSERT(reg_width == 4); - ASSERT(buflen_u < (1 << 30)); - ASSERT(sd->client_block_size[func]); - - sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n", - __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W', - buflen_u, sd->r_cnt, sd->t_cnt, pkt)); - - /* Break buffer down into blocksize chunks. */ - while (buflen > 0) { - len = MIN(sd->client_block_size[func], buflen); - if (bcmspi_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) { - sd_err(("%s: bcmspi_card_buf %s failed\n", - __FUNCTION__, rw == SDIOH_READ ? "Read" : "Write")); - spi_unlock(sd); - return SDIOH_API_RC_FAIL; - } - buffer += len; - buflen -= len; - if (!fifo) - addr += len; - } - spi_unlock(sd); - return SDIOH_API_RC_SUCCESS; -} - -/* This function allows write to gspi bus when another rd/wr function is deep down the call stack. - * Its main aim is to have simpler spi writes rather than recursive writes. - * e.g. When there is a need to program response delay on the fly after detecting the SPI-func - * this call will allow to program the response delay. - */ -static int -bcmspi_card_byterewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 byte) -{ - uint32 cmd_arg; - uint32 datalen = 1; - uint32 hostlen; - - cmd_arg = 0; - - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, datalen); - - sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); - - - /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen - * according to the wordlen mode(16/32bit) the device is in. - */ - ASSERT(sd->wordlen == 4 || sd->wordlen == 2); - datalen = ROUNDUP(datalen, sd->wordlen); - - /* Start by copying command in the spi-outbuffer */ - if (sd->wordlen == 4) { /* 32bit spid */ - *(uint32 *)spi_outbuf2 = SPISWAP_WD4(cmd_arg); - if (datalen & 0x3) - datalen += (4 - (datalen & 0x3)); - } else if (sd->wordlen == 2) { /* 16bit spid */ - *(uint32 *)spi_outbuf2 = SPISWAP_WD2(cmd_arg); - if (datalen & 0x1) - datalen++; - } else { - sd_err(("%s: Host is %d bit spid, could not create SPI command.\n", - __FUNCTION__, 8 * sd->wordlen)); - return ERROR; - } - - /* for Write, put the data into the output buffer */ - if (datalen != 0) { - if (sd->wordlen == 4) { /* 32bit spid */ - *(uint32 *)&spi_outbuf2[CMDLEN] = SPISWAP_WD4(byte); - } else if (sd->wordlen == 2) { /* 16bit spid */ - *(uint32 *)&spi_outbuf2[CMDLEN] = SPISWAP_WD2(byte); - } - } - - /* +4 for cmd, +4 for dstatus */ - hostlen = datalen + 8; - hostlen += (4 - (hostlen & 0x3)); - spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, hostlen); - - /* Last 4bytes are dstatus. Device is configured to return status bits. */ - if (sd->wordlen == 4) { /* 32bit spid */ - sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); - } else { - sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", - __FUNCTION__, 8 * sd->wordlen)); - return ERROR; - } - - if (sd->card_dstatus) - sd_trace(("dstatus after byte rewrite = 0x%x\n", sd->card_dstatus)); - - return (BCME_OK); -} - -/* Program the response delay corresponding to the spi function */ -static int -bcmspi_prog_resp_delay(sdioh_info_t *sd, int func, uint8 resp_delay) -{ - if (sd->resp_delay_all == FALSE) - return (BCME_OK); - - if (sd->prev_fun == func) - return (BCME_OK); - - if (F0_RESPONSE_DELAY == F1_RESPONSE_DELAY) - return (BCME_OK); - - bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_RESPONSE_DELAY, resp_delay); - - /* Remember function for which to avoid reprogramming resp-delay in next iteration */ - sd->prev_fun = func; - - return (BCME_OK); - -} - -#define GSPI_RESYNC_PATTERN 0x0 - -/* A resync pattern is a 32bit MOSI line with all zeros. Its a special command in gSPI. - * It resets the spi-bkplane logic so that all F1 related ping-pong buffer logic is - * synchronised and all queued resuests are cancelled. - */ -static int -bcmspi_resync_f1(sdioh_info_t *sd) -{ - uint32 cmd_arg = GSPI_RESYNC_PATTERN, data = 0, datalen = 0; - - - /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen - * according to the wordlen mode(16/32bit) the device is in. - */ - ASSERT(sd->wordlen == 4 || sd->wordlen == 2); - datalen = ROUNDUP(datalen, sd->wordlen); - - /* Start by copying command in the spi-outbuffer */ - *(uint32 *)spi_outbuf2 = cmd_arg; - - /* for Write, put the data into the output buffer */ - *(uint32 *)&spi_outbuf2[CMDLEN] = data; - - /* +4 for cmd, +4 for dstatus */ - spi_sendrecv(sd, spi_outbuf2, spi_inbuf2, datalen + 8); - - /* Last 4bytes are dstatus. Device is configured to return status bits. */ - if (sd->wordlen == 4) { /* 32bit spid */ - sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf2[datalen + CMDLEN ]); - } else { - sd_err(("%s: Host is %d bit machine, could not read SPI dstatus.\n", - __FUNCTION__, 8 * sd->wordlen)); - return ERROR; - } - - if (sd->card_dstatus) - sd_trace(("dstatus after resync pattern write = 0x%x\n", sd->card_dstatus)); - - return (BCME_OK); -} - -uint32 dstatus_count = 0; - -static int -bcmspi_update_stats(sdioh_info_t *sd, uint32 cmd_arg) -{ - uint32 dstatus = sd->card_dstatus; - struct spierrstats_t *spierrstats = &sd->spierrstats; - int err = SUCCESS; - - sd_trace(("cmd = 0x%x, dstatus = 0x%x\n", cmd_arg, dstatus)); - - /* Store dstatus of last few gSPI transactions */ - spierrstats->dstatus[dstatus_count % NUM_PREV_TRANSACTIONS] = dstatus; - spierrstats->spicmd[dstatus_count % NUM_PREV_TRANSACTIONS] = cmd_arg; - dstatus_count++; - - if (sd->card_init_done == FALSE) - return err; - - if (dstatus & STATUS_DATA_NOT_AVAILABLE) { - spierrstats->dna++; - sd_trace(("Read data not available on F1 addr = 0x%x\n", - GFIELD(cmd_arg, SPI_REG_ADDR))); - /* Clear dna bit */ - bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, DATA_UNAVAILABLE); - } - - if (dstatus & STATUS_UNDERFLOW) { - spierrstats->rdunderflow++; - sd_err(("FIFO underflow happened due to current F2 read command.\n")); - } - - if (dstatus & STATUS_OVERFLOW) { - spierrstats->wroverflow++; - sd_err(("FIFO overflow happened due to current (F1/F2) write command.\n")); - bcmspi_card_byterewrite(sd, SPI_FUNC_0, SPID_INTR_REG, F1_OVERFLOW); - bcmspi_resync_f1(sd); - sd_err(("Recovering from F1 FIFO overflow.\n")); - } - - if (dstatus & STATUS_F2_INTR) { - spierrstats->f2interrupt++; - sd_trace(("Interrupt from F2. SW should clear corresponding IntStatus bits\n")); - } - - if (dstatus & STATUS_F3_INTR) { - spierrstats->f3interrupt++; - sd_err(("Interrupt from F3. SW should clear corresponding IntStatus bits\n")); - } - - if (dstatus & STATUS_HOST_CMD_DATA_ERR) { - spierrstats->hostcmddataerr++; - sd_err(("Error in CMD or Host data, detected by CRC/Checksum (optional)\n")); - } - - if (dstatus & STATUS_F2_PKT_AVAILABLE) { - spierrstats->f2pktavailable++; - sd_trace(("Packet is available/ready in F2 TX FIFO\n")); - sd_trace(("Packet length = %d\n", sd->dwordmode ? - ((dstatus & STATUS_F2_PKT_LEN_MASK) >> (STATUS_F2_PKT_LEN_SHIFT - 2)) : - ((dstatus & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT))); - } - - if (dstatus & STATUS_F3_PKT_AVAILABLE) { - spierrstats->f3pktavailable++; - sd_err(("Packet is available/ready in F3 TX FIFO\n")); - sd_err(("Packet length = %d\n", - (dstatus & STATUS_F3_PKT_LEN_MASK) >> STATUS_F3_PKT_LEN_SHIFT)); - } - - return err; -} - -extern int -sdioh_abort(sdioh_info_t *sd, uint func) -{ - return 0; -} - -int -sdioh_start(sdioh_info_t *sd, int stage) -{ - return SUCCESS; -} - -int -sdioh_stop(sdioh_info_t *sd) -{ - return SUCCESS; -} - -int -sdioh_waitlockfree(sdioh_info_t *sd) -{ - return SUCCESS; -} - - -/* - * Private/Static work routines - */ -static int -bcmspi_host_init(sdioh_info_t *sd) -{ - - /* Default power on mode */ - sd->sd_mode = SDIOH_MODE_SPI; - sd->polled_mode = TRUE; - sd->host_init_done = TRUE; - sd->card_init_done = FALSE; - sd->adapter_slot = 1; - - return (SUCCESS); -} - -static int -get_client_blocksize(sdioh_info_t *sd) -{ - uint32 regdata[2]; - int status; - - /* Find F1/F2/F3 max packet size */ - if ((status = bcmspi_card_regread(sd, 0, SPID_F1_INFO_REG, - 8, regdata)) != SUCCESS) { - return status; - } - - sd_trace(("pkt_size regdata[0] = 0x%x, regdata[1] = 0x%x\n", - regdata[0], regdata[1])); - - sd->client_block_size[1] = (regdata[0] & F1_MAX_PKT_SIZE) >> 2; - sd_trace(("Func1 blocksize = %d\n", sd->client_block_size[1])); - ASSERT(sd->client_block_size[1] == BLOCK_SIZE_F1); - - sd->client_block_size[2] = ((regdata[0] >> 16) & F2_MAX_PKT_SIZE) >> 2; - sd_trace(("Func2 blocksize = %d\n", sd->client_block_size[2])); - ASSERT(sd->client_block_size[2] == BLOCK_SIZE_F2); - - sd->client_block_size[3] = (regdata[1] & F3_MAX_PKT_SIZE) >> 2; - sd_trace(("Func3 blocksize = %d\n", sd->client_block_size[3])); - ASSERT(sd->client_block_size[3] == BLOCK_SIZE_F3); - - return 0; -} - -static int -bcmspi_client_init(sdioh_info_t *sd) -{ - uint32 status_en_reg = 0; - sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot)); - -#ifdef HSMODE - if (!spi_start_clock(sd, (uint16)sd_divisor)) { - sd_err(("spi_start_clock failed\n")); - return ERROR; - } -#else - /* Start at ~400KHz clock rate for initialization */ - if (!spi_start_clock(sd, 128)) { - sd_err(("spi_start_clock failed\n")); - return ERROR; - } -#endif /* HSMODE */ - - if (!bcmspi_host_device_init_adapt(sd)) { - sd_err(("bcmspi_host_device_init_adapt failed\n")); - return ERROR; - } - - if (!bcmspi_test_card(sd)) { - sd_err(("bcmspi_test_card failed\n")); - return ERROR; - } - - sd->num_funcs = SPI_MAX_IOFUNCS; - - get_client_blocksize(sd); - - /* Apply resync pattern cmd with all zeros to reset spi-bkplane F1 logic */ - bcmspi_resync_f1(sd); - - sd->dwordmode = FALSE; - - bcmspi_card_regread(sd, 0, SPID_STATUS_ENABLE, 1, &status_en_reg); - - sd_trace(("%s: Enabling interrupt with dstatus \n", __FUNCTION__)); - status_en_reg |= INTR_WITH_STATUS; - - if (bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_STATUS_ENABLE, 1, - status_en_reg & 0xff) != SUCCESS) { - sd_err(("%s: Unable to set response delay for all fun's.\n", __FUNCTION__)); - return ERROR; - } - -#ifndef HSMODE - /* After configuring for High-Speed mode, set the desired clock rate. */ - if (!spi_start_clock(sd, 4)) { - sd_err(("spi_start_clock failed\n")); - return ERROR; - } -#endif /* HSMODE */ - - /* check to see if the response delay needs to be programmed properly */ - { - uint32 f1_respdelay = 0; - bcmspi_card_regread(sd, 0, SPID_RESP_DELAY_F1, 1, &f1_respdelay); - if ((f1_respdelay == 0) || (f1_respdelay == 0xFF)) { - /* older sdiodevice core and has no separte resp delay for each of */ - sd_err(("older corerev < 4 so use the same resp delay for all funcs\n")); - sd->resp_delay_new = FALSE; - } - else { - /* older sdiodevice core and has no separte resp delay for each of */ - int ret_val; - sd->resp_delay_new = TRUE; - sd_err(("new corerev >= 4 so set the resp delay for each of the funcs\n")); - sd_trace(("resp delay for funcs f0(%d), f1(%d), f2(%d), f3(%d)\n", - GSPI_F0_RESP_DELAY, GSPI_F1_RESP_DELAY, - GSPI_F2_RESP_DELAY, GSPI_F3_RESP_DELAY)); - ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F0, 1, - GSPI_F0_RESP_DELAY); - if (ret_val != SUCCESS) { - sd_err(("%s: Unable to set response delay for F0\n", __FUNCTION__)); - return ERROR; - } - ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F1, 1, - GSPI_F1_RESP_DELAY); - if (ret_val != SUCCESS) { - sd_err(("%s: Unable to set response delay for F1\n", __FUNCTION__)); - return ERROR; - } - ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F2, 1, - GSPI_F2_RESP_DELAY); - if (ret_val != SUCCESS) { - sd_err(("%s: Unable to set response delay for F2\n", __FUNCTION__)); - return ERROR; - } - ret_val = bcmspi_card_regwrite(sd, SPI_FUNC_0, SPID_RESP_DELAY_F3, 1, - GSPI_F3_RESP_DELAY); - if (ret_val != SUCCESS) { - sd_err(("%s: Unable to set response delay for F2\n", __FUNCTION__)); - return ERROR; - } - } - } - - - sd->card_init_done = TRUE; - - /* get the device rev to program the prop respdelays */ - - return SUCCESS; -} - -static int -bcmspi_set_highspeed_mode(sdioh_info_t *sd, bool hsmode) -{ - uint32 regdata; - int status; - - if ((status = bcmspi_card_regread(sd, 0, SPID_CONFIG, - 4, ®data)) != SUCCESS) - return status; - - sd_trace(("In %s spih-ctrl = 0x%x \n", __FUNCTION__, regdata)); - - - if (hsmode == TRUE) { - sd_trace(("Attempting to enable High-Speed mode.\n")); - - if (regdata & HIGH_SPEED_MODE) { - sd_trace(("Device is already in High-Speed mode.\n")); - return status; - } else { - regdata |= HIGH_SPEED_MODE; - sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); - if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, - 4, regdata)) != SUCCESS) { - return status; - } - } - } else { - sd_trace(("Attempting to disable High-Speed mode.\n")); - - if (regdata & HIGH_SPEED_MODE) { - regdata &= ~HIGH_SPEED_MODE; - sd_trace(("Writing %08x to device at %08x\n", regdata, SPID_CONFIG)); - if ((status = bcmspi_card_regwrite(sd, 0, SPID_CONFIG, - 4, regdata)) != SUCCESS) - return status; - } - else { - sd_trace(("Device is already in Low-Speed mode.\n")); - return status; - } - } - spi_controller_highspeed_mode(sd, hsmode); - - return TRUE; -} - -#define bcmspi_find_curr_mode(sd) { \ - sd->wordlen = 2; \ - status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ - regdata &= 0xff; \ - if ((regdata == 0xad) || (regdata == 0x5b) || \ - (regdata == 0x5d) || (regdata == 0x5a)) \ - break; \ - sd->wordlen = 4; \ - status = bcmspi_card_regread_fixedaddr(sd, 0, SPID_TEST_READ, 4, ®data); \ - regdata &= 0xff; \ - if ((regdata == 0xad) || (regdata == 0x5b) || \ - (regdata == 0x5d) || (regdata == 0x5a)) \ - break; \ - sd_trace(("Silicon testability issue: regdata = 0x%x." \ - " Expected 0xad, 0x5a, 0x5b or 0x5d.\n", regdata)); \ - OSL_DELAY(100000); \ -} - -#define INIT_ADAPT_LOOP 100 - -/* Adapt clock-phase-speed-bitwidth between host and device */ -static bool -bcmspi_host_device_init_adapt(sdioh_info_t *sd) -{ - uint32 wrregdata, regdata = 0; - int status; - int i; - - /* Due to a silicon testability issue, the first command from the Host - * to the device will get corrupted (first bit will be lost). So the - * Host should poll the device with a safe read request. ie: The Host - * should try to read F0 addr 0x14 using the Fixed address mode - * (This will prevent a unintended write command to be detected by device) - */ - for (i = 0; i < INIT_ADAPT_LOOP; i++) { - /* If device was not power-cycled it will stay in 32bit mode with - * response-delay-all bit set. Alternate the iteration so that - * read either with or without response-delay for F0 to succeed. - */ - bcmspi_find_curr_mode(sd); - sd->resp_delay_all = (i & 0x1) ? TRUE : FALSE; - - bcmspi_find_curr_mode(sd); - sd->dwordmode = TRUE; - - bcmspi_find_curr_mode(sd); - sd->dwordmode = FALSE; - } - - /* Bail out, device not detected */ - if (i == INIT_ADAPT_LOOP) - return FALSE; - - /* Softreset the spid logic */ - if ((sd->dwordmode) || (sd->wordlen == 4)) { - bcmspi_card_regwrite(sd, 0, SPID_RESET_BP, 1, RESET_ON_WLAN_BP_RESET|RESET_SPI); - bcmspi_card_regread(sd, 0, SPID_RESET_BP, 1, ®data); - sd_trace(("reset reg read = 0x%x\n", regdata)); - sd_trace(("dwordmode = %d, wordlen = %d, resp_delay_all = %d\n", sd->dwordmode, - sd->wordlen, sd->resp_delay_all)); - /* Restore default state after softreset */ - sd->wordlen = 2; - sd->dwordmode = FALSE; - } - - if (sd->wordlen == 4) { - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != - SUCCESS) - return FALSE; - if (regdata == TEST_RO_DATA_32BIT_LE) { - sd_trace(("Spid is already in 32bit LE mode. Value read = 0x%x\n", - regdata)); - sd_trace(("Spid power was left on.\n")); - } else { - sd_err(("Spid power was left on but signature read failed." - " Value read = 0x%x\n", regdata)); - return FALSE; - } - } else { - sd->wordlen = 2; - -#define CTRL_REG_DEFAULT 0x00010430 /* according to the host m/c */ - - wrregdata = (CTRL_REG_DEFAULT); - - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) - return FALSE; - sd_trace(("(we are still in 16bit mode) 32bit READ LE regdata = 0x%x\n", regdata)); - -#ifndef HSMODE - wrregdata |= (CLOCK_PHASE | CLOCK_POLARITY); - wrregdata &= ~HIGH_SPEED_MODE; - bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); -#endif /* HSMODE */ - - for (i = 0; i < INIT_ADAPT_LOOP; i++) { - if ((regdata == 0xfdda7d5b) || (regdata == 0xfdda7d5a)) { - sd_trace(("0xfeedbead was leftshifted by 1-bit.\n")); - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, - ®data)) != SUCCESS) - return FALSE; - } - OSL_DELAY(1000); - } - -#if defined(CHANGE_SPI_INTR_POLARITY_ACTIVE_HIGH) - /* Change to host controller intr-polarity of active-high */ - wrregdata |= INTR_POLARITY; -#else - /* Change to host controller intr-polarity of active-low */ - wrregdata &= ~INTR_POLARITY; -#endif /* CHANGE_SPI_INTR_POLARITY_ACTIVE_HIGH */ - - sd_trace(("(we are still in 16bit mode) 32bit Write LE reg-ctrl-data = 0x%x\n", - wrregdata)); - /* Change to 32bit mode */ - wrregdata |= WORD_LENGTH_32; - bcmspi_card_regwrite(sd, 0, SPID_CONFIG, 4, wrregdata); - - /* Change command/data packaging in 32bit LE mode */ - sd->wordlen = 4; - - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) - return FALSE; - - if (regdata == TEST_RO_DATA_32BIT_LE) { - sd_trace(("Read spid passed. Value read = 0x%x\n", regdata)); - sd_trace(("Spid had power-on cycle OR spi was soft-resetted \n")); - } else { - sd_err(("Stale spid reg values read as it was kept powered. Value read =" - "0x%x\n", regdata)); - return FALSE; - } - } - - - return TRUE; -} - -static bool -bcmspi_test_card(sdioh_info_t *sd) -{ - uint32 regdata; - int status; - - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_READ, 4, ®data)) != SUCCESS) - return FALSE; - - if (regdata == (TEST_RO_DATA_32BIT_LE)) - sd_trace(("32bit LE regdata = 0x%x\n", regdata)); - else { - sd_trace(("Incorrect 32bit LE regdata = 0x%x\n", regdata)); - return FALSE; - } - - -#define RW_PATTERN1 0xA0A1A2A3 -#define RW_PATTERN2 0x4B5B6B7B - - regdata = RW_PATTERN1; - if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) - return FALSE; - regdata = 0; - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) - return FALSE; - if (regdata != RW_PATTERN1) { - sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", - RW_PATTERN1, regdata)); - return FALSE; - } else - sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); - - regdata = RW_PATTERN2; - if ((status = bcmspi_card_regwrite(sd, 0, SPID_TEST_RW, 4, regdata)) != SUCCESS) - return FALSE; - regdata = 0; - if ((status = bcmspi_card_regread(sd, 0, SPID_TEST_RW, 4, ®data)) != SUCCESS) - return FALSE; - if (regdata != RW_PATTERN2) { - sd_err(("Write-Read spid failed. Value wrote = 0x%x, Value read = 0x%x\n", - RW_PATTERN2, regdata)); - return FALSE; - } else - sd_trace(("R/W spid passed. Value read = 0x%x\n", regdata)); - - return TRUE; -} - -static int -bcmspi_driver_init(sdioh_info_t *sd) -{ - sd_trace(("%s\n", __FUNCTION__)); - if ((bcmspi_host_init(sd)) != SUCCESS) { - return ERROR; - } - - if (bcmspi_client_init(sd) != SUCCESS) { - return ERROR; - } - - return SUCCESS; -} - -/* Read device reg */ -static int -bcmspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) -{ - int status; - uint32 cmd_arg, dstatus; - - ASSERT(regsize); - - if (func == 2) - sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); - - sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d\n", - __FUNCTION__, cmd_arg, func, regaddr, regsize)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) != SUCCESS) - return status; - - bcmspi_cmd_getdstatus(sd, &dstatus); - if (dstatus) - sd_trace(("dstatus =0x%x\n", dstatus)); - - return SUCCESS; -} - -static int -bcmspi_card_regread_fixedaddr(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) -{ - - int status; - uint32 cmd_arg; - uint32 dstatus; - - ASSERT(regsize); - - if (func == 2) - sd_trace(("Reg access on F2 will generate error indication in dstatus bits.\n")); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 0); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); /* Fixed access */ - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize); - - sd_trace(("%s: RD cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d\n", - __FUNCTION__, cmd_arg, func, regaddr, regsize)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, regsize)) != SUCCESS) - return status; - - sd_trace(("%s: RD result=0x%x\n", __FUNCTION__, *data)); - - bcmspi_cmd_getdstatus(sd, &dstatus); - sd_trace(("dstatus =0x%x\n", dstatus)); - return SUCCESS; -} - -/* write a device register */ -static int -bcmspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) -{ - int status; - uint32 cmd_arg, dstatus; - - ASSERT(regsize); - - cmd_arg = 0; - - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, regsize == BLOCK_SIZE_F2 ? 0 : regsize); - - sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x regsize=%d data=0x%x\n", - __FUNCTION__, cmd_arg, func, regaddr, regsize, data)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, regsize)) != SUCCESS) - return status; - - bcmspi_cmd_getdstatus(sd, &dstatus); - if (dstatus) - sd_trace(("dstatus=0x%x\n", dstatus)); - - return SUCCESS; -} - -/* write a device register - 1 byte */ -static int -bcmspi_card_bytewrite(sdioh_info_t *sd, int func, uint32 regaddr, uint8 *byte) -{ - int status; - uint32 cmd_arg; - uint32 dstatus; - uint32 data = (uint32)(*byte); - - cmd_arg = 0; - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); /* Incremental access */ - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, regaddr); - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, 1); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, 1); - - sd_trace(("%s: WR cmd_arg=0x%x func=%d regaddr=0x%x data=0x%x\n", - __FUNCTION__, cmd_arg, func, regaddr, data)); - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, &data, 1)) != SUCCESS) - return status; - - bcmspi_cmd_getdstatus(sd, &dstatus); - if (dstatus) - sd_trace(("dstatus =0x%x\n", dstatus)); - - return SUCCESS; -} - -void -bcmspi_cmd_getdstatus(sdioh_info_t *sd, uint32 *dstatus_buffer) -{ - *dstatus_buffer = sd->card_dstatus; -} - -/* 'data' is of type uint32 whereas other buffers are of type uint8 */ -static int -bcmspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd_arg, - uint32 *data, uint32 datalen) -{ - uint32 i, j; - uint8 resp_delay = 0; - int err = SUCCESS; - uint32 hostlen; - uint32 spilen = 0; - uint32 dstatus_idx = 0; - uint16 templen, buslen, len, *ptr = NULL; - - sd_trace(("spi cmd = 0x%x\n", cmd_arg)); - - /* Set up and issue the SPI command. MSByte goes out on bus first. Increase datalen - * according to the wordlen mode(16/32bit) the device is in. - */ - if (sd->wordlen == 4) { /* 32bit spid */ - *(uint32 *)spi_outbuf = SPISWAP_WD4(cmd_arg); - if (datalen & 0x3) - datalen += (4 - (datalen & 0x3)); - } else if (sd->wordlen == 2) { /* 16bit spid */ - *(uint32 *)spi_outbuf = SPISWAP_WD2(cmd_arg); - if (datalen & 0x1) - datalen++; - if (datalen < 4) - datalen = ROUNDUP(datalen, 4); - } else { - sd_err(("Host is %d bit spid, could not create SPI command.\n", - 8 * sd->wordlen)); - return ERROR; - } - - /* for Write, put the data into the output buffer */ - if (GFIELD(cmd_arg, SPI_RW_FLAG) == 1) { - /* We send len field of hw-header always a mod16 size, both from host and dongle */ - if (datalen != 0) { - for (i = 0; i < datalen/4; i++) { - if (sd->wordlen == 4) { /* 32bit spid */ - *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = - SPISWAP_WD4(data[i]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - *(uint32 *)&spi_outbuf[i * 4 + CMDLEN] = - SPISWAP_WD2(data[i]); - } - } - } - } - - /* Append resp-delay number of bytes and clock them out for F0/1/2 reads. */ - if ((GFIELD(cmd_arg, SPI_RW_FLAG) == 0)) { - int func = GFIELD(cmd_arg, SPI_FUNCTION); - switch (func) { - case 0: - if (sd->resp_delay_new) - resp_delay = GSPI_F0_RESP_DELAY; - else - resp_delay = sd->resp_delay_all ? F0_RESPONSE_DELAY : 0; - break; - case 1: - if (sd->resp_delay_new) - resp_delay = GSPI_F1_RESP_DELAY; - else - resp_delay = F1_RESPONSE_DELAY; - break; - case 2: - if (sd->resp_delay_new) - resp_delay = GSPI_F2_RESP_DELAY; - else - resp_delay = sd->resp_delay_all ? F2_RESPONSE_DELAY : 0; - break; - default: - ASSERT(0); - break; - } - /* Program response delay */ - if (sd->resp_delay_new == FALSE) - bcmspi_prog_resp_delay(sd, func, resp_delay); - } - - /* +4 for cmd and +4 for dstatus */ - hostlen = datalen + 8 + resp_delay; - hostlen += dstatus_idx; - hostlen += (4 - (hostlen & 0x3)); - spi_sendrecv(sd, spi_outbuf, spi_inbuf, hostlen); - - /* for Read, get the data into the input buffer */ - if (datalen != 0) { - if (GFIELD(cmd_arg, SPI_RW_FLAG) == 0) { /* if read cmd */ - for (j = 0; j < datalen/4; j++) { - if (sd->wordlen == 4) { /* 32bit spid */ - data[j] = SPISWAP_WD4(*(uint32 *)&spi_inbuf[j * 4 + - CMDLEN + resp_delay]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - data[j] = SPISWAP_WD2(*(uint32 *)&spi_inbuf[j * 4 + - CMDLEN + resp_delay]); - } - } - } - } - - dstatus_idx += (datalen + CMDLEN + resp_delay); - /* Last 4bytes are dstatus. Device is configured to return status bits. */ - if (sd->wordlen == 4) { /* 32bit spid */ - sd->card_dstatus = SPISWAP_WD4(*(uint32 *)&spi_inbuf[dstatus_idx]); - } else if (sd->wordlen == 2) { /* 16bit spid */ - sd->card_dstatus = SPISWAP_WD2(*(uint32 *)&spi_inbuf[dstatus_idx]); - } else { - sd_err(("Host is %d bit machine, could not read SPI dstatus.\n", - 8 * sd->wordlen)); - return ERROR; - } - if (sd->card_dstatus == 0xffffffff) { - sd_err(("looks like not a GSPI device or device is not powered.\n")); - } - - err = bcmspi_update_stats(sd, cmd_arg); - - return err; - -} - -static int -bcmspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, - uint32 addr, int nbytes, uint32 *data) -{ - int status; - uint32 cmd_arg; - bool write = rw == SDIOH_READ ? 0 : 1; - uint retries = 0; - - bool enable; - uint32 spilen; - - cmd_arg = 0; - - ASSERT(nbytes); - ASSERT(nbytes <= sd->client_block_size[func]); - - if (write) sd->t_cnt++; else sd->r_cnt++; - - if (func == 2) { - /* Frame len check limited by gSPI. */ - if ((nbytes > 2000) && write) { - sd_trace((">2KB write: F2 wr of %d bytes\n", nbytes)); - } - /* ASSERT(nbytes <= 2048); Fix bigger len gspi issue and uncomment. */ - /* If F2 fifo on device is not ready to receive data, don't do F2 transfer */ - if (write) { - uint32 dstatus; - /* check F2 ready with cached one */ - bcmspi_cmd_getdstatus(sd, &dstatus); - if ((dstatus & STATUS_F2_RX_READY) == 0) { - retries = WAIT_F2RXFIFORDY; - enable = 0; - while (retries-- && !enable) { - OSL_DELAY(WAIT_F2RXFIFORDY_DELAY * 1000); - bcmspi_card_regread(sd, SPI_FUNC_0, SPID_STATUS_REG, 4, - &dstatus); - if (dstatus & STATUS_F2_RX_READY) - enable = TRUE; - } - if (!enable) { - struct spierrstats_t *spierrstats = &sd->spierrstats; - spierrstats->f2rxnotready++; - sd_err(("F2 FIFO is not ready to receive data.\n")); - return ERROR; - } - sd_trace(("No of retries on F2 ready %d\n", - (WAIT_F2RXFIFORDY - retries))); - } - } - } - - /* F2 transfers happen on 0 addr */ - addr = (func == 2) ? 0 : addr; - - /* In pio mode buffer is read using fixed address fifo in func 1 */ - if ((func == 1) && (fifo)) - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 0); - else - cmd_arg = SFIELD(cmd_arg, SPI_ACCESS, 1); - - cmd_arg = SFIELD(cmd_arg, SPI_FUNCTION, func); - cmd_arg = SFIELD(cmd_arg, SPI_REG_ADDR, addr); - cmd_arg = SFIELD(cmd_arg, SPI_RW_FLAG, write); - spilen = sd->data_xfer_count = MIN(sd->client_block_size[func], nbytes); - if ((sd->dwordmode == TRUE) && (GFIELD(cmd_arg, SPI_FUNCTION) == SPI_FUNC_2)) { - /* convert len to mod4 size */ - spilen = spilen + ((spilen & 0x3) ? (4 - (spilen & 0x3)): 0); - cmd_arg = SFIELD(cmd_arg, SPI_LEN, (spilen >> 2)); - } else - cmd_arg = SFIELD(cmd_arg, SPI_LEN, spilen); - - if ((func == 2) && (fifo == 1)) { - sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", - __FUNCTION__, write ? "Wr" : "Rd", func, "INCR", - addr, nbytes, sd->r_cnt, sd->t_cnt)); - } - - sd_trace(("%s cmd_arg = 0x%x\n", __FUNCTION__, cmd_arg)); - sd_data(("%s: %s func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", - __FUNCTION__, write ? "Wd" : "Rd", func, "INCR", - addr, nbytes, sd->r_cnt, sd->t_cnt)); - - - if ((status = bcmspi_cmd_issue(sd, sd->sd_use_dma, cmd_arg, data, nbytes)) != SUCCESS) { - sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__, - (write ? "write" : "read"))); - return status; - } - - /* gSPI expects that hw-header-len is equal to spi-command-len */ - if ((func == 2) && (rw == SDIOH_WRITE) && (sd->dwordmode == FALSE)) { - ASSERT((uint16)sd->data_xfer_count == (uint16)(*data & 0xffff)); - ASSERT((uint16)sd->data_xfer_count == (uint16)(~((*data & 0xffff0000) >> 16))); - } - - if ((nbytes > 2000) && !write) { - sd_trace((">2KB read: F2 rd of %d bytes\n", nbytes)); - } - - return SUCCESS; -} - -/* Reset and re-initialize the device */ -int -sdioh_sdio_reset(sdioh_info_t *si) -{ - si->card_init_done = FALSE; - return bcmspi_client_init(si); -} - -SDIOH_API_RC -sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio) -{ - return SDIOH_API_RC_FAIL; -} - -SDIOH_API_RC -sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab) -{ - return SDIOH_API_RC_FAIL; -} - -bool -sdioh_gpioin(sdioh_info_t *sd, uint32 gpio) -{ - return FALSE; -} - -SDIOH_API_RC -sdioh_gpio_init(sdioh_info_t *sd) -{ - return SDIOH_API_RC_FAIL; -}
diff --git a/bcmdhd.1.579.77.41.x/bcmutils.c b/bcmdhd.1.579.77.41.x/bcmutils.c deleted file mode 100644 index 926d496..0000000 --- a/bcmdhd.1.579.77.41.x/bcmutils.c +++ /dev/null
@@ -1,4163 +0,0 @@ -/* - * Driver O/S-independent utility routines - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: bcmutils.c 699163 2017-05-12 05:18:23Z $ - */ - -#include <bcm_cfg.h> -#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> -#include <bcmutils.h> - -#if defined(BCMEXTSUP) -#include <bcm_osl.h> -#endif - -#ifndef ASSERT -#define ASSERT(exp) -#endif - -#endif /* !BCMDRIVER */ - -#include <bcmendian.h> -#include <bcmdevs.h> -#include <ethernet.h> -#include <vlan.h> -#include <bcmip.h> -#include <802.1d.h> -#include <802.11.h> -#include <bcmip.h> -#include <bcmipv6.h> -#include <bcmtcp.h> -#include <dhd_dbg.h> - -/* Look-up table to calculate head room present in a number */ -static const uint8 msb_table[] = { - 0, 1, 2, 2, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, -}; - -void *_bcmutils_dummy_fn = NULL; - - - - -#ifdef BCMDRIVER - - -/* copy a pkt buffer chain into a buffer */ -uint -pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf) -{ - uint n, ret = 0; - - if (len < 0) - len = 4096; /* "infinite" */ - - /* skip 'offset' bytes */ - for (; p && offset; p = PKTNEXT(osh, p)) { - if (offset < (uint)PKTLEN(osh, p)) - break; - offset -= PKTLEN(osh, p); - } - - if (!p) - return 0; - - /* copy the data */ - for (; p && len; p = PKTNEXT(osh, p)) { - n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); - bcopy(PKTDATA(osh, p) + offset, buf, n); - buf += n; - len -= n; - ret += n; - offset = 0; - } - - return ret; -} - -/* copy a buffer into a pkt buffer chain */ -uint -pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf) -{ - uint n, ret = 0; - - - /* skip 'offset' bytes */ - for (; p && offset; p = PKTNEXT(osh, p)) { - if (offset < (uint)PKTLEN(osh, p)) - break; - offset -= PKTLEN(osh, p); - } - - if (!p) - return 0; - - /* copy the data */ - for (; p && len; p = PKTNEXT(osh, p)) { - n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len); - bcopy(buf, PKTDATA(osh, p) + offset, n); - buf += n; - len -= n; - ret += n; - offset = 0; - } - - return ret; -} - - - -/* return total length of buffer chain */ -uint BCMFASTPATH -pkttotlen(osl_t *osh, void *p) -{ - uint total; - int len; - - total = 0; - for (; p; p = PKTNEXT(osh, p)) { - len = PKTLEN(osh, p); - total += len; -#ifdef BCMLFRAG - if (BCMLFRAG_ENAB()) { - if (PKTISFRAG(osh, p)) { - total += PKTFRAGTOTLEN(osh, p); - } - } -#endif - } - - return (total); -} - -/* return the last buffer of chained pkt */ -void * -pktlast(osl_t *osh, void *p) -{ - for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p)) - ; - - return (p); -} - -/* count segments of a chained packet */ -uint BCMFASTPATH -pktsegcnt(osl_t *osh, void *p) -{ - uint cnt; - - for (cnt = 0; p; p = PKTNEXT(osh, p)) { - cnt++; -#ifdef BCMLFRAG - if (BCMLFRAG_ENAB()) { - if (PKTISFRAG(osh, p)) { - cnt += PKTFRAGTOTNUM(osh, p); - } - } -#endif - } - - return cnt; -} - - -/* count segments of a chained packet */ -uint BCMFASTPATH -pktsegcnt_war(osl_t *osh, void *p) -{ - uint cnt; - uint8 *pktdata; - uint len, remain, align64; - - for (cnt = 0; p; p = PKTNEXT(osh, p)) { - cnt++; - len = PKTLEN(osh, p); - if (len > 128) { - pktdata = (uint8 *)PKTDATA(osh, p); /* starting address of data */ - /* Check for page boundary straddle (2048B) */ - if (((uintptr)pktdata & ~0x7ff) != ((uintptr)(pktdata+len) & ~0x7ff)) - cnt++; - - align64 = (uint)((uintptr)pktdata & 0x3f); /* aligned to 64B */ - align64 = (64 - align64) & 0x3f; - len -= align64; /* bytes from aligned 64B to end */ - /* if aligned to 128B, check for MOD 128 between 1 to 4B */ - remain = len % 128; - if (remain > 0 && remain <= 4) - cnt++; /* add extra seg */ - } - } - - return cnt; -} - -uint8 * BCMFASTPATH -pktdataoffset(osl_t *osh, void *p, uint offset) -{ - uint total = pkttotlen(osh, p); - uint pkt_off = 0, len = 0; - uint8 *pdata = (uint8 *) PKTDATA(osh, p); - - if (offset > total) - return NULL; - - for (; p; p = PKTNEXT(osh, p)) { - pdata = (uint8 *) PKTDATA(osh, p); - pkt_off = offset - len; - len += PKTLEN(osh, p); - if (len > offset) - break; - } - return (uint8*) (pdata+pkt_off); -} - - -/* given a offset in pdata, find the pkt seg hdr */ -void * -pktoffset(osl_t *osh, void *p, uint offset) -{ - uint total = pkttotlen(osh, p); - uint len = 0; - - if (offset > total) - return NULL; - - for (; p; p = PKTNEXT(osh, p)) { - len += PKTLEN(osh, p); - if (len > offset) - break; - } - return p; -} - -#endif /* BCMDRIVER */ - -#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) -const unsigned char bcm_ctype[] = { - - _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */ - _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C, - _BCM_C, /* 8-15 */ - _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */ - _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */ - _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */ - _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */ - _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */ - _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */ - _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, - _BCM_U|_BCM_X, _BCM_U, /* 64-71 */ - _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */ - _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */ - _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */ - _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, - _BCM_L|_BCM_X, _BCM_L, /* 96-103 */ - _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */ - _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */ - _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */ - _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, - _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */ - _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, - _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */ - _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, - _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */ - _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U, - _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */ - _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, - _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */ - _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L, - _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */ -}; - -ulong -bcm_strtoul(const char *cp, char **endp, uint base) -{ - ulong result, last_result = 0, value; - bool minus; - - minus = FALSE; - - while (bcm_isspace(*cp)) - cp++; - - if (cp[0] == '+') - cp++; - else if (cp[0] == '-') { - minus = TRUE; - cp++; - } - - if (base == 0) { - if (cp[0] == '0') { - if ((cp[1] == 'x') || (cp[1] == 'X')) { - base = 16; - cp = &cp[2]; - } else { - base = 8; - cp = &cp[1]; - } - } else - base = 10; - } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) { - cp = &cp[2]; - } - - result = 0; - - while (bcm_isxdigit(*cp) && - (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) { - result = result*base + value; - /* Detected overflow */ - if (result < last_result && !minus) { - if (endp) { - /* Go to the end of current number */ - while (bcm_isxdigit(*cp)) { - cp++; - } - *endp = DISCARD_QUAL(cp, char); - } - return (ulong)-1; - } - last_result = result; - cp++; - } - - if (minus) - result = (ulong)(-(long)result); - - if (endp) - *endp = DISCARD_QUAL(cp, char); - - return (result); -} - -int -bcm_atoi(const char *s) -{ - return (int)bcm_strtoul(s, NULL, 10); -} - -/* return pointer to location of substring 'needle' in 'haystack' */ -char * -bcmstrstr(const char *haystack, const char *needle) -{ - int len, nlen; - int i; - - if ((haystack == NULL) || (needle == NULL)) - return DISCARD_QUAL(haystack, char); - - nlen = (int)strlen(needle); - len = (int)strlen(haystack) - nlen + 1; - - for (i = 0; i < len; i++) - if (memcmp(needle, &haystack[i], nlen) == 0) - return DISCARD_QUAL(&haystack[i], char); - return (NULL); -} - -char * -bcmstrnstr(const char *s, uint s_len, const char *substr, uint substr_len) -{ - for (; s_len >= substr_len; s++, s_len--) - if (strncmp(s, substr, substr_len) == 0) - return DISCARD_QUAL(s, char); - - return NULL; -} - -char * -bcmstrcat(char *dest, const char *src) -{ - char *p; - - p = dest + strlen(dest); - - while ((*p++ = *src++) != '\0') - ; - - return (dest); -} - -char * -bcmstrncat(char *dest, const char *src, uint size) -{ - char *endp; - char *p; - - p = dest + strlen(dest); - endp = p + size; - - while (p != endp && (*p++ = *src++) != '\0') - ; - - return (dest); -} - - -/**************************************************************************** -* Function: bcmstrtok -* -* Purpose: -* Tokenizes a string. This function is conceptually similiar to ANSI C strtok(), -* but allows strToken() to be used by different strings or callers at the same -* time. Each call modifies '*string' by substituting a NULL character for the -* first delimiter that is encountered, and updates 'string' to point to the char -* after the delimiter. Leading delimiters are skipped. -* -* Parameters: -* string (mod) Ptr to string ptr, updated by token. -* delimiters (in) Set of delimiter characters. -* tokdelim (out) Character that delimits the returned token. (May -* be set to NULL if token delimiter is not required). -* -* Returns: Pointer to the next token found. NULL when no more tokens are found. -***************************************************************************** -*/ -char * -bcmstrtok(char **string, const char *delimiters, char *tokdelim) -{ - unsigned char *str; - unsigned long map[8]; - int count; - char *nextoken; - - if (tokdelim != NULL) { - /* Prime the token delimiter */ - *tokdelim = '\0'; - } - - /* Clear control map */ - for (count = 0; count < 8; count++) { - map[count] = 0; - } - - /* Set bits in delimiter table */ - do { - map[*delimiters >> 5] |= (1 << (*delimiters & 31)); - } - while (*delimiters++); - - str = (unsigned char*)*string; - - /* Find beginning of token (skip over leading delimiters). Note that - * there is no token iff this loop sets str to point to the terminal - * null (*str == '\0') - */ - while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) { - str++; - } - - nextoken = (char*)str; - - /* Find the end of the token. If it is not the end of the string, - * put a null there. - */ - for (; *str; str++) { - if (map[*str >> 5] & (1 << (*str & 31))) { - if (tokdelim != NULL) { - *tokdelim = *str; - } - - *str++ = '\0'; - break; - } - } - - *string = (char*)str; - - /* Determine if a token has been found. */ - if (nextoken == (char *) str) { - return NULL; - } - else { - return nextoken; - } -} - - -#define xToLower(C) \ - ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C) - - -/**************************************************************************** -* Function: bcmstricmp -* -* Purpose: Compare to strings case insensitively. -* -* Parameters: s1 (in) First string to compare. -* s2 (in) Second string to compare. -* -* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if -* t1 > t2, when ignoring case sensitivity. -***************************************************************************** -*/ -int -bcmstricmp(const char *s1, const char *s2) -{ - char dc, sc; - - while (*s2 && *s1) { - dc = xToLower(*s1); - sc = xToLower(*s2); - if (dc < sc) return -1; - if (dc > sc) return 1; - s1++; - s2++; - } - - if (*s1 && !*s2) return 1; - if (!*s1 && *s2) return -1; - return 0; -} - - -/**************************************************************************** -* Function: bcmstrnicmp -* -* Purpose: Compare to strings case insensitively, upto a max of 'cnt' -* characters. -* -* Parameters: s1 (in) First string to compare. -* s2 (in) Second string to compare. -* cnt (in) Max characters to compare. -* -* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if -* t1 > t2, when ignoring case sensitivity. -***************************************************************************** -*/ -int -bcmstrnicmp(const char* s1, const char* s2, int cnt) -{ - char dc, sc; - - while (*s2 && *s1 && cnt) { - dc = xToLower(*s1); - sc = xToLower(*s2); - if (dc < sc) return -1; - if (dc > sc) return 1; - s1++; - s2++; - cnt--; - } - - if (!cnt) return 0; - if (*s1 && !*s2) return 1; - if (!*s1 && *s2) return -1; - return 0; -} - -/* parse a xx:xx:xx:xx:xx:xx format ethernet address */ -int -bcm_ether_atoe(const char *p, struct ether_addr *ea) -{ - int i = 0; - char *ep; - - for (;;) { - ea->octet[i++] = (char) bcm_strtoul(p, &ep, 16); - p = ep; - if (!*p++ || i == 6) - break; - } - - return (i == 6); -} - -int -bcm_atoipv4(const char *p, struct ipv4_addr *ip) -{ - - int i = 0; - char *c; - for (;;) { - ip->addr[i++] = (uint8)bcm_strtoul(p, &c, 0); - if (*c++ != '.' || i == IPV4_ADDR_LEN) - break; - p = c; - } - return (i == IPV4_ADDR_LEN); -} -#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ - - -#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER) -/* registry routine buffer preparation utility functions: - * parameter order is like strncpy, but returns count - * of bytes copied. Minimum bytes copied is null char(1)/wchar(2) - */ -ulong -wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen) -{ - ulong copyct = 1; - ushort i; - - if (abuflen == 0) - return 0; - - /* wbuflen is in bytes */ - wbuflen /= sizeof(ushort); - - for (i = 0; i < wbuflen; ++i) { - if (--abuflen == 0) - break; - *abuf++ = (char) *wbuf++; - ++copyct; - } - *abuf = '\0'; - - return copyct; -} -#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */ - -char * -bcm_ether_ntoa(const struct ether_addr *ea, char *buf) -{ - static const char hex[] = - { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; - const uint8 *octet = ea->octet; - char *p = buf; - int i; - - for (i = 0; i < 6; i++, octet++) { - *p++ = hex[(*octet >> 4) & 0xf]; - *p++ = hex[*octet & 0xf]; - *p++ = ':'; - } - - *(p-1) = '\0'; - - return (buf); -} - -char * -bcm_ip_ntoa(struct ipv4_addr *ia, char *buf) -{ - snprintf(buf, 16, "%d.%d.%d.%d", - ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]); - return (buf); -} - -char * -bcm_ipv6_ntoa(void *ipv6, char *buf) -{ - /* Implementing RFC 5952 Sections 4 + 5 */ - /* Not thoroughly tested */ - uint16 tmp[8]; - uint16 *a = &tmp[0]; - char *p = buf; - int i, i_max = -1, cnt = 0, cnt_max = 1; - uint8 *a4 = NULL; - memcpy((uint8 *)&tmp[0], (uint8 *)ipv6, IPV6_ADDR_LEN); - - for (i = 0; i < IPV6_ADDR_LEN/2; i++) { - if (a[i]) { - if (cnt > cnt_max) { - cnt_max = cnt; - i_max = i - cnt; - } - cnt = 0; - } else - cnt++; - } - if (cnt > cnt_max) { - cnt_max = cnt; - i_max = i - cnt; - } - if (i_max == 0 && - /* IPv4-translated: ::ffff:0:a.b.c.d */ - ((cnt_max == 4 && a[4] == 0xffff && a[5] == 0) || - /* IPv4-mapped: ::ffff:a.b.c.d */ - (cnt_max == 5 && a[5] == 0xffff))) - a4 = (uint8*) (a + 6); - - for (i = 0; i < IPV6_ADDR_LEN/2; i++) { - if ((uint8*) (a + i) == a4) { - snprintf(p, 16, ":%u.%u.%u.%u", a4[0], a4[1], a4[2], a4[3]); - break; - } else if (i == i_max) { - *p++ = ':'; - i += cnt_max - 1; - p[0] = ':'; - p[1] = '\0'; - } else { - if (i) - *p++ = ':'; - p += snprintf(p, 8, "%x", ntoh16(a[i])); - } - } - - return buf; -} -#ifdef BCMDRIVER - -void -bcm_mdelay(uint ms) -{ - uint i; - - for (i = 0; i < ms; i++) { - OSL_DELAY(1000); - } -} - - - - - -#if defined(DHD_DEBUG) -/* pretty hex print a pkt buffer chain */ -void -prpkt(const char *msg, osl_t *osh, void *p0) -{ - void *p; - - if (msg && (msg[0] != '\0')) - DHD_PRINT(("%s:\n", msg)); - - for (p = p0; p; p = PKTNEXT(osh, p)) - prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p)); -} -#endif - -/* Takes an Ethernet frame and sets out-of-bound PKTPRIO. - * Also updates the inplace vlan tag if requested. - * For debugging, it returns an indication of what it did. - */ -uint BCMFASTPATH -pktsetprio(void *pkt, bool update_vtag) -{ - struct ether_header *eh; - struct ethervlan_header *evh; - uint8 *pktdata; - int priority = 0; - int rc = 0; - - pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt); - ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); - - eh = (struct ether_header *) pktdata; - - if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) { - uint16 vlan_tag; - int vlan_prio, dscp_prio = 0; - - evh = (struct ethervlan_header *)eh; - - vlan_tag = ntoh16(evh->vlan_tag); - vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; - - if ((evh->ether_type == hton16(ETHER_TYPE_IP)) || - (evh->ether_type == hton16(ETHER_TYPE_IPV6))) { - uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); - uint8 tos_tc = IP_TOS46(ip_body); - dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); - } - - /* DSCP priority gets precedence over 802.1P (vlan tag) */ - if (dscp_prio != 0) { - priority = dscp_prio; - rc |= PKTPRIO_VDSCP; - } else { - priority = vlan_prio; - rc |= PKTPRIO_VLAN; - } - /* - * If the DSCP priority is not the same as the VLAN priority, - * then overwrite the priority field in the vlan tag, with the - * DSCP priority value. This is required for Linux APs because - * the VLAN driver on Linux, overwrites the skb->priority field - * with the priority value in the vlan tag - */ - if (update_vtag && (priority != vlan_prio)) { - vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); - vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; - evh->vlan_tag = hton16(vlan_tag); - rc |= PKTPRIO_UPD; - } -#if defined(EAPOL_PKT_PRIO) || defined(DHD_LOSSLESS_ROAMING) - } else if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) { - priority = PRIO_8021D_NC; - rc = PKTPRIO_DSCP; -#endif /* EAPOL_PKT_PRIO || DHD_LOSSLESS_ROAMING */ - } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) || - (eh->ether_type == hton16(ETHER_TYPE_IPV6))) { - uint8 *ip_body = pktdata + sizeof(struct ether_header); - uint8 tos_tc = IP_TOS46(ip_body); - uint8 dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT; - switch (dscp) { - case DSCP_EF: - priority = PRIO_8021D_VO; - break; - case DSCP_AF31: - case DSCP_AF32: - case DSCP_AF33: - priority = PRIO_8021D_CL; - break; - case DSCP_AF21: - case DSCP_AF22: - case DSCP_AF23: - case DSCP_AF11: - case DSCP_AF12: - case DSCP_AF13: - priority = PRIO_8021D_EE; - break; - default: - priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); - break; - } - - rc |= PKTPRIO_DSCP; - } - - ASSERT(priority >= 0 && priority <= MAXPRIO); - PKTSETPRIO(pkt, priority); - return (rc | priority); -} - -/* lookup user priority for specified DSCP */ -static uint8 -dscp2up(uint8 *up_table, uint8 dscp) -{ - uint8 user_priority = 255; - - /* lookup up from table if parameters valid */ - if (up_table != NULL && dscp < UP_TABLE_MAX) { - user_priority = up_table[dscp]; - } - - /* 255 is unused value so return up from dscp */ - if (user_priority == 255) { - user_priority = dscp >> (IPV4_TOS_PREC_SHIFT - IPV4_TOS_DSCP_SHIFT); - } - - return user_priority; -} - -/* set user priority by QoS Map Set table (UP table), table size is UP_TABLE_MAX */ -uint BCMFASTPATH -pktsetprio_qms(void *pkt, uint8* up_table, bool update_vtag) -{ - if (up_table) { - uint8 *pktdata; - uint pktlen; - uint8 dscp; - uint user_priority = 0; - uint rc = 0; - - pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt); - pktlen = PKTLEN(OSH_NULL, pkt); - - if (pktgetdscp(pktdata, pktlen, &dscp)) { - rc = PKTPRIO_DSCP; - user_priority = dscp2up(up_table, dscp); - PKTSETPRIO(pkt, user_priority); - } - - return (rc | user_priority); - } else { - return pktsetprio(pkt, update_vtag); - } -} - -/* Returns TRUE and DSCP if IP header found, FALSE otherwise. - */ -bool BCMFASTPATH -pktgetdscp(uint8 *pktdata, uint pktlen, uint8 *dscp) -{ - struct ether_header *eh; - struct ethervlan_header *evh; - uint8 *ip_body; - bool rc = FALSE; - - /* minimum length is ether header and IP header */ - if (pktlen < sizeof(struct ether_header) + IPV4_MIN_HEADER_LEN) - return FALSE; - - eh = (struct ether_header *) pktdata; - - if (eh->ether_type == HTON16(ETHER_TYPE_IP)) { - ip_body = pktdata + sizeof(struct ether_header); - *dscp = IP_DSCP46(ip_body); - rc = TRUE; - } - else if (eh->ether_type == HTON16(ETHER_TYPE_8021Q)) { - evh = (struct ethervlan_header *)eh; - - /* minimum length is ethervlan header and IP header */ - if (pktlen >= sizeof(struct ethervlan_header) + IPV4_MIN_HEADER_LEN && - evh->ether_type == HTON16(ETHER_TYPE_IP)) { - ip_body = pktdata + sizeof(struct ethervlan_header); - *dscp = IP_DSCP46(ip_body); - rc = TRUE; - } - } - - return rc; -} - -/* Add to adjust the 802.1x priority */ -void -pktset8021xprio(void *pkt, int prio) -{ - struct ether_header *eh; - uint8 *pktdata; - if(prio == PKTPRIO(pkt)) - return; - pktdata = (uint8 *)PKTDATA(OSH_NULL, pkt); - ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); - eh = (struct ether_header *) pktdata; - if (eh->ether_type == hton16(ETHER_TYPE_802_1X)) { - ASSERT(prio >= 0 && prio <= MAXPRIO); - PKTSETPRIO(pkt, prio); - } -} - -/* usr_prio range from low to high with usr_prio value */ -static bool -up_table_set(uint8 *up_table, uint8 usr_prio, uint8 low, uint8 high) -{ - int i; - - if (usr_prio > 7 || low > high || low >= UP_TABLE_MAX || high >= UP_TABLE_MAX) { - return FALSE; - } - - for (i = low; i <= high; i++) { - up_table[i] = usr_prio; - } - - return TRUE; -} - -/* set user priority table */ -int BCMFASTPATH -wl_set_up_table(uint8 *up_table, bcm_tlv_t *qos_map_ie) -{ - uint8 len; - - if (up_table == NULL || qos_map_ie == NULL) { - return BCME_ERROR; - } - - /* clear table to check table was set or not */ - memset(up_table, 0xff, UP_TABLE_MAX); - - /* length of QoS Map IE must be 16+n*2, n is number of exceptions */ - if (qos_map_ie != NULL && qos_map_ie->id == DOT11_MNG_QOS_MAP_ID && - (len = qos_map_ie->len) >= QOS_MAP_FIXED_LENGTH && - (len % 2) == 0) { - uint8 *except_ptr = (uint8 *)qos_map_ie->data; - uint8 except_len = len - QOS_MAP_FIXED_LENGTH; - uint8 *range_ptr = except_ptr + except_len; - int i; - - /* fill in ranges */ - for (i = 0; i < QOS_MAP_FIXED_LENGTH; i += 2) { - uint8 low = range_ptr[i]; - uint8 high = range_ptr[i + 1]; - if (low == 255 && high == 255) { - continue; - } - - if (!up_table_set(up_table, i / 2, low, high)) { - /* clear the table on failure */ - memset(up_table, 0xff, UP_TABLE_MAX); - return BCME_ERROR; - } - } - - /* update exceptions */ - for (i = 0; i < except_len; i += 2) { - uint8 dscp = except_ptr[i]; - uint8 usr_prio = except_ptr[i+1]; - - /* exceptions with invalid dscp/usr_prio are ignored */ - up_table_set(up_table, usr_prio, dscp, dscp); - } - } - - return BCME_OK; -} - -/* The 0.5KB string table is not removed by compiler even though it's unused */ - -static char bcm_undeferrstr[32]; -static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; - -/* Convert the error codes into related error strings */ -const char * -bcmerrorstr(int bcmerror) -{ - /* check if someone added a bcmerror code but forgot to add errorstring */ - ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1)); - - if (bcmerror > 0 || bcmerror < BCME_LAST) { - snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror); - return bcm_undeferrstr; - } - - ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN); - - return bcmerrorstrtable[-bcmerror]; -} - - -/* iovar table lookup */ -/* could mandate sorted tables and do a binary search */ -const bcm_iovar_t* -bcm_iovar_lookup(const bcm_iovar_t *table, const char *name) -{ - const bcm_iovar_t *vi; - const char *lookup_name; - - /* skip any ':' delimited option prefixes */ - lookup_name = strrchr(name, ':'); - if (lookup_name != NULL) - lookup_name++; - else - lookup_name = name; - - ASSERT(table != NULL); - - for (vi = table; vi->name; vi++) { - if (!strcmp(vi->name, lookup_name)) - return vi; - } - /* ran to end of table */ - - return NULL; /* var name not found */ -} - -int -bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set) -{ - int bcmerror = 0; - BCM_REFERENCE(arg); - - /* length check on io buf */ - switch (vi->type) { - case IOVT_BOOL: - case IOVT_INT8: - case IOVT_INT16: - case IOVT_INT32: - case IOVT_UINT8: - case IOVT_UINT16: - case IOVT_UINT32: - /* all integers are int32 sized args at the ioctl interface */ - if (len < (int)sizeof(int)) { - bcmerror = BCME_BUFTOOSHORT; - } - break; - - case IOVT_BUFFER: - /* buffer must meet minimum length requirement */ - if (len < vi->minlen) { - bcmerror = BCME_BUFTOOSHORT; - } - break; - - case IOVT_VOID: - if (!set) { - /* Cannot return nil... */ - bcmerror = BCME_UNSUPPORTED; - } else if (len) { - /* Set is an action w/o parameters */ - bcmerror = BCME_BUFTOOLONG; - } - break; - - default: - /* unknown type for length check in iovar info */ - ASSERT(0); - bcmerror = BCME_UNSUPPORTED; - } - - return bcmerror; -} - -#endif /* BCMDRIVER */ - -#ifdef BCM_OBJECT_TRACE - -#define BCM_OBJECT_MERGE_SAME_OBJ 0 - -/* some place may add / remove the object to trace list for Linux: */ -/* add: osl_alloc_skb dev_alloc_skb skb_realloc_headroom dhd_start_xmit */ -/* remove: osl_pktfree dev_kfree_skb netif_rx */ - -#define BCM_OBJDBG_COUNT (1024 * 100) -static spinlock_t dbgobj_lock; -#define BCM_OBJDBG_LOCK_INIT() spin_lock_init(&dbgobj_lock) -#define BCM_OBJDBG_LOCK_DESTROY() -#define BCM_OBJDBG_LOCK spin_lock_irqsave -#define BCM_OBJDBG_UNLOCK spin_unlock_irqrestore - -#define BCM_OBJDBG_ADDTOHEAD 0 -#define BCM_OBJDBG_ADDTOTAIL 1 - -#define BCM_OBJDBG_CALLER_LEN 32 -struct bcm_dbgobj { - struct bcm_dbgobj *prior; - struct bcm_dbgobj *next; - uint32 flag; - void *obj; - uint32 obj_sn; - uint32 obj_state; - uint32 line; - char caller[BCM_OBJDBG_CALLER_LEN]; -}; - -static struct bcm_dbgobj *dbgobj_freehead = NULL; -static struct bcm_dbgobj *dbgobj_freetail = NULL; -static struct bcm_dbgobj *dbgobj_objhead = NULL; -static struct bcm_dbgobj *dbgobj_objtail = NULL; - -static uint32 dbgobj_sn = 0; -static int dbgobj_count = 0; -static struct bcm_dbgobj bcm_dbg_objs[BCM_OBJDBG_COUNT]; - -void -bcm_object_trace_init(void) -{ - int i = 0; - BCM_OBJDBG_LOCK_INIT(); - memset(&bcm_dbg_objs, 0x00, sizeof(struct bcm_dbgobj) * BCM_OBJDBG_COUNT); - dbgobj_freehead = &bcm_dbg_objs[0]; - dbgobj_freetail = &bcm_dbg_objs[BCM_OBJDBG_COUNT - 1]; - - for (i = 0; i < BCM_OBJDBG_COUNT; ++i) { - bcm_dbg_objs[i].next = (i == (BCM_OBJDBG_COUNT - 1)) ? - dbgobj_freehead : &bcm_dbg_objs[i + 1]; - bcm_dbg_objs[i].prior = (i == 0) ? - dbgobj_freetail : &bcm_dbg_objs[i - 1]; - } -} - -void -bcm_object_trace_deinit(void) -{ - if (dbgobj_objhead || dbgobj_objtail) { - DHD_ERROR(("%s: not all objects are released\n", __FUNCTION__)); - ASSERT(0); - } - BCM_OBJDBG_LOCK_DESTROY(); -} - -static void -bcm_object_rm_list(struct bcm_dbgobj **head, struct bcm_dbgobj **tail, - struct bcm_dbgobj *dbgobj) -{ - if ((dbgobj == *head) && (dbgobj == *tail)) { - *head = NULL; - *tail = NULL; - } else if (dbgobj == *head) { - *head = (*head)->next; - } else if (dbgobj == *tail) { - *tail = (*tail)->prior; - } - dbgobj->next->prior = dbgobj->prior; - dbgobj->prior->next = dbgobj->next; -} - -static void -bcm_object_add_list(struct bcm_dbgobj **head, struct bcm_dbgobj **tail, - struct bcm_dbgobj *dbgobj, int addtotail) -{ - if (!(*head) && !(*tail)) { - *head = dbgobj; - *tail = dbgobj; - dbgobj->next = dbgobj; - dbgobj->prior = dbgobj; - } else if ((*head) && (*tail)) { - (*tail)->next = dbgobj; - (*head)->prior = dbgobj; - dbgobj->next = *head; - dbgobj->prior = *tail; - if (addtotail == BCM_OBJDBG_ADDTOTAIL) - *tail = dbgobj; - else - *head = dbgobj; - } else { - ASSERT(0); /* can't be this case */ - } -} - -static INLINE void -bcm_object_movetoend(struct bcm_dbgobj **head, struct bcm_dbgobj **tail, - struct bcm_dbgobj *dbgobj, int movetotail) -{ - if ((*head) && (*tail)) { - if (movetotail == BCM_OBJDBG_ADDTOTAIL) { - if (dbgobj != (*tail)) { - bcm_object_rm_list(head, tail, dbgobj); - bcm_object_add_list(head, tail, dbgobj, movetotail); - } - } else { - if (dbgobj != (*head)) { - bcm_object_rm_list(head, tail, dbgobj); - bcm_object_add_list(head, tail, dbgobj, movetotail); - } - } - } else { - ASSERT(0); /* can't be this case */ - } -} - -void -bcm_object_trace_opr(void *obj, uint32 opt, const char *caller, int line) -{ - struct bcm_dbgobj *dbgobj; - unsigned long flags; - - BCM_REFERENCE(flags); - BCM_OBJDBG_LOCK(&dbgobj_lock, flags); - - if (opt == BCM_OBJDBG_ADD_PKT || - opt == BCM_OBJDBG_ADD) { - dbgobj = dbgobj_objtail; - while (dbgobj) { - if (dbgobj->obj == obj) { - DHD_PRINT(("%s: obj %p allocated from %s(%d)," - " allocate again from %s(%d)\n", - __FUNCTION__, dbgobj->obj, - dbgobj->caller, dbgobj->line, - caller, line)); - ASSERT(0); - goto EXIT; - } - dbgobj = dbgobj->prior; - if (dbgobj == dbgobj_objtail) - break; - } - -#if BCM_OBJECT_MERGE_SAME_OBJ - dbgobj = dbgobj_freetail; - while (dbgobj) { - if (dbgobj->obj == obj) { - goto FREED_ENTRY_FOUND; - } - dbgobj = dbgobj->prior; - if (dbgobj == dbgobj_freetail) - break; - } -#endif /* BCM_OBJECT_MERGE_SAME_OBJ */ - - dbgobj = dbgobj_freehead; -#if BCM_OBJECT_MERGE_SAME_OBJ -FREED_ENTRY_FOUND: -#endif /* BCM_OBJECT_MERGE_SAME_OBJ */ - if (!dbgobj) { - DHD_ERROR(("%s: already got %d objects ?????????????????????\n", - __FUNCTION__, BCM_OBJDBG_COUNT)); - ASSERT(0); - goto EXIT; - } - - bcm_object_rm_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj); - dbgobj->obj = obj; - strncpy(dbgobj->caller, caller, BCM_OBJDBG_CALLER_LEN); - dbgobj->caller[BCM_OBJDBG_CALLER_LEN-1] = '\0'; - dbgobj->line = line; - dbgobj->flag = 0; - if (opt == BCM_OBJDBG_ADD_PKT) { - dbgobj->obj_sn = dbgobj_sn++; - dbgobj->obj_state = 0; - /* first 4 bytes is pkt sn */ - if (((unsigned long)PKTTAG(obj)) & 0x3) - DHD_ERROR(("pkt tag address not aligned by 4: %p\n", PKTTAG(obj))); - *(uint32*)PKTTAG(obj) = dbgobj->obj_sn; - } - bcm_object_add_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj, - BCM_OBJDBG_ADDTOTAIL); - - dbgobj_count++; - - } else if (opt == BCM_OBJDBG_REMOVE) { - dbgobj = dbgobj_objtail; - while (dbgobj) { - if (dbgobj->obj == obj) { - if (dbgobj->flag) { - DHD_PRINT(("%s: rm flagged obj %p flag 0x%08x from %s(%d)\n", - __FUNCTION__, obj, dbgobj->flag, caller, line)); - } - bcm_object_rm_list(&dbgobj_objhead, &dbgobj_objtail, dbgobj); - memset(dbgobj->caller, 0x00, BCM_OBJDBG_CALLER_LEN); - strncpy(dbgobj->caller, caller, BCM_OBJDBG_CALLER_LEN); - dbgobj->caller[BCM_OBJDBG_CALLER_LEN-1] = '\0'; - dbgobj->line = line; - bcm_object_add_list(&dbgobj_freehead, &dbgobj_freetail, dbgobj, - BCM_OBJDBG_ADDTOTAIL); - dbgobj_count--; - goto EXIT; - } - dbgobj = dbgobj->prior; - if (dbgobj == dbgobj_objtail) - break; - } - - dbgobj = dbgobj_freetail; - while (dbgobj && dbgobj->obj) { - if (dbgobj->obj == obj) { - DHD_ERROR(("%s: obj %p already freed from from %s(%d)," - " try free again from %s(%d)\n", - __FUNCTION__, obj, - dbgobj->caller, dbgobj->line, - caller, line)); - //ASSERT(0); /* release same obj more than one time? */ - goto EXIT; - } - dbgobj = dbgobj->prior; - if (dbgobj == dbgobj_freetail) - break; - } - - DHD_ERROR(("%s: ################### release none-existing obj %p from %s(%d)\n", - __FUNCTION__, obj, caller, line)); - //ASSERT(0); /* release same obj more than one time? */ - - } - -EXIT: - BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags); - return; -} - -void -bcm_object_trace_upd(void *obj, void *obj_new) -{ - struct bcm_dbgobj *dbgobj; - unsigned long flags; - - BCM_REFERENCE(flags); - BCM_OBJDBG_LOCK(&dbgobj_lock, flags); - - dbgobj = dbgobj_objtail; - while (dbgobj) { - if (dbgobj->obj == obj) { - dbgobj->obj = obj_new; - if (dbgobj != dbgobj_objtail) { - bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail, - dbgobj, BCM_OBJDBG_ADDTOTAIL); - } - goto EXIT; - } - dbgobj = dbgobj->prior; - if (dbgobj == dbgobj_objtail) - break; - } - -EXIT: - BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags); - return; -} - -void -bcm_object_trace_chk(void *obj, uint32 chksn, uint32 sn, - const char *caller, int line) -{ - struct bcm_dbgobj *dbgobj; - unsigned long flags; - - BCM_REFERENCE(flags); - BCM_OBJDBG_LOCK(&dbgobj_lock, flags); - - dbgobj = dbgobj_objtail; - while (dbgobj) { - if ((dbgobj->obj == obj) && - ((!chksn) || (dbgobj->obj_sn == sn))) { - if (dbgobj != dbgobj_objtail) { - bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail, - dbgobj, BCM_OBJDBG_ADDTOTAIL); - } - goto EXIT; - } - dbgobj = dbgobj->prior; - if (dbgobj == dbgobj_objtail) - break; - } - - dbgobj = dbgobj_freetail; - while (dbgobj) { - if ((dbgobj->obj == obj) && - ((!chksn) || (dbgobj->obj_sn == sn))) { - DHD_ERROR(("%s: (%s:%d) obj %p (sn %d state %d) was freed from %s(%d)\n", - __FUNCTION__, caller, line, - dbgobj->obj, dbgobj->obj_sn, dbgobj->obj_state, - dbgobj->caller, dbgobj->line)); - goto EXIT; - } - else if (dbgobj->obj == NULL) { - break; - } - dbgobj = dbgobj->prior; - if (dbgobj == dbgobj_freetail) - break; - } - - DHD_INFO(("%s: obj %p not found, check from %s(%d), chksn %s, sn %d\n", - __FUNCTION__, obj, caller, line, chksn ? "yes" : "no", sn)); - dbgobj = dbgobj_objtail; - while (dbgobj) { - DHD_PRINT(("%s: (%s:%d) obj %p sn %d was allocated from %s(%d)\n", - __FUNCTION__, caller, line, - dbgobj->obj, dbgobj->obj_sn, dbgobj->caller, dbgobj->line)); - dbgobj = dbgobj->prior; - if (dbgobj == dbgobj_objtail) - break; - } - -EXIT: - BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags); - return; -} - -void -bcm_object_feature_set(void *obj, uint32 type, uint32 value) -{ - struct bcm_dbgobj *dbgobj; - unsigned long flags; - - BCM_REFERENCE(flags); - BCM_OBJDBG_LOCK(&dbgobj_lock, flags); - - dbgobj = dbgobj_objtail; - while (dbgobj) { - if (dbgobj->obj == obj) { - if (type == BCM_OBJECT_FEATURE_FLAG) { - if (value & BCM_OBJECT_FEATURE_CLEAR) - dbgobj->flag &= ~(value); - else - dbgobj->flag |= (value); - } else if (type == BCM_OBJECT_FEATURE_PKT_STATE) { - dbgobj->obj_state = value; - } - if (dbgobj != dbgobj_objtail) { - bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail, - dbgobj, BCM_OBJDBG_ADDTOTAIL); - } - goto EXIT; - } - dbgobj = dbgobj->prior; - if (dbgobj == dbgobj_objtail) - break; - } - - DHD_INFO(("%s: obj %p not found in active list\n", __FUNCTION__, obj)); - ASSERT(0); - -EXIT: - BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags); - return; -} - -int -bcm_object_feature_get(void *obj, uint32 type, uint32 value) -{ - int rtn = 0; - struct bcm_dbgobj *dbgobj; - unsigned long flags; - - BCM_REFERENCE(flags); - BCM_OBJDBG_LOCK(&dbgobj_lock, flags); - - dbgobj = dbgobj_objtail; - while (dbgobj) { - if (dbgobj->obj == obj) { - if (type == BCM_OBJECT_FEATURE_FLAG) { - rtn = (dbgobj->flag & value) & (~BCM_OBJECT_FEATURE_CLEAR); - } - if (dbgobj != dbgobj_objtail) { - bcm_object_movetoend(&dbgobj_objhead, &dbgobj_objtail, - dbgobj, BCM_OBJDBG_ADDTOTAIL); - } - goto EXIT; - } - dbgobj = dbgobj->prior; - if (dbgobj == dbgobj_objtail) - break; - } - - DHD_INFO(("%s: obj %p not found in active list\n", __FUNCTION__, obj)); - ASSERT(0); - -EXIT: - BCM_OBJDBG_UNLOCK(&dbgobj_lock, flags); - return rtn; -} - -#endif /* BCM_OBJECT_TRACE */ - -uint8 * -bcm_write_tlv(int type, const void *data, int datalen, uint8 *dst) -{ - uint8 *new_dst = dst; - bcm_tlv_t *dst_tlv = (bcm_tlv_t *)dst; - - /* dst buffer should always be valid */ - ASSERT(dst); - - /* data len must be within valid range */ - ASSERT((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)); - - /* source data buffer pointer should be valid, unless datalen is 0 - * meaning no data with this TLV - */ - ASSERT((data != NULL) || (datalen == 0)); - - /* only do work if the inputs are valid - * - must have a dst to write to AND - * - datalen must be within range AND - * - the source data pointer must be non-NULL if datalen is non-zero - * (this last condition detects datalen > 0 with a NULL data pointer) - */ - if ((dst != NULL) && - ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) && - ((data != NULL) || (datalen == 0))) { - - /* write type, len fields */ - dst_tlv->id = (uint8)type; - dst_tlv->len = (uint8)datalen; - - /* if data is present, copy to the output buffer and update - * pointer to output buffer - */ - if (datalen > 0) { - - memcpy(dst_tlv->data, data, datalen); - } - - /* update the output destination poitner to point past - * the TLV written - */ - new_dst = dst + BCM_TLV_HDR_SIZE + datalen; - } - - return (new_dst); -} - -uint8 * -bcm_write_tlv_safe(int type, const void *data, int datalen, uint8 *dst, int dst_maxlen) -{ - uint8 *new_dst = dst; - - if ((datalen >= 0) && (datalen <= BCM_TLV_MAX_DATA_SIZE)) { - - /* if len + tlv hdr len is more than destlen, don't do anything - * just return the buffer untouched - */ - if ((int)(datalen + BCM_TLV_HDR_SIZE) <= dst_maxlen) { - - new_dst = bcm_write_tlv(type, data, datalen, dst); - } - } - - return (new_dst); -} - -uint8 * -bcm_copy_tlv(const void *src, uint8 *dst) -{ - uint8 *new_dst = dst; - const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src; - uint totlen; - - ASSERT(dst && src); - if (dst && src) { - - totlen = BCM_TLV_HDR_SIZE + src_tlv->len; - memcpy(dst, src_tlv, totlen); - new_dst = dst + totlen; - } - - return (new_dst); -} - - -uint8 *bcm_copy_tlv_safe(const void *src, uint8 *dst, int dst_maxlen) -{ - uint8 *new_dst = dst; - const bcm_tlv_t *src_tlv = (const bcm_tlv_t *)src; - - ASSERT(src); - if (src) { - if (bcm_valid_tlv(src_tlv, dst_maxlen)) { - new_dst = bcm_copy_tlv(src, dst); - } - } - - return (new_dst); -} - - -#if !defined(BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS) -/******************************************************************************* - * crc8 - * - * Computes a crc8 over the input data using the polynomial: - * - * x^8 + x^7 +x^6 + x^4 + x^2 + 1 - * - * The caller provides the initial value (either CRC8_INIT_VALUE - * or the previous returned value) to allow for processing of - * discontiguous blocks of data. When generating the CRC the - * caller is responsible for complementing the final return value - * and inserting it into the byte stream. When checking, a final - * return value of CRC8_GOOD_VALUE indicates a valid CRC. - * - * Reference: Dallas Semiconductor Application Note 27 - * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", - * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., - * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt - * - * **************************************************************************** - */ - -static const uint8 crc8_table[256] = { - 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, - 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, - 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, - 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, - 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, - 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, - 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, - 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, - 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, - 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, - 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, - 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, - 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, - 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, - 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, - 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, - 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, - 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, - 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, - 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, - 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, - 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, - 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, - 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, - 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, - 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, - 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, - 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, - 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, - 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, - 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, - 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F -}; - -#define CRC_INNER_LOOP(n, c, x) \ - (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff] - -uint8 -hndcrc8( - uint8 *pdata, /* pointer to array of data to process */ - uint nbytes, /* number of input data bytes to process */ - uint8 crc /* either CRC8_INIT_VALUE or previous return value */ -) -{ - /* hard code the crc loop instead of using CRC_INNER_LOOP macro - * to avoid the undefined and unnecessary (uint8 >> 8) operation. - */ - while (nbytes-- > 0) - crc = crc8_table[(crc ^ *pdata++) & 0xff]; - - return crc; -} - -/******************************************************************************* - * crc16 - * - * Computes a crc16 over the input data using the polynomial: - * - * x^16 + x^12 +x^5 + 1 - * - * The caller provides the initial value (either CRC16_INIT_VALUE - * or the previous returned value) to allow for processing of - * discontiguous blocks of data. When generating the CRC the - * caller is responsible for complementing the final return value - * and inserting it into the byte stream. When checking, a final - * return value of CRC16_GOOD_VALUE indicates a valid CRC. - * - * Reference: Dallas Semiconductor Application Note 27 - * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms", - * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd., - * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt - * - * **************************************************************************** - */ - -static const uint16 crc16_table[256] = { - 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, - 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, - 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, - 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, - 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, - 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, - 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, - 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, - 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, - 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, - 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, - 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, - 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, - 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, - 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, - 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, - 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, - 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, - 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, - 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, - 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, - 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, - 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, - 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, - 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, - 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, - 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, - 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, - 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, - 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, - 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, - 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 -}; - -uint16 -hndcrc16( - uint8 *pdata, /* pointer to array of data to process */ - uint nbytes, /* number of input data bytes to process */ - uint16 crc /* either CRC16_INIT_VALUE or previous return value */ -) -{ - while (nbytes-- > 0) - CRC_INNER_LOOP(16, crc, *pdata++); - return crc; -} - -static const uint32 crc32_table[256] = { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, - 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, - 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, - 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, - 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, - 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, - 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, - 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, - 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, - 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, - 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, - 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, - 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, - 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, - 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, - 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, - 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, - 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, - 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, - 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, - 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, - 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, - 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, - 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, - 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, - 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, - 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D -}; - -/* - * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if - * accumulating over multiple pieces. - */ -uint32 -hndcrc32(uint8 *pdata, uint nbytes, uint32 crc) -{ - uint8 *pend; - pend = pdata + nbytes; - while (pdata < pend) - CRC_INNER_LOOP(32, crc, *pdata++); - - return crc; -} - -#ifdef notdef -#define CLEN 1499 /* CRC Length */ -#define CBUFSIZ (CLEN+4) -#define CNBUFS 5 /* # of bufs */ - -void -testcrc32(void) -{ - uint j, k, l; - uint8 *buf; - uint len[CNBUFS]; - uint32 crcr; - uint32 crc32tv[CNBUFS] = - {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110}; - - ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL); - - /* step through all possible alignments */ - for (l = 0; l <= 4; l++) { - for (j = 0; j < CNBUFS; j++) { - len[j] = CLEN; - for (k = 0; k < len[j]; k++) - *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff; - } - - for (j = 0; j < CNBUFS; j++) { - crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE); - ASSERT(crcr == crc32tv[j]); - } - } - - MFREE(buf, CBUFSIZ*CNBUFS); - return; -} -#endif /* notdef */ - -/* - * Advance from the current 1-byte tag/1-byte length/variable-length value - * triple, to the next, returning a pointer to the next. - * If the current or next TLV is invalid (does not fit in given buffer length), - * NULL is returned. - * *buflen is not modified if the TLV elt parameter is invalid, or is decremented - * by the TLV parameter's length if it is valid. - */ -bcm_tlv_t * -bcm_next_tlv(bcm_tlv_t *elt, int *buflen) -{ - int len; - - /* validate current elt */ - if (!bcm_valid_tlv(elt, *buflen)) { - return NULL; - } - - /* advance to next elt */ - len = elt->len; - elt = (bcm_tlv_t*)(elt->data + len); - *buflen -= (TLV_HDR_LEN + len); - - /* validate next elt */ - if (!bcm_valid_tlv(elt, *buflen)) { - return NULL; - } - - return elt; -} - -/* - * Traverse a string of 1-byte tag/1-byte length/variable-length value - * triples, returning a pointer to the substring whose first element - * matches tag - */ -bcm_tlv_t * -bcm_parse_tlvs(void *buf, int buflen, uint key) -{ - bcm_tlv_t *elt; - int totlen; - - if ((elt = (bcm_tlv_t*)buf) == NULL) { - return NULL; - } - totlen = buflen; - - /* find tagged parameter */ - while (totlen >= TLV_HDR_LEN) { - int len = elt->len; - - /* validate remaining totlen */ - if ((elt->id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) { - - return (elt); - } - - elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); - totlen -= (len + TLV_HDR_LEN); - } - - return NULL; -} - -bcm_tlv_t * -bcm_parse_tlvs_dot11(void *buf, int buflen, uint key, bool id_ext) -{ - bcm_tlv_t *elt; - int totlen; - - elt = (bcm_tlv_t*)buf; - totlen = buflen; - - /* find tagged parameter */ - while (totlen >= TLV_HDR_LEN) { - int len = elt->len; - - do { - /* validate remaining totlen */ - if (totlen < (int)(len + TLV_HDR_LEN)) - break; - - if (id_ext) { - if (!DOT11_MNG_IE_ID_EXT_MATCH(elt, key)) - break; - } else if (elt->id != key) { - break; - } - - return (elt); - } while (0); - - elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); - totlen -= (len + TLV_HDR_LEN); - } - - return NULL; -} - -/* - * Traverse a string of 1-byte tag/1-byte length/variable-length value - * triples, returning a pointer to the substring whose first element - * matches tag - * return NULL if not found or length field < min_varlen - */ -bcm_tlv_t * -bcm_parse_tlvs_min_bodylen(void *buf, int buflen, uint key, int min_bodylen) -{ - bcm_tlv_t * ret; - ret = bcm_parse_tlvs(buf, buflen, key); - if (ret == NULL || ret->len < min_bodylen) { - return NULL; - } - return ret; -} - -/* - * Traverse a string of 1-byte tag/1-byte length/variable-length value - * triples, returning a pointer to the substring whose first element - * matches tag. Stop parsing when we see an element whose ID is greater - * than the target key. - */ -bcm_tlv_t * -bcm_parse_ordered_tlvs(void *buf, int buflen, uint key) -{ - bcm_tlv_t *elt; - int totlen; - - elt = (bcm_tlv_t*)buf; - totlen = buflen; - - /* find tagged parameter */ - while (totlen >= TLV_HDR_LEN) { - uint id = elt->id; - int len = elt->len; - - /* Punt if we start seeing IDs > than target key */ - if (id > key) { - return (NULL); - } - - /* validate remaining totlen */ - if ((id == key) && (totlen >= (int)(len + TLV_HDR_LEN))) { - return (elt); - } - - elt = (bcm_tlv_t*)((uint8*)elt + (len + TLV_HDR_LEN)); - totlen -= (len + TLV_HDR_LEN); - } - return NULL; -} -#endif /* !BCMROMOFFLOAD_EXCLUDE_BCMUTILS_FUNCS */ - -#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \ - defined(DHD_DEBUG) -int -bcm_format_field(const bcm_bit_desc_ex_t *bd, uint32 flags, char* buf, int len) -{ - int i, slen = 0; - uint32 bit, mask; - const char *name; - mask = bd->mask; - if (len < 2 || !buf) - return 0; - - buf[0] = '\0'; - - for (i = 0; (name = bd->bitfield[i].name) != NULL; i++) { - bit = bd->bitfield[i].bit; - if ((flags & mask) == bit) { - if (len > (int)strlen(name)) { - slen = strlen(name); - strncpy(buf, name, slen+1); - } - break; - } - } - return slen; -} - -int -bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len) -{ - int i; - char* p = buf; - char hexstr[16]; - int slen = 0, nlen = 0; - uint32 bit; - const char* name; - - if (len < 2 || !buf) - return 0; - - buf[0] = '\0'; - - for (i = 0; flags != 0; i++) { - bit = bd[i].bit; - name = bd[i].name; - if (bit == 0 && flags != 0) { - /* print any unnamed bits */ - snprintf(hexstr, 16, "0x%X", flags); - name = hexstr; - flags = 0; /* exit loop */ - } else if ((flags & bit) == 0) - continue; - flags &= ~bit; - nlen = strlen(name); - slen += nlen; - /* count btwn flag space */ - if (flags != 0) - slen += 1; - /* need NULL char as well */ - if (len <= slen) - break; - /* copy NULL char but don't count it */ - strncpy(p, name, nlen + 1); - p += nlen; - /* copy btwn flag space and NULL char */ - if (flags != 0) - p += snprintf(p, 2, " "); - } - - /* indicate the str was too short */ - if (flags != 0) { - p += snprintf(p, 2, ">"); - } - - return (int)(p - buf); -} -#endif - -/* print bytes formatted as hex to a string. return the resulting string length */ -int -bcm_format_hex(char *str, const void *bytes, int len) -{ - int i; - char *p = str; - const uint8 *src = (const uint8*)bytes; - - for (i = 0; i < len; i++) { - p += snprintf(p, 3, "%02X", *src); - src++; - } - return (int)(p - str); -} - -/* pretty hex print a contiguous buffer */ -void -prhex(const char *msg, volatile uchar *buf, uint nbytes) -{ - char line[128], *p; - int len = sizeof(line); - int nchar; - uint i; - - if (msg && (msg[0] != '\0')) - DHD_PRINT(("%s:\n", msg)); - - p = line; - for (i = 0; i < nbytes; i++) { - if (i % 16 == 0) { - nchar = snprintf(p, len, " %04x: ", i); /* line prefix */ - p += nchar; - len -= nchar; - } - if (len > 0) { - nchar = snprintf(p, len, "%02x ", buf[i]); - p += nchar; - len -= nchar; - } - - if (i % 16 == 15) { - DHD_PRINT(("%s\n", line)); /* flush line */ - p = line; - len = sizeof(line); - } - } - - /* flush last partial line */ - if (p != line) - DHD_PRINT(("%s\n", line)); -} - -static const char *crypto_algo_names[] = { - "NONE", - "WEP1", - "TKIP", - "WEP128", - "AES_CCM", - "AES_OCB_MSDU", - "AES_OCB_MPDU", - "NALG", - "UNDEF", - "UNDEF", - "UNDEF", - "UNDEF" - "PMK", - "BIP", - "AES_GCM", - "AES_CCM256", - "AES_GCM256", - "BIP_CMAC256", - "BIP_GMAC", - "BIP_GMAC256", - "UNDEF" -}; - -const char * -bcm_crypto_algo_name(uint algo) -{ - return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR"; -} - - -char * -bcm_chipname(uint chipid, char *buf, uint len) -{ - const char *fmt; - - fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; - snprintf(buf, len, fmt, chipid); - return buf; -} - -/* Produce a human-readable string for boardrev */ -char * -bcm_brev_str(uint32 brev, char *buf) -{ - if (brev < 0x100) - snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf); - else - snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff); - - return (buf); -} - -#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */ - -/* dump large strings to console */ -void -printbig(char *buf) -{ - uint len, max_len; - char c; - - len = (uint)strlen(buf); - - max_len = BUFSIZE_TODUMP_ATONCE; - - while (len > max_len) { - c = buf[max_len]; - buf[max_len] = '\0'; - DHD_PRINT(("%s", buf)); - buf[max_len] = c; - - buf += max_len; - len -= max_len; - } - /* print the remaining string */ - DHD_PRINT(("%s\n", buf)); - return; -} - -/* routine to dump fields in a fileddesc structure */ -uint -bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array, - char *buf, uint32 bufsize) -{ - uint filled_len; - int len; - struct fielddesc *cur_ptr; - - filled_len = 0; - cur_ptr = fielddesc_array; - - while (bufsize > 1) { - if (cur_ptr->nameandfmt == NULL) - break; - len = snprintf(buf, bufsize, cur_ptr->nameandfmt, - read_rtn(arg0, arg1, cur_ptr->offset)); - /* check for snprintf overflow or error */ - if (len < 0 || (uint32)len >= bufsize) - len = bufsize - 1; - buf += len; - bufsize -= len; - filled_len += len; - cur_ptr++; - } - return filled_len; -} - -uint -bcm_mkiovar(const char *name, const char *data, uint datalen, char *buf, uint buflen) -{ - uint len; - - len = (uint)strlen(name) + 1; - - if ((len + datalen) > buflen) - return 0; - - strncpy(buf, name, buflen); - - /* append data onto the end of the name string */ - if (data && datalen != 0) { - memcpy(&buf[len], data, datalen); - len += datalen; - } - - return len; -} - -/* Quarter dBm units to mW - * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153 - * Table is offset so the last entry is largest mW value that fits in - * a uint16. - */ - -#define QDBM_OFFSET 153 /* Offset for first entry */ -#define QDBM_TABLE_LEN 40 /* Table size */ - -/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET. - * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2 - */ -#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */ - -/* Largest mW value that will round down to the last table entry, - * QDBM_OFFSET + QDBM_TABLE_LEN-1. - * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2. - */ -#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */ - -static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = { -/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */ -/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000, -/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849, -/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119, -/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811, -/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096 -}; - -uint16 -bcm_qdbm_to_mw(uint8 qdbm) -{ - uint factor = 1; - int idx = qdbm - QDBM_OFFSET; - - if (idx >= QDBM_TABLE_LEN) { - /* clamp to max uint16 mW value */ - return 0xFFFF; - } - - /* scale the qdBm index up to the range of the table 0-40 - * where an offset of 40 qdBm equals a factor of 10 mW. - */ - while (idx < 0) { - idx += 40; - factor *= 10; - } - - /* return the mW value scaled down to the correct factor of 10, - * adding in factor/2 to get proper rounding. - */ - return ((nqdBm_to_mW_map[idx] + factor/2) / factor); -} - -uint8 -bcm_mw_to_qdbm(uint16 mw) -{ - uint8 qdbm; - int offset; - uint mw_uint = mw; - uint boundary; - - /* handle boundary case */ - if (mw_uint <= 1) - return 0; - - offset = QDBM_OFFSET; - - /* move mw into the range of the table */ - while (mw_uint < QDBM_TABLE_LOW_BOUND) { - mw_uint *= 10; - offset -= 40; - } - - for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) { - boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] - - nqdBm_to_mW_map[qdbm])/2; - if (mw_uint < boundary) break; - } - - qdbm += (uint8)offset; - - return (qdbm); -} - - -uint -bcm_bitcount(uint8 *bitmap, uint length) -{ - uint bitcount = 0, i; - uint8 tmp; - for (i = 0; i < length; i++) { - tmp = bitmap[i]; - while (tmp) { - bitcount++; - tmp &= (tmp - 1); - } - } - return bitcount; -} - -#if defined(BCMDRIVER) || defined(WL_UNITTEST) - -/* triggers bcm_bprintf to print to kernel log */ -bool bcm_bprintf_bypass = FALSE; - -/* Initialization of bcmstrbuf structure */ -void -bcm_binit(struct bcmstrbuf *b, char *buf, uint size) -{ - b->origsize = b->size = size; - b->origbuf = b->buf = buf; -} - -/* Buffer sprintf wrapper to guard against buffer overflow */ -int -bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...) -{ - va_list ap; - int r; - - va_start(ap, fmt); - - r = vsnprintf(b->buf, b->size, fmt, ap); - if (bcm_bprintf_bypass == TRUE) { - DHD_PRINT(("%s", b->buf)); - goto exit; - } - - /* Non Ansi C99 compliant returns -1, - * Ansi compliant return r >= b->size, - * bcmstdlib returns 0, handle all - */ - /* r == 0 is also the case when strlen(fmt) is zero. - * typically the case when "" is passed as argument. - */ - if ((r == -1) || (r >= (int)b->size)) { - b->size = 0; - } else { - b->size -= r; - b->buf += r; - } - -exit: - va_end(ap); - - return r; -} - -void -bcm_bprhex(struct bcmstrbuf *b, const char *msg, bool newline, const uint8 *buf, int len) -{ - int i; - - if (msg != NULL && msg[0] != '\0') - bcm_bprintf(b, "%s", msg); - for (i = 0; i < len; i ++) - bcm_bprintf(b, "%02X", buf[i]); - if (newline) - bcm_bprintf(b, "\n"); -} - -void -bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount) -{ - int i; - - for (i = 0; i < num_bytes; i++) { - num[i] += amount; - if (num[i] >= amount) - break; - amount = 1; - } -} - -int -bcm_cmp_bytes(const uchar *arg1, const uchar *arg2, uint8 nbytes) -{ - int i; - - for (i = nbytes - 1; i >= 0; i--) { - if (arg1[i] != arg2[i]) - return (arg1[i] - arg2[i]); - } - return 0; -} - -void -bcm_print_bytes(const char *name, const uchar *data, int len) -{ - int i; - int per_line = 0; - - DHD_PRINT(("%s: %d \n", name ? name : "", len)); - for (i = 0; i < len; i++) { - DHD_PRINT(("%02x ", *data++)); - per_line++; - if (per_line == 16) { - per_line = 0; - DHD_PRINT(("\n")); - } - } - DHD_PRINT(("\n")); -} - -/* Look for vendor-specific IE with specified OUI and optional type */ -bcm_tlv_t * -bcm_find_vendor_ie(void *tlvs, int tlvs_len, const char *voui, uint8 *type, int type_len) -{ - bcm_tlv_t *ie; - uint8 ie_len; - - ie = (bcm_tlv_t*)tlvs; - - /* make sure we are looking at a valid IE */ - if (ie == NULL || !bcm_valid_tlv(ie, tlvs_len)) { - return NULL; - } - - /* Walk through the IEs looking for an OUI match */ - do { - ie_len = ie->len; - if ((ie->id == DOT11_MNG_PROPR_ID) && - (ie_len >= (DOT11_OUI_LEN + type_len)) && - !bcmp(ie->data, voui, DOT11_OUI_LEN)) - { - /* compare optional type */ - if (type_len == 0 || - !bcmp(&ie->data[DOT11_OUI_LEN], type, type_len)) { - return (ie); /* a match */ - } - } - } while ((ie = bcm_next_tlv(ie, &tlvs_len)) != NULL); - - return NULL; -} - -#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1) - -int -bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len) -{ - uint i, c; - char *p = buf; - char *endp = buf + SSID_FMT_BUF_LEN; - - if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN; - - for (i = 0; i < ssid_len; i++) { - c = (uint)ssid[i]; - if (c == '\\') { - *p++ = '\\'; - *p++ = '\\'; - } else if (bcm_isprint((uchar)c)) { - *p++ = (char)c; - } else { - p += snprintf(p, (endp - p), "\\x%02X", c); - } - } - *p = '\0'; - ASSERT(p < endp); - - return (int)(p - buf); -} - -#endif /* BCMDRIVER || WL_UNITTEST */ - -/* - * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL. - * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0 - * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs. - * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs. -*/ - -unsigned int -process_nvram_vars(char *varbuf, unsigned int len) -{ - char *dp; - bool findNewline; - int column; - unsigned int buf_len, n; - unsigned int pad = 0; - char nv_ver[128]; - - dp = varbuf; - - findNewline = FALSE; - column = 0; - - // terence 20130914: print out NVRAM version - if (varbuf[0] == '#') { - memset(nv_ver, 0x00, sizeof(nv_ver)); - for (n=1; n<len && n<(sizeof(nv_ver)-1); n++) { - if (varbuf[n] == '\n') - break; - nv_ver[n-1] = varbuf[n]; - } - printk("NVRAM version: %s\n", nv_ver); - } - - for (n = 0; n < len; n++) { - if (varbuf[n] == '\r') - continue; - if (findNewline && varbuf[n] != '\n') - continue; - findNewline = FALSE; - if (varbuf[n] == '#') { - findNewline = TRUE; - continue; - } - if (varbuf[n] == '\n') { - if (column == 0) - continue; - *dp++ = 0; - column = 0; - continue; - } - *dp++ = varbuf[n]; - column++; - } - buf_len = (unsigned int)(dp - varbuf); - if (buf_len % 4) { - pad = 4 - buf_len % 4; - if (pad && (buf_len + pad <= len)) { - buf_len += pad; - } - } - - while (dp < varbuf + n) - *dp++ = 0; - - return buf_len; -} - -/* calculate a * b + c */ -void -bcm_uint64_multiple_add(uint32* r_high, uint32* r_low, uint32 a, uint32 b, uint32 c) -{ -#define FORMALIZE(var) {cc += (var & 0x80000000) ? 1 : 0; var &= 0x7fffffff;} - uint32 r1, r0; - uint32 a1, a0, b1, b0, t, cc = 0; - - a1 = a >> 16; - a0 = a & 0xffff; - b1 = b >> 16; - b0 = b & 0xffff; - - r0 = a0 * b0; - FORMALIZE(r0); - - t = (a1 * b0) << 16; - FORMALIZE(t); - - r0 += t; - FORMALIZE(r0); - - t = (a0 * b1) << 16; - FORMALIZE(t); - - r0 += t; - FORMALIZE(r0); - - FORMALIZE(c); - - r0 += c; - FORMALIZE(r0); - - r0 |= (cc % 2) ? 0x80000000 : 0; - r1 = a1 * b1 + ((a1 * b0) >> 16) + ((b1 * a0) >> 16) + (cc / 2); - - *r_high = r1; - *r_low = r0; -} - -/* calculate a / b */ -void -bcm_uint64_divide(uint32* r, uint32 a_high, uint32 a_low, uint32 b) -{ - uint32 a1 = a_high, a0 = a_low, r0 = 0; - - if (b < 2) - return; - - while (a1 != 0) { - r0 += (0xffffffff / b) * a1; - bcm_uint64_multiple_add(&a1, &a0, ((0xffffffff % b) + 1) % b, a1, a0); - } - - r0 += a0 / b; - *r = r0; -} - -#ifndef setbit /* As in the header file */ -#ifdef BCMUTILS_BIT_MACROS_USE_FUNCS -/* Set bit in byte array. */ -void -setbit(void *array, uint bit) -{ - ((uint8 *)array)[bit / NBBY] |= 1 << (bit % NBBY); -} - -/* Clear bit in byte array. */ -void -clrbit(void *array, uint bit) -{ - ((uint8 *)array)[bit / NBBY] &= ~(1 << (bit % NBBY)); -} - -/* Test if bit is set in byte array. */ -bool -isset(const void *array, uint bit) -{ - return (((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))); -} - -/* Test if bit is clear in byte array. */ -bool -isclr(const void *array, uint bit) -{ - return ((((const uint8 *)array)[bit / NBBY] & (1 << (bit % NBBY))) == 0); -} -#endif /* BCMUTILS_BIT_MACROS_USE_FUNCS */ -#endif /* setbit */ - -void -set_bitrange(void *array, uint start, uint end, uint maxbit) -{ - uint startbyte = start/NBBY; - uint endbyte = end/NBBY; - uint i, startbytelastbit, endbytestartbit; - - if (end >= start) { - if (endbyte - startbyte > 1) - { - startbytelastbit = (startbyte+1)*NBBY - 1; - endbytestartbit = endbyte*NBBY; - for (i = startbyte+1; i < endbyte; i++) - ((uint8 *)array)[i] = 0xFF; - for (i = start; i <= startbytelastbit; i++) - setbit(array, i); - for (i = endbytestartbit; i <= end; i++) - setbit(array, i); - } else { - for (i = start; i <= end; i++) - setbit(array, i); - } - } - else { - set_bitrange(array, start, maxbit, maxbit); - set_bitrange(array, 0, end, maxbit); - } -} - -void -bcm_bitprint32(const uint32 u32arg) -{ - int i; - for (i = NBITS(uint32) - 1; i >= 0; i--) { - if (isbitset(u32arg, i)) { - DHD_PRINT(("1")); - } else { - DHD_PRINT(("0")); - } - - if ((i % NBBY) == 0) DHD_PRINT((" ")); - } - DHD_PRINT(("\n")); -} - -/* calculate checksum for ip header, tcp / udp header / data */ -uint16 -bcm_ip_cksum(uint8 *buf, uint32 len, uint32 sum) -{ - while (len > 1) { - sum += (buf[0] << 8) | buf[1]; - buf += 2; - len -= 2; - } - - if (len > 0) { - sum += (*buf) << 8; - } - - while (sum >> 16) { - sum = (sum & 0xffff) + (sum >> 16); - } - - return ((uint16)~sum); -} -#if defined(BCMDRIVER) && !defined(_CFEZ_) -/* - * Hierarchical Multiword bitmap based small id allocator. - * - * Multilevel hierarchy bitmap. (maximum 2 levels) - * First hierarchy uses a multiword bitmap to identify 32bit words in the - * second hierarchy that have at least a single bit set. Each bit in a word of - * the second hierarchy represents a unique ID that may be allocated. - * - * BCM_MWBMAP_ITEMS_MAX: Maximum number of IDs managed. - * BCM_MWBMAP_BITS_WORD: Number of bits in a bitmap word word - * BCM_MWBMAP_WORDS_MAX: Maximum number of bitmap words needed for free IDs. - * BCM_MWBMAP_WDMAP_MAX: Maximum number of bitmap wordss identifying first non - * non-zero bitmap word carrying at least one free ID. - * BCM_MWBMAP_SHIFT_OP: Used in MOD, DIV and MUL operations. - * BCM_MWBMAP_INVALID_IDX: Value ~0U is treated as an invalid ID - * - * Design Notes: - * BCM_MWBMAP_USE_CNTSETBITS trades CPU for memory. A runtime count of how many - * bits are computed each time on allocation and deallocation, requiring 4 - * array indexed access and 3 arithmetic operations. When not defined, a runtime - * count of set bits state is maintained. Upto 32 Bytes per 1024 IDs is needed. - * In a 4K max ID allocator, up to 128Bytes are hence used per instantiation. - * In a memory limited system e.g. dongle builds, a CPU for memory tradeoff may - * be used by defining BCM_MWBMAP_USE_CNTSETBITS. - * - * Note: wd_bitmap[] is statically declared and is not ROM friendly ... array - * size is fixed. No intention to support larger than 4K indice allocation. ID - * allocators for ranges smaller than 4K will have a wastage of only 12Bytes - * with savings in not having to use an indirect access, had it been dynamically - * allocated. - */ -#define BCM_MWBMAP_ITEMS_MAX (64 * 1024) /* May increase to 64K */ - -#define BCM_MWBMAP_BITS_WORD (NBITS(uint32)) -#define BCM_MWBMAP_WORDS_MAX (BCM_MWBMAP_ITEMS_MAX / BCM_MWBMAP_BITS_WORD) -#define BCM_MWBMAP_WDMAP_MAX (BCM_MWBMAP_WORDS_MAX / BCM_MWBMAP_BITS_WORD) -#define BCM_MWBMAP_SHIFT_OP (5) -#define BCM_MWBMAP_MODOP(ix) ((ix) & (BCM_MWBMAP_BITS_WORD - 1)) -#define BCM_MWBMAP_DIVOP(ix) ((ix) >> BCM_MWBMAP_SHIFT_OP) -#define BCM_MWBMAP_MULOP(ix) ((ix) << BCM_MWBMAP_SHIFT_OP) - -/* Redefine PTR() and/or HDL() conversion to invoke audit for debugging */ -#define BCM_MWBMAP_PTR(hdl) ((struct bcm_mwbmap *)(hdl)) -#define BCM_MWBMAP_HDL(ptr) ((void *)(ptr)) - -#if defined(BCM_MWBMAP_DEBUG) -#define BCM_MWBMAP_AUDIT(mwb) \ - do { \ - ASSERT((mwb != NULL) && \ - (((struct bcm_mwbmap *)(mwb))->magic == (void *)(mwb))); \ - bcm_mwbmap_audit(mwb); \ - } while (0) -#define MWBMAP_ASSERT(exp) ASSERT(exp) -#define MWBMAP_DBG(x) printf x -#else /* !BCM_MWBMAP_DEBUG */ -#define BCM_MWBMAP_AUDIT(mwb) do {} while (0) -#define MWBMAP_ASSERT(exp) do {} while (0) -#define MWBMAP_DBG(x) -#endif /* !BCM_MWBMAP_DEBUG */ - - -typedef struct bcm_mwbmap { /* Hierarchical multiword bitmap allocator */ - uint16 wmaps; /* Total number of words in free wd bitmap */ - uint16 imaps; /* Total number of words in free id bitmap */ - int32 ifree; /* Count of free indices. Used only in audits */ - uint16 total; /* Total indices managed by multiword bitmap */ - - void * magic; /* Audit handle parameter from user */ - - uint32 wd_bitmap[BCM_MWBMAP_WDMAP_MAX]; /* 1st level bitmap of */ -#if !defined(BCM_MWBMAP_USE_CNTSETBITS) - int8 wd_count[BCM_MWBMAP_WORDS_MAX]; /* free id running count, 1st lvl */ -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - - uint32 id_bitmap[0]; /* Second level bitmap */ -} bcm_mwbmap_t; - -/* Incarnate a hierarchical multiword bitmap based small index allocator. */ -struct bcm_mwbmap * -bcm_mwbmap_init(osl_t *osh, uint32 items_max) -{ - struct bcm_mwbmap * mwbmap_p; - uint32 wordix, size, words, extra; - - /* Implementation Constraint: Uses 32bit word bitmap */ - MWBMAP_ASSERT(BCM_MWBMAP_BITS_WORD == 32U); - MWBMAP_ASSERT(BCM_MWBMAP_SHIFT_OP == 5U); - MWBMAP_ASSERT(ISPOWEROF2(BCM_MWBMAP_ITEMS_MAX)); - MWBMAP_ASSERT((BCM_MWBMAP_ITEMS_MAX % BCM_MWBMAP_BITS_WORD) == 0U); - - ASSERT(items_max <= BCM_MWBMAP_ITEMS_MAX); - - /* Determine the number of words needed in the multiword bitmap */ - extra = BCM_MWBMAP_MODOP(items_max); - words = BCM_MWBMAP_DIVOP(items_max) + ((extra != 0U) ? 1U : 0U); - - /* Allocate runtime state of multiword bitmap */ - /* Note: wd_count[] or wd_bitmap[] are not dynamically allocated */ - size = sizeof(bcm_mwbmap_t) + (sizeof(uint32) * words); - mwbmap_p = (bcm_mwbmap_t *)MALLOC(osh, size); - if (mwbmap_p == (bcm_mwbmap_t *)NULL) { - ASSERT(0); - goto error1; - } - memset(mwbmap_p, 0, size); - - /* Initialize runtime multiword bitmap state */ - mwbmap_p->imaps = (uint16)words; - mwbmap_p->ifree = (int32)items_max; - mwbmap_p->total = (uint16)items_max; - - /* Setup magic, for use in audit of handle */ - mwbmap_p->magic = BCM_MWBMAP_HDL(mwbmap_p); - - /* Setup the second level bitmap of free indices */ - /* Mark all indices as available */ - for (wordix = 0U; wordix < mwbmap_p->imaps; wordix++) { - mwbmap_p->id_bitmap[wordix] = (uint32)(~0U); -#if !defined(BCM_MWBMAP_USE_CNTSETBITS) - mwbmap_p->wd_count[wordix] = BCM_MWBMAP_BITS_WORD; -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - } - - /* Ensure that extra indices are tagged as un-available */ - if (extra) { /* fixup the free ids in last bitmap and wd_count */ - uint32 * bmap_p = &mwbmap_p->id_bitmap[mwbmap_p->imaps - 1]; - *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ -#if !defined(BCM_MWBMAP_USE_CNTSETBITS) - mwbmap_p->wd_count[mwbmap_p->imaps - 1] = (int8)extra; /* fixup count */ -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - } - - /* Setup the first level bitmap hierarchy */ - extra = BCM_MWBMAP_MODOP(mwbmap_p->imaps); - words = BCM_MWBMAP_DIVOP(mwbmap_p->imaps) + ((extra != 0U) ? 1U : 0U); - - mwbmap_p->wmaps = (uint16)words; - - for (wordix = 0U; wordix < mwbmap_p->wmaps; wordix++) - mwbmap_p->wd_bitmap[wordix] = (uint32)(~0U); - if (extra) { - uint32 * bmap_p = &mwbmap_p->wd_bitmap[mwbmap_p->wmaps - 1]; - *bmap_p ^= (uint32)(~0U << extra); /* fixup bitmap */ - } - - return mwbmap_p; - -error1: - return BCM_MWBMAP_INVALID_HDL; -} - -/* Release resources used by multiword bitmap based small index allocator. */ -void -bcm_mwbmap_fini(osl_t * osh, struct bcm_mwbmap * mwbmap_hdl) -{ - bcm_mwbmap_t * mwbmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - MFREE(osh, mwbmap_p, sizeof(struct bcm_mwbmap) - + (sizeof(uint32) * mwbmap_p->imaps)); - return; -} - -/* Allocate a unique small index using a multiword bitmap index allocator. */ -uint32 BCMFASTPATH -bcm_mwbmap_alloc(struct bcm_mwbmap * mwbmap_hdl) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 wordix, bitmap; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - /* Start with the first hierarchy */ - for (wordix = 0; wordix < mwbmap_p->wmaps; ++wordix) { - - bitmap = mwbmap_p->wd_bitmap[wordix]; /* get the word bitmap */ - - if (bitmap != 0U) { - - uint32 count, bitix, *bitmap_p; - - bitmap_p = &mwbmap_p->wd_bitmap[wordix]; - - /* clear all except trailing 1 */ - bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); - MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == - bcm_count_leading_zeros(bitmap)); - bitix = (BCM_MWBMAP_BITS_WORD - 1) - - bcm_count_leading_zeros(bitmap); /* use asm clz */ - wordix = BCM_MWBMAP_MULOP(wordix) + bitix; - - /* Clear bit if wd count is 0, without conditional branch */ -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1; -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - mwbmap_p->wd_count[wordix]--; - count = mwbmap_p->wd_count[wordix]; - MWBMAP_ASSERT(count == - (bcm_cntsetbits(mwbmap_p->id_bitmap[wordix]) - 1)); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - MWBMAP_ASSERT(count >= 0); - - /* clear wd_bitmap bit if id_map count is 0 */ - bitmap = (count == 0) << bitix; - - MWBMAP_DBG(( - "Lvl1: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x wfree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, count)); - - *bitmap_p ^= bitmap; - - /* Use bitix in the second hierarchy */ - bitmap_p = &mwbmap_p->id_bitmap[wordix]; - - bitmap = mwbmap_p->id_bitmap[wordix]; /* get the id bitmap */ - MWBMAP_ASSERT(bitmap != 0U); - - /* clear all except trailing 1 */ - bitmap = (uint32)(((int)(bitmap)) & (-((int)(bitmap)))); - MWBMAP_ASSERT(C_bcm_count_leading_zeros(bitmap) == - bcm_count_leading_zeros(bitmap)); - bitix = BCM_MWBMAP_MULOP(wordix) - + (BCM_MWBMAP_BITS_WORD - 1) - - bcm_count_leading_zeros(bitmap); /* use asm clz */ - - mwbmap_p->ifree--; /* decrement system wide free count */ - MWBMAP_ASSERT(mwbmap_p->ifree >= 0); - - MWBMAP_DBG(( - "Lvl2: bitix<%02u> wordix<%02u>: %08x ^ %08x = %08x ifree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, - mwbmap_p->ifree)); - - *bitmap_p ^= bitmap; /* mark as allocated = 1b0 */ - - return bitix; - } - } - - ASSERT(mwbmap_p->ifree == 0); - - return BCM_MWBMAP_INVALID_IDX; -} - -/* Force an index at a specified position to be in use */ -void -bcm_mwbmap_force(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 count, wordix, bitmap, *bitmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - ASSERT(bitix < mwbmap_p->total); - - /* Start with second hierarchy */ - wordix = BCM_MWBMAP_DIVOP(bitix); - bitmap = (uint32)(1U << BCM_MWBMAP_MODOP(bitix)); - bitmap_p = &mwbmap_p->id_bitmap[wordix]; - - ASSERT((*bitmap_p & bitmap) == bitmap); - - mwbmap_p->ifree--; /* update free count */ - ASSERT(mwbmap_p->ifree >= 0); - - MWBMAP_DBG(("Lvl2: bitix<%u> wordix<%u>: %08x ^ %08x = %08x ifree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) ^ bitmap, - mwbmap_p->ifree)); - - *bitmap_p ^= bitmap; /* mark as in use */ - - /* Update first hierarchy */ - bitix = wordix; - - wordix = BCM_MWBMAP_DIVOP(bitix); - bitmap_p = &mwbmap_p->wd_bitmap[wordix]; - -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - mwbmap_p->wd_count[bitix]--; - count = mwbmap_p->wd_count[bitix]; - MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - MWBMAP_ASSERT(count >= 0); - - bitmap = (count == 0) << BCM_MWBMAP_MODOP(bitix); - - MWBMAP_DBG(("Lvl1: bitix<%02lu> wordix<%02u>: %08x ^ %08x = %08x wfree %d", - BCM_MWBMAP_MODOP(bitix), wordix, *bitmap_p, bitmap, - (*bitmap_p) ^ bitmap, count)); - - *bitmap_p ^= bitmap; /* mark as in use */ - - return; -} - -/* Free a previously allocated index back into the multiword bitmap allocator */ -void BCMFASTPATH -bcm_mwbmap_free(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 wordix, bitmap, *bitmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - ASSERT(bitix < mwbmap_p->total); - - /* Start with second level hierarchy */ - wordix = BCM_MWBMAP_DIVOP(bitix); - bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); - bitmap_p = &mwbmap_p->id_bitmap[wordix]; - - ASSERT((*bitmap_p & bitmap) == 0U); /* ASSERT not a double free */ - - mwbmap_p->ifree++; /* update free count */ - ASSERT(mwbmap_p->ifree <= mwbmap_p->total); - - MWBMAP_DBG(("Lvl2: bitix<%02u> wordix<%02u>: %08x | %08x = %08x ifree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, - mwbmap_p->ifree)); - - *bitmap_p |= bitmap; /* mark as available */ - - /* Now update first level hierarchy */ - - bitix = wordix; - - wordix = BCM_MWBMAP_DIVOP(bitix); /* first level's word index */ - bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); - bitmap_p = &mwbmap_p->wd_bitmap[wordix]; - -#if !defined(BCM_MWBMAP_USE_CNTSETBITS) - mwbmap_p->wd_count[bitix]++; -#endif - -#if defined(BCM_MWBMAP_DEBUG) - { - uint32 count; -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[bitix]); -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - count = mwbmap_p->wd_count[bitix]; - MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[bitix])); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - - MWBMAP_ASSERT(count <= BCM_MWBMAP_BITS_WORD); - - MWBMAP_DBG(("Lvl1: bitix<%02u> wordix<%02u>: %08x | %08x = %08x wfree %d", - bitix, wordix, *bitmap_p, bitmap, (*bitmap_p) | bitmap, count)); - } -#endif /* BCM_MWBMAP_DEBUG */ - - *bitmap_p |= bitmap; - - return; -} - -/* Fetch the toal number of free indices in the multiword bitmap allocator */ -uint32 -bcm_mwbmap_free_cnt(struct bcm_mwbmap * mwbmap_hdl) -{ - bcm_mwbmap_t * mwbmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - ASSERT(mwbmap_p->ifree >= 0); - - return mwbmap_p->ifree; -} - -/* Determine whether an index is inuse or free */ -bool -bcm_mwbmap_isfree(struct bcm_mwbmap * mwbmap_hdl, uint32 bitix) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 wordix, bitmap; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - ASSERT(bitix < mwbmap_p->total); - - wordix = BCM_MWBMAP_DIVOP(bitix); - bitmap = (1U << BCM_MWBMAP_MODOP(bitix)); - - return ((mwbmap_p->id_bitmap[wordix] & bitmap) != 0U); -} - -/* Debug dump a multiword bitmap allocator */ -void -bcm_mwbmap_show(struct bcm_mwbmap * mwbmap_hdl) -{ - uint32 ix, count; - bcm_mwbmap_t * mwbmap_p; - - BCM_MWBMAP_AUDIT(mwbmap_hdl); - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - DHD_PRINT(("mwbmap_p %p wmaps %u imaps %u ifree %d total %u\n", mwbmap_p, - mwbmap_p->wmaps, mwbmap_p->imaps, mwbmap_p->ifree, mwbmap_p->total)); - for (ix = 0U; ix < mwbmap_p->wmaps; ix++) { - DHD_PRINT(("\tWDMAP:%2u. 0x%08x\t", ix, mwbmap_p->wd_bitmap[ix])); - bcm_bitprint32(mwbmap_p->wd_bitmap[ix]); - DHD_PRINT(("\n")); - } - for (ix = 0U; ix < mwbmap_p->imaps; ix++) { -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[ix]); -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - count = mwbmap_p->wd_count[ix]; - MWBMAP_ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[ix])); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - DHD_PRINT(("\tIDMAP:%2u. 0x%08x %02u\t", ix, mwbmap_p->id_bitmap[ix], count)); - bcm_bitprint32(mwbmap_p->id_bitmap[ix]); - DHD_PRINT(("\n")); - } - - return; -} - -/* Audit a hierarchical multiword bitmap */ -void -bcm_mwbmap_audit(struct bcm_mwbmap * mwbmap_hdl) -{ - bcm_mwbmap_t * mwbmap_p; - uint32 count, free_cnt = 0U, wordix, idmap_ix, bitix, *bitmap_p; - - mwbmap_p = BCM_MWBMAP_PTR(mwbmap_hdl); - - for (wordix = 0U; wordix < mwbmap_p->wmaps; ++wordix) { - - bitmap_p = &mwbmap_p->wd_bitmap[wordix]; - - for (bitix = 0U; bitix < BCM_MWBMAP_BITS_WORD; bitix++) { - if ((*bitmap_p) & (1 << bitix)) { - idmap_ix = BCM_MWBMAP_MULOP(wordix) + bitix; -#if defined(BCM_MWBMAP_USE_CNTSETBITS) - count = bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix]); -#else /* ! BCM_MWBMAP_USE_CNTSETBITS */ - count = mwbmap_p->wd_count[idmap_ix]; - ASSERT(count == bcm_cntsetbits(mwbmap_p->id_bitmap[idmap_ix])); -#endif /* ! BCM_MWBMAP_USE_CNTSETBITS */ - ASSERT(count != 0U); - free_cnt += count; - } - } - } - - ASSERT((int)free_cnt == mwbmap_p->ifree); -} -/* END : Multiword bitmap based 64bit to Unique 32bit Id allocator. */ - -/* Simple 16bit Id allocator using a stack implementation. */ -typedef struct id16_map { - uint32 failures; /* count of failures */ - void *dbg; /* debug placeholder */ - uint16 total; /* total number of ids managed by allocator */ - uint16 start; /* start value of 16bit ids to be managed */ - int stack_idx; /* index into stack of available ids */ - uint16 stack[0]; /* stack of 16 bit ids */ -} id16_map_t; - -#define ID16_MAP_SZ(items) (sizeof(id16_map_t) + \ - (sizeof(uint16) * (items))) - -#if defined(BCM_DBG) - -/* Uncomment BCM_DBG_ID16 to debug double free */ -/* #define BCM_DBG_ID16 */ - -typedef struct id16_map_dbg { - uint16 total; - bool avail[0]; -} id16_map_dbg_t; -#define ID16_MAP_DBG_SZ(items) (sizeof(id16_map_dbg_t) + \ - (sizeof(bool) * (items))) -#define ID16_MAP_MSG(x) print x -#else -#define ID16_MAP_MSG(x) -#endif /* BCM_DBG */ - -void * /* Construct an id16 allocator: [start_val16 .. start_val16+total_ids) */ -id16_map_init(osl_t *osh, uint16 total_ids, uint16 start_val16) -{ - uint16 idx, val16; - id16_map_t * id16_map; - - ASSERT(total_ids > 0); - - /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map - * with random values. - */ - ASSERT((start_val16 == ID16_UNDEFINED) || - (start_val16 + total_ids) < ID16_INVALID); - - id16_map = (id16_map_t *) MALLOC(osh, ID16_MAP_SZ(total_ids)); - if (id16_map == NULL) { - return NULL; - } - - id16_map->total = total_ids; - id16_map->start = start_val16; - id16_map->failures = 0; - id16_map->dbg = NULL; - - /* - * Populate stack with 16bit id values, commencing with start_val16. - * if start_val16 is ID16_UNDEFINED, then do not populate the id16 map. - */ - id16_map->stack_idx = -1; - - if (id16_map->start != ID16_UNDEFINED) { - val16 = start_val16; - - for (idx = 0; idx < total_ids; idx++, val16++) { - id16_map->stack_idx = idx; - id16_map->stack[id16_map->stack_idx] = val16; - } - } - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - if (id16_map->start != ID16_UNDEFINED) { - id16_map->dbg = MALLOC(osh, ID16_MAP_DBG_SZ(total_ids)); - - if (id16_map->dbg) { - id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; - - id16_map_dbg->total = total_ids; - for (idx = 0; idx < total_ids; idx++) { - id16_map_dbg->avail[idx] = TRUE; - } - } - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - - return (void *)id16_map; -} - -void * /* Destruct an id16 allocator instance */ -id16_map_fini(osl_t *osh, void * id16_map_hndl) -{ - uint16 total_ids; - id16_map_t * id16_map; - - if (id16_map_hndl == NULL) - return NULL; - - id16_map = (id16_map_t *)id16_map_hndl; - - total_ids = id16_map->total; - ASSERT(total_ids > 0); - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - if (id16_map->dbg) { - MFREE(osh, id16_map->dbg, ID16_MAP_DBG_SZ(total_ids)); - id16_map->dbg = NULL; - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - - id16_map->total = 0; - MFREE(osh, id16_map, ID16_MAP_SZ(total_ids)); - - return NULL; -} - -void -id16_map_clear(void * id16_map_hndl, uint16 total_ids, uint16 start_val16) -{ - uint16 idx, val16; - id16_map_t * id16_map; - - ASSERT(total_ids > 0); - /* A start_val16 of ID16_UNDEFINED, allows the caller to fill the id16 map - * with random values. - */ - ASSERT((start_val16 == ID16_UNDEFINED) || - (start_val16 + total_ids) < ID16_INVALID); - - id16_map = (id16_map_t *)id16_map_hndl; - if (id16_map == NULL) { - return; - } - - id16_map->total = total_ids; - id16_map->start = start_val16; - id16_map->failures = 0; - - /* Populate stack with 16bit id values, commencing with start_val16 */ - id16_map->stack_idx = -1; - - if (id16_map->start != ID16_UNDEFINED) { - val16 = start_val16; - - for (idx = 0; idx < total_ids; idx++, val16++) { - id16_map->stack_idx = idx; - id16_map->stack[id16_map->stack_idx] = val16; - } - } - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - if (id16_map->start != ID16_UNDEFINED) { - if (id16_map->dbg) { - id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; - - id16_map_dbg->total = total_ids; - for (idx = 0; idx < total_ids; idx++) { - id16_map_dbg->avail[idx] = TRUE; - } - } - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ -} - -uint16 BCMFASTPATH /* Allocate a unique 16bit id */ -id16_map_alloc(void * id16_map_hndl) -{ - uint16 val16; - id16_map_t * id16_map; - - ASSERT(id16_map_hndl != NULL); - - id16_map = (id16_map_t *)id16_map_hndl; - - ASSERT(id16_map->total > 0); - - if (id16_map->stack_idx < 0) { - id16_map->failures++; - return ID16_INVALID; - } - - val16 = id16_map->stack[id16_map->stack_idx]; - id16_map->stack_idx--; - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - ASSERT((id16_map->start == ID16_UNDEFINED) || - (val16 < (id16_map->start + id16_map->total))); - - if (id16_map->dbg) { /* Validate val16 */ - id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; - - ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == TRUE); - id16_map_dbg->avail[val16 - id16_map->start] = FALSE; - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - - return val16; -} - - -void BCMFASTPATH /* Free a 16bit id value into the id16 allocator */ -id16_map_free(void * id16_map_hndl, uint16 val16) -{ - id16_map_t * id16_map; - - ASSERT(id16_map_hndl != NULL); - - id16_map = (id16_map_t *)id16_map_hndl; - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - ASSERT((id16_map->start == ID16_UNDEFINED) || - (val16 < (id16_map->start + id16_map->total))); - - if (id16_map->dbg) { /* Validate val16 */ - id16_map_dbg_t *id16_map_dbg = (id16_map_dbg_t *)id16_map->dbg; - - ASSERT(id16_map_dbg->avail[val16 - id16_map->start] == FALSE); - id16_map_dbg->avail[val16 - id16_map->start] = TRUE; - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - - id16_map->stack_idx++; - id16_map->stack[id16_map->stack_idx] = val16; -} - -uint32 /* Returns number of failures to allocate an unique id16 */ -id16_map_failures(void * id16_map_hndl) -{ - ASSERT(id16_map_hndl != NULL); - return ((id16_map_t *)id16_map_hndl)->failures; -} - -bool -id16_map_audit(void * id16_map_hndl) -{ - int idx; - int insane = 0; - id16_map_t * id16_map; - - ASSERT(id16_map_hndl != NULL); - - id16_map = (id16_map_t *)id16_map_hndl; - - ASSERT(id16_map->stack_idx >= -1); - ASSERT(id16_map->stack_idx < (int)id16_map->total); - - if (id16_map->start == ID16_UNDEFINED) - goto done; - - for (idx = 0; idx <= id16_map->stack_idx; idx++) { - ASSERT(id16_map->stack[idx] >= id16_map->start); - ASSERT(id16_map->stack[idx] < (id16_map->start + id16_map->total)); - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - if (id16_map->dbg) { - uint16 val16 = id16_map->stack[idx]; - if (((id16_map_dbg_t *)(id16_map->dbg))->avail[val16] != TRUE) { - insane |= 1; - ID16_MAP_MSG(("id16_map<%p>: stack_idx %u invalid val16 %u\n", - id16_map_hndl, idx, val16)); - } - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - } - -#if defined(BCM_DBG) && defined(BCM_DBG_ID16) - if (id16_map->dbg) { - uint16 avail = 0; /* Audit available ids counts */ - for (idx = 0; idx < id16_map_dbg->total; idx++) { - if (((id16_map_dbg_t *)(id16_map->dbg))->avail[idx16] == TRUE) - avail++; - } - if (avail && (avail != (id16_map->stack_idx + 1))) { - insane |= 1; - ID16_MAP_MSG(("id16_map<%p>: avail %u stack_idx %u\n", - id16_map_hndl, avail, id16_map->stack_idx)); - } - } -#endif /* BCM_DBG && BCM_DBG_ID16 */ - -done: - /* invoke any other system audits */ - return (!!insane); -} -/* END: Simple id16 allocator */ - - -#endif - -/* calculate a >> b; and returns only lower 32 bits */ -void -bcm_uint64_right_shift(uint32* r, uint32 a_high, uint32 a_low, uint32 b) -{ - uint32 a1 = a_high, a0 = a_low, r0 = 0; - - if (b == 0) { - r0 = a_low; - *r = r0; - return; - } - - if (b < 32) { - a0 = a0 >> b; - a1 = a1 & ((1 << b) - 1); - a1 = a1 << (32 - b); - r0 = a0 | a1; - *r = r0; - return; - } else { - r0 = a1 >> (b - 32); - *r = r0; - return; - } - -} - -/* calculate a + b where a is a 64 bit number and b is a 32 bit number */ -void -bcm_add_64(uint32* r_hi, uint32* r_lo, uint32 offset) -{ - uint32 r1_lo = *r_lo; - (*r_lo) += offset; - if (*r_lo < r1_lo) - (*r_hi) ++; -} - -/* calculate a - b where a is a 64 bit number and b is a 32 bit number */ -void -bcm_sub_64(uint32* r_hi, uint32* r_lo, uint32 offset) -{ - uint32 r1_lo = *r_lo; - (*r_lo) -= offset; - if (*r_lo > r1_lo) - (*r_hi) --; -} - -/* Does unsigned 64 bit fixed point multiplication */ -uint64 -fp_mult_64(uint64 val1, uint64 val2, uint8 nf1, uint8 nf2, uint8 nf_res) -{ - uint64 mult_out_tmp, mult_out, rnd_val; - uint8 shift_amt; - - shift_amt = nf1 + nf2 - nf_res; - /* 0.5 in 1.0.shift_amt */ - rnd_val = bcm_shl_64(1, (shift_amt - 1)); - rnd_val = (shift_amt == 0) ? 0 : rnd_val; - mult_out_tmp = (uint64)((uint64)val1 * (uint64)val2) + (uint64)rnd_val; - mult_out = bcm_shr_64(mult_out_tmp, shift_amt); - - return mult_out; -} - - -/* Does unsigned 64 bit by 32 bit fixed point division */ -uint8 -fp_div_64(uint64 num, uint32 den, uint8 nf_num, uint8 nf_den, uint32 *div_out) -{ - uint8 shift_amt1, shift_amt2, shift_amt, nf_res, hd_rm_nr, hd_rm_dr; - uint32 num_hi, num_lo; - uint64 num_scale; - - /* Worst case shift possible */ - hd_rm_nr = fp_calc_head_room_64(num); - hd_rm_dr = fp_calc_head_room_32(den); - - /* (Nr / Dr) <= 2^32 */ - shift_amt1 = hd_rm_nr - hd_rm_dr - 1; - /* Shift <= 32 + N2 - N1 */ - shift_amt2 = 31 + nf_den - nf_num; - shift_amt = MINIMUM(shift_amt1, shift_amt2); - - /* Scale numerator */ - num_scale = bcm_shl_64(num, shift_amt); - - /* Do division */ - num_hi = (uint32)((uint64)num_scale >> 32) & MASK_32_BITS; - num_lo = (uint32)(num_scale & MASK_32_BITS); - bcm_uint64_divide(div_out, num_hi, num_lo, den); - - /* Result format */ - nf_res = nf_num - nf_den + shift_amt; - return nf_res; -} - -/* Finds the number of bits available for shifting in unsigned 64 bit number */ -uint8 -fp_calc_head_room_64(uint64 num) -{ - uint8 n_room_bits = 0, msb_pos; - uint32 num_hi, num_lo, x; - - num_hi = (uint32)((uint64)num >> 32) & MASK_32_BITS; - num_lo = (uint32)(num & MASK_32_BITS); - - if (num_hi > 0) { - x = num_hi; - n_room_bits = 0; - } else { - x = num_lo; - n_room_bits = 32; - } - - msb_pos = (x >> 16) ? ((x >> 24) ? (24 + msb_table[(x >> 24) & MASK_8_BITS]) - : (16 + msb_table[(x >> 16) & MASK_8_BITS])) - : ((x >> 8) ? (8 + msb_table[(x >> 8) & MASK_8_BITS]) - : msb_table[x & MASK_8_BITS]); - - return (n_room_bits + 32 - msb_pos); -} - -/* Finds the number of bits available for shifting in unsigned 32 bit number */ -uint8 -fp_calc_head_room_32(uint32 x) -{ - uint8 msb_pos; - - msb_pos = (x >> 16) ? ((x >> 24) ? (24 + msb_table[(x >> 24) & MASK_8_BITS]) - : (16 + msb_table[(x >> 16) & MASK_8_BITS])) - : ((x >> 8) ? (8 + msb_table[(x >> 8) & MASK_8_BITS]) - : msb_table[x & MASK_8_BITS]); - - return (32 - msb_pos); -} - -/* Does unsigned 64 bit fixed point floor */ -uint32 -fp_floor_64(uint64 num, uint8 floor_pos) -{ - uint32 floor_out; - - floor_out = (uint32)bcm_shr_64(num, floor_pos); - - return floor_out; -} - -/* Does unsigned 32 bit fixed point floor */ -uint32 -fp_floor_32(uint32 num, uint8 floor_pos) -{ - return num >> floor_pos; -} - -/* Does unsigned 64 bit fixed point rounding */ -uint32 -fp_round_64(uint64 num, uint8 rnd_pos) -{ - uint64 rnd_val, rnd_out_tmp; - uint32 rnd_out; - - /* 0.5 in 1.0.rnd_pos */ - rnd_val = bcm_shl_64(1, (rnd_pos - 1)); - rnd_val = (rnd_pos == 0) ? 0 : rnd_val; - rnd_out_tmp = num + rnd_val; - rnd_out = (uint32)bcm_shr_64(rnd_out_tmp, rnd_pos); - - return rnd_out; -} - -/* Does unsigned 32 bit fixed point rounding */ -uint32 -fp_round_32(uint32 num, uint8 rnd_pos) -{ - uint32 rnd_val, rnd_out_tmp; - - /* 0.5 in 1.0.rnd_pos */ - rnd_val = 1 << (rnd_pos - 1); - rnd_val = (rnd_pos == 0) ? 0 : rnd_val; - rnd_out_tmp = num + rnd_val; - return (rnd_out_tmp >> rnd_pos); -} - -/* Does unsigned fixed point ceiling */ -uint32 -fp_ceil_64(uint64 num, uint8 ceil_pos) -{ - uint64 ceil_val, ceil_out_tmp; - uint32 ceil_out; - - /* 0.999 in 1.0.rnd_pos */ - ceil_val = bcm_shl_64(1, ceil_pos) - 1; - ceil_out_tmp = num + ceil_val; - ceil_out = (uint32)bcm_shr_64(ceil_out_tmp, ceil_pos); - - return ceil_out; -} - -/* Does left shift of unsigned 64 bit number */ -uint64 -bcm_shl_64(uint64 input, uint8 shift_amt) -{ - uint32 in_hi, in_lo; - uint32 masked_lo = 0; - uint32 mask; - uint64 shl_out; - - if (shift_amt == 0) { - return input; - } - - /* Get hi and lo part */ - in_hi = (uint32)((uint64)input >> 32) & MASK_32_BITS; - in_lo = (uint32)(input & MASK_32_BITS); - - if (shift_amt < 32) { - /* Extract bit which belongs to hi part after shifting */ - mask = ((uint32)~0) << (32 - shift_amt); - masked_lo = (in_lo & mask) >> (32 - shift_amt); - - /* Shift hi and lo and prepare output */ - in_hi = (in_hi << shift_amt) | masked_lo; - in_lo = in_lo << shift_amt; - } else { - /* Extract bit which belongs to hi part after shifting */ - shift_amt = shift_amt - 32; - - /* Shift hi and lo and prepare output */ - in_hi = in_lo << shift_amt; - in_lo = 0; - } - - shl_out = (((uint64)in_hi << 32) | in_lo); - return shl_out; -} - -/* Does right shift of unsigned 64 bit number */ -uint64 -bcm_shr_64(uint64 input, uint8 shift_amt) -{ - uint32 in_hi, in_lo; - uint32 masked_hi = 0; - uint32 mask; - uint64 shr_out; - - if (shift_amt == 0) { - return input; - } - - /* Get hi and lo part */ - in_hi = (uint32)((uint64)input >> 32) & MASK_32_BITS; - in_lo = (uint32)(input & MASK_32_BITS); - - if (shift_amt < 32) { - /* Extract bit which belongs to lo part after shifting */ - mask = (1 << shift_amt) - 1; - masked_hi = in_hi & mask; - - /* Shift hi and lo and prepare output */ - in_hi = (uint32)in_hi >> shift_amt; - in_lo = ((uint32)in_lo >> shift_amt) | (masked_hi << (32 - shift_amt)); - } else { - shift_amt = shift_amt - 32; - in_lo = in_hi >> shift_amt; - in_hi = 0; - } - - shr_out = (((uint64)in_hi << 32) | in_lo); - return shr_out; -} - -#ifdef DEBUG_COUNTER -#if (OSL_SYSUPTIME_SUPPORT == TRUE) -void counter_printlog(counter_tbl_t *ctr_tbl) -{ - uint32 now; - - if (!ctr_tbl->enabled) - return; - - now = OSL_SYSUPTIME(); - - if (now - ctr_tbl->prev_log_print > ctr_tbl->log_print_interval) { - uint8 i = 0; - DHD_PRINT(("counter_print(%s %d):", ctr_tbl->name, now - ctr_tbl->prev_log_print)); - - for (i = 0; i < ctr_tbl->needed_cnt; i++) { - DHD_PRINT((" %u", ctr_tbl->cnt[i])); - } - DHD_PRINT(("\n")); - - ctr_tbl->prev_log_print = now; - bzero(ctr_tbl->cnt, CNTR_TBL_MAX * sizeof(uint)); - } -} -#else -/* OSL_SYSUPTIME is not supported so no way to get time */ -#define counter_printlog(a) do {} while (0) -#endif /* OSL_SYSUPTIME_SUPPORT == TRUE */ -#endif /* DEBUG_COUNTER */ - -#if defined(BCMDRIVER) && !defined(_CFEZ_) -void -dll_pool_detach(void * osh, dll_pool_t * pool, uint16 elems_max, uint16 elem_size) -{ - uint32 mem_size; - mem_size = sizeof(dll_pool_t) + (elems_max * elem_size); - if (pool) - MFREE(osh, pool, mem_size); -} -dll_pool_t * -dll_pool_init(void * osh, uint16 elems_max, uint16 elem_size) -{ - uint32 mem_size, i; - dll_pool_t * dll_pool_p; - dll_t * elem_p; - - ASSERT(elem_size > sizeof(dll_t)); - - mem_size = sizeof(dll_pool_t) + (elems_max * elem_size); - - if ((dll_pool_p = (dll_pool_t *)MALLOCZ(osh, mem_size)) == NULL) { - DHD_ERROR(("dll_pool_init: elems_max<%u> elem_size<%u> malloc failure\n", - elems_max, elem_size)); - ASSERT(0); - return dll_pool_p; - } - - dll_init(&dll_pool_p->free_list); - dll_pool_p->elems_max = elems_max; - dll_pool_p->elem_size = elem_size; - - elem_p = dll_pool_p->elements; - for (i = 0; i < elems_max; i++) { - dll_append(&dll_pool_p->free_list, elem_p); - elem_p = (dll_t *)((uintptr)elem_p + elem_size); - } - - dll_pool_p->free_count = elems_max; - - return dll_pool_p; -} - - -void * -dll_pool_alloc(dll_pool_t * dll_pool_p) -{ - dll_t * elem_p; - - if (dll_pool_p->free_count == 0) { - ASSERT(dll_empty(&dll_pool_p->free_list)); - return NULL; - } - - elem_p = dll_head_p(&dll_pool_p->free_list); - dll_delete(elem_p); - dll_pool_p->free_count -= 1; - - return (void *)elem_p; -} - -void -dll_pool_free(dll_pool_t * dll_pool_p, void * elem_p) -{ - dll_t * node_p = (dll_t *)elem_p; - dll_prepend(&dll_pool_p->free_list, node_p); - dll_pool_p->free_count += 1; -} - - -void -dll_pool_free_tail(dll_pool_t * dll_pool_p, void * elem_p) -{ - dll_t * node_p = (dll_t *)elem_p; - dll_append(&dll_pool_p->free_list, node_p); - dll_pool_p->free_count += 1; -} - -#endif - -/* calculate partial checksum */ -static uint32 -ip_cksum_partial(uint32 sum, uint8 *val8, uint32 count) -{ - uint32 i; - uint16 *val16 = (uint16 *)val8; - - ASSERT(val8 != NULL); - /* partial chksum calculated on 16-bit values */ - ASSERT((count % 2) == 0); - - count /= 2; - - for (i = 0; i < count; i++) { - sum += *val16++; - } - return sum; -} - -/* calculate IP checksum */ -static uint16 -ip_cksum(uint32 sum, uint8 *val8, uint32 count) -{ - uint16 *val16 = (uint16 *)val8; - - ASSERT(val8 != NULL); - - while (count > 1) { - sum += *val16++; - count -= 2; - } - /* add left-over byte, if any */ - if (count > 0) { - sum += (*(uint8 *)val16); - } - - /* fold 32-bit sum to 16 bits */ - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - return ((uint16)~sum); -} - -/* calculate IPv4 header checksum - * - input ip points to IP header in network order - * - output cksum is in network order - */ -uint16 -ipv4_hdr_cksum(uint8 *ip, int ip_len) -{ - uint32 sum = 0; - uint8 *ptr = ip; - - ASSERT(ip != NULL); - ASSERT(ip_len >= IPV4_MIN_HEADER_LEN); - - /* partial cksum skipping the hdr_chksum field */ - sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct ipv4_hdr, hdr_chksum)); - ptr += OFFSETOF(struct ipv4_hdr, hdr_chksum) + 2; - - /* return calculated chksum */ - return ip_cksum(sum, ptr, ip_len - OFFSETOF(struct ipv4_hdr, src_ip)); -} - -/* calculate TCP header checksum using partial sum */ -static uint16 -tcp_hdr_chksum(uint32 sum, uint8 *tcp_hdr, uint16 tcp_len) -{ - uint8 *ptr = tcp_hdr; - - ASSERT(tcp_hdr != NULL); - ASSERT(tcp_len >= TCP_MIN_HEADER_LEN); - - /* partial TCP cksum skipping the chksum field */ - sum = ip_cksum_partial(sum, ptr, OFFSETOF(struct bcmtcp_hdr, chksum)); - ptr += OFFSETOF(struct bcmtcp_hdr, chksum) + 2; - - /* return calculated chksum */ - return ip_cksum(sum, ptr, tcp_len - OFFSETOF(struct bcmtcp_hdr, urg_ptr)); -} - -struct tcp_pseudo_hdr { - uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */ - uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */ - uint8 zero; - uint8 prot; - uint16 tcp_size; -}; - -/* calculate IPv4 TCP header checksum - * - input ip and tcp points to IP and TCP header in network order - * - output cksum is in network order - */ -uint16 -ipv4_tcp_hdr_cksum(uint8 *ip, uint8 *tcp, uint16 tcp_len) -{ - struct ipv4_hdr *ip_hdr = (struct ipv4_hdr *)ip; - struct tcp_pseudo_hdr tcp_ps; - uint32 sum = 0; - - ASSERT(ip != NULL); - ASSERT(tcp != NULL); - ASSERT(tcp_len >= TCP_MIN_HEADER_LEN); - - /* pseudo header cksum */ - memset(&tcp_ps, 0, sizeof(tcp_ps)); - memcpy(&tcp_ps.dst_ip, ip_hdr->dst_ip, IPV4_ADDR_LEN); - memcpy(&tcp_ps.src_ip, ip_hdr->src_ip, IPV4_ADDR_LEN); - tcp_ps.zero = 0; - tcp_ps.prot = ip_hdr->prot; - tcp_ps.tcp_size = hton16(tcp_len); - sum = ip_cksum_partial(sum, (uint8 *)&tcp_ps, sizeof(tcp_ps)); - - /* return calculated TCP header chksum */ - return tcp_hdr_chksum(sum, tcp, tcp_len); -} - -struct ipv6_pseudo_hdr { - uint8 saddr[IPV6_ADDR_LEN]; - uint8 daddr[IPV6_ADDR_LEN]; - uint16 payload_len; - uint8 zero; - uint8 next_hdr; -}; - -/* calculate IPv6 TCP header checksum - * - input ipv6 and tcp points to IPv6 and TCP header in network order - * - output cksum is in network order - */ -uint16 -ipv6_tcp_hdr_cksum(uint8 *ipv6, uint8 *tcp, uint16 tcp_len) -{ - struct ipv6_hdr *ipv6_hdr = (struct ipv6_hdr *)ipv6; - struct ipv6_pseudo_hdr ipv6_pseudo; - uint32 sum = 0; - - ASSERT(ipv6 != NULL); - ASSERT(tcp != NULL); - ASSERT(tcp_len >= TCP_MIN_HEADER_LEN); - - /* pseudo header cksum */ - memset((char *)&ipv6_pseudo, 0, sizeof(ipv6_pseudo)); - memcpy((char *)ipv6_pseudo.saddr, (char *)ipv6_hdr->saddr.addr, - sizeof(ipv6_pseudo.saddr)); - memcpy((char *)ipv6_pseudo.daddr, (char *)ipv6_hdr->daddr.addr, - sizeof(ipv6_pseudo.daddr)); - ipv6_pseudo.payload_len = ipv6_hdr->payload_len; - ipv6_pseudo.next_hdr = ipv6_hdr->nexthdr; - sum = ip_cksum_partial(sum, (uint8 *)&ipv6_pseudo, sizeof(ipv6_pseudo)); - - /* return calculated TCP header chksum */ - return tcp_hdr_chksum(sum, tcp, tcp_len); -} - -#ifdef SIMPLE_MAC_PRINT -#define MAC_PATTERN_1 "**:XX:XX:XX:**:**" -#define MAC_PATTERN_2 " **XXXXXX****" -#define MAC_PATTERN_3 ":**XXXXXX****" - -static int check_pattern(char *target, int tlen, char *pattern, int plen) -{ - int i = 0; - - if (tlen < plen) - return 0; - - /* make sure target matches pattern */ - for (i = 0; i < plen; i++) { - if ((pattern[i] == '*') || - (pattern[i] == 'X')) { - if (!bcm_isxdigit(target[i])) - return 0; - } else if (bcm_tolower(target[i]) != bcm_tolower(pattern[i])) { - if (pattern[i] == ' ') { - if (target[i] != '\t') - return 0; - } else - return 0; - } - } - - /* WAR corner case */ - if (tlen > plen) - if (bcm_isalnum(target[plen])) - return 0; - - /* Apply pattern */ - for (i = 0; i < plen; i++) { - if (pattern[i] == 'X') - target[i] = 'X'; - else if (bcm_isalpha(target[i])) - target[i] = bcm_tolower(target[i]); - } - return plen-1; -} - -void hide_mac_detail(const char *str, uint len) { - int i, tlen, ret; - for (i = 0; (i < len); i++) { - char *target = (char *)str + i; - tlen = len - i; - ret = check_pattern(target, tlen, MAC_PATTERN_1, strlen(MAC_PATTERN_1)); - if (!ret) { - ret = check_pattern(target, tlen, MAC_PATTERN_2, strlen(MAC_PATTERN_2)); - } - if (!ret) { - ret = check_pattern(target, tlen, MAC_PATTERN_3, strlen(MAC_PATTERN_3)); - } - i = i + ret; // skip the handled MAC */ - } -} -#endif /* SIMPLE_MAC_PRINT */
diff --git a/bcmdhd.1.579.77.41.x/bcmwifi_channels.c b/bcmdhd.1.579.77.41.x/bcmwifi_channels.c deleted file mode 100644 index 40fc3f7..0000000 --- a/bcmdhd.1.579.77.41.x/bcmwifi_channels.c +++ /dev/null
@@ -1,1349 +0,0 @@ -/* - * Misc utility routines used by kernel or app-level. - * Contents are wifi-specific, used by any kernel or app-level - * software that might want wifi things as it grows. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * 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.c 612483 2016-01-14 03:44:27Z $ - */ - -#include <bcm_cfg.h> -#include <typedefs.h> -#include <bcmutils.h> - -#ifdef BCMDRIVER -#include <osl.h> -#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) -#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c)) -#else -#include <stdio.h> -#include <stdlib.h> -#include <ctype.h> -#ifndef ASSERT -#define ASSERT(exp) -#endif -#endif /* BCMDRIVER */ - -#include <bcmwifi_channels.h> - -#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL)) -#include <bcmstdlib.h> /* For wl/exe/GNUmakefile.brcm_wlu and GNUmakefile.wlm_dll */ -#endif - -/* Definitions for D11AC capable Chanspec type */ - -/* Chanspec ASCII representation with 802.11ac capability: - * [<band> 'g'] <channel> ['/'<bandwidth> [<ctl-sideband>]['/'<1st80channel>'-'<2nd80channel>]] - * - * <band>: - * (optional) 2, 3, 4, 5 for 2.4GHz, 3GHz, 4GHz, and 5GHz respectively. - * Default value is 2g if channel <= 14, otherwise 5g. - * <channel>: - * channel number of the 5MHz, 10MHz, 20MHz channel, - * or primary channel of 40MHz, 80MHz, 160MHz, or 80+80MHz channel. - * <bandwidth>: - * (optional) 5, 10, 20, 40, 80, 160, or 80+80. Default value is 20. - * <primary-sideband>: - * (only for 2.4GHz band 40MHz) U for upper sideband primary, L for lower. - * - * For 2.4GHz band 40MHz channels, the same primary channel may be the - * upper sideband for one 40MHz channel, and the lower sideband for an - * overlapping 40MHz channel. The U/L disambiguates which 40MHz channel - * is being specified. - * - * For 40MHz in the 5GHz band and all channel bandwidths greater than - * 40MHz, the U/L specificaion is not allowed since the channels are - * non-overlapping and the primary sub-band is derived from its - * position in the wide bandwidth channel. - * - * <1st80Channel>: - * <2nd80Channel>: - * Required for 80+80, otherwise not allowed. - * Specifies the center channel of the first and second 80MHz band. - * - * In its simplest form, it is a 20MHz channel number, with the implied band - * of 2.4GHz if channel number <= 14, and 5GHz otherwise. - * - * To allow for backward compatibility with scripts, the old form for - * 40MHz channels is also allowed: <channel><ctl-sideband> - * - * <channel>: - * primary channel of 40MHz, channel <= 14 is 2GHz, otherwise 5GHz - * <ctl-sideband>: - * "U" for upper, "L" for lower (or lower case "u" "l") - * - * 5 GHz Examples: - * Chanspec BW Center Ch Channel Range Primary Ch - * 5g8 20MHz 8 - - - * 52 20MHz 52 - - - * 52/40 40MHz 54 52-56 52 - * 56/40 40MHz 54 52-56 56 - * 52/80 80MHz 58 52-64 52 - * 56/80 80MHz 58 52-64 56 - * 60/80 80MHz 58 52-64 60 - * 64/80 80MHz 58 52-64 64 - * 52/160 160MHz 50 36-64 52 - * 36/160 160MGz 50 36-64 36 - * 36/80+80/42-106 80+80MHz 42,106 36-48,100-112 36 - * - * 2 GHz Examples: - * Chanspec BW Center Ch Channel Range Primary Ch - * 2g8 20MHz 8 - - - * 8 20MHz 8 - - - * 6 20MHz 6 - - - * 6/40l 40MHz 8 6-10 6 - * 6l 40MHz 8 6-10 6 - * 6/40u 40MHz 4 2-6 6 - * 6u 40MHz 4 2-6 6 - */ - -/* bandwidth ASCII string */ -static const char *wf_chspec_bw_str[] = -{ - "5", - "10", - "20", - "40", - "80", - "160", - "80+80", -#ifdef WL11ULB - "2.5" -#else /* WL11ULB */ - "na" -#endif /* WL11ULB */ -}; - -static const uint8 wf_chspec_bw_mhz[] = -{5, 10, 20, 40, 80, 160, 160}; - -#define WF_NUM_BW \ - (sizeof(wf_chspec_bw_mhz)/sizeof(uint8)) - -/* 40MHz channels in 5GHz band */ -static const uint8 wf_5g_40m_chans[] = -{38, 46, 54, 62, 102, 110, 118, 126, 134, 142, 151, 159}; -#define WF_NUM_5G_40M_CHANS \ - (sizeof(wf_5g_40m_chans)/sizeof(uint8)) - -/* 80MHz channels in 5GHz band */ -static const uint8 wf_5g_80m_chans[] = -{42, 58, 106, 122, 138, 155}; -#define WF_NUM_5G_80M_CHANS \ - (sizeof(wf_5g_80m_chans)/sizeof(uint8)) - -/* 160MHz channels in 5GHz band */ -static const uint8 wf_5g_160m_chans[] = -{50, 114}; -#define WF_NUM_5G_160M_CHANS \ - (sizeof(wf_5g_160m_chans)/sizeof(uint8)) - -/* opclass and channel information for US. Table E-1 */ -static const uint16 opclass_data[] = { - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_3G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_5)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_10)&WL_CHANSPEC_BW_MASK)), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_20)&WL_CHANSPEC_BW_MASK)), - 0, - 0, - 0, - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), - (WL_CHANSPEC_BAND_5G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), - (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_LOWER), - (WL_CHANSPEC_BAND_2G |((WL_CHANSPEC_BW_40)&WL_CHANSPEC_BW_MASK)|WL_CHANSPEC_CTL_SB_UPPER), -}; - -/* convert bandwidth from chanspec to MHz */ -static uint -bw_chspec_to_mhz(chanspec_t chspec) -{ - uint bw; - - bw = (chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT; - return (bw >= WF_NUM_BW ? 0 : wf_chspec_bw_mhz[bw]); -} - -/* bw in MHz, return the channel count from the center channel to the - * the channel at the edge of the band - */ -static uint8 -center_chan_to_edge(uint bw) -{ - /* edge channels separated by BW - 10MHz on each side - * delta from cf to edge is half of that, - * MHz to channel num conversion is 5MHz/channel - */ - return (uint8)(((bw - 20) / 2) / 5); -} - -/* return channel number of the low edge of the band - * given the center channel and BW - */ -static uint8 -channel_low_edge(uint center_ch, uint bw) -{ - return (uint8)(center_ch - center_chan_to_edge(bw)); -} - -/* return side band number given center channel and control channel - * return -1 on error - */ -static int -channel_to_sb(uint center_ch, uint ctl_ch, uint bw) -{ - uint lowest = channel_low_edge(center_ch, bw); - uint sb; - - if ((ctl_ch - lowest) % 4) { - /* bad ctl channel, not mult 4 */ - return -1; - } - - sb = ((ctl_ch - lowest) / 4); - - /* sb must be a index to a 20MHz channel in range */ - if (sb >= (bw / 20)) { - /* ctl_ch must have been too high for the center_ch */ - return -1; - } - - return sb; -} - -/* return control channel given center channel and side band */ -static uint8 -channel_to_ctl_chan(uint center_ch, uint bw, uint sb) -{ - return (uint8)(channel_low_edge(center_ch, bw) + sb * 4); -} - -/* return index of 80MHz channel from channel number - * return -1 on error - */ -static int -channel_80mhz_to_id(uint ch) -{ - uint i; - for (i = 0; i < WF_NUM_5G_80M_CHANS; i ++) { - if (ch == wf_5g_80m_chans[i]) - return i; - } - - return -1; -} - -/* wrapper function for wf_chspec_ntoa. In case of an error it puts - * the original chanspec in the output buffer, prepended with "invalid". - * Can be directly used in print routines as it takes care of null - */ -char * -wf_chspec_ntoa_ex(chanspec_t chspec, char *buf) -{ - if (wf_chspec_ntoa(chspec, buf) == NULL) - snprintf(buf, CHANSPEC_STR_LEN, "invalid 0x%04x", chspec); - return buf; -} - -/* given a chanspec and a string buffer, format the chanspec as a - * string, and return the original pointer a. - * Min buffer length must be CHANSPEC_STR_LEN. - * On error return NULL - */ -char * -wf_chspec_ntoa(chanspec_t chspec, char *buf) -{ - const char *band; - uint ctl_chan; - - if (wf_chspec_malformed(chspec)) - return NULL; - - band = ""; - - /* check for non-default band spec */ - if ((CHSPEC_IS2G(chspec) && CHSPEC_CHANNEL(chspec) > CH_MAX_2G_CHANNEL) || - (CHSPEC_IS5G(chspec) && CHSPEC_CHANNEL(chspec) <= CH_MAX_2G_CHANNEL)) - band = (CHSPEC_IS2G(chspec)) ? "2g" : "5g"; - - /* ctl channel */ - ctl_chan = wf_chspec_ctlchan(chspec); - - /* bandwidth and ctl sideband */ - if (CHSPEC_IS20(chspec)) { - snprintf(buf, CHANSPEC_STR_LEN, "%s%d", band, ctl_chan); - } else if (!CHSPEC_IS8080(chspec)) { - const char *bw; - const char *sb = ""; - - bw = wf_chspec_bw_str[(chspec & WL_CHANSPEC_BW_MASK) >> WL_CHANSPEC_BW_SHIFT]; - -#ifdef CHANSPEC_NEW_40MHZ_FORMAT - /* ctl sideband string if needed for 2g 40MHz */ - if (CHSPEC_IS40(chspec) && CHSPEC_IS2G(chspec)) { - sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; - } - - snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s%s", band, ctl_chan, bw, sb); -#else - /* ctl sideband string instead of BW for 40MHz */ - if (CHSPEC_IS40(chspec)) { - sb = CHSPEC_SB_UPPER(chspec) ? "u" : "l"; - snprintf(buf, CHANSPEC_STR_LEN, "%s%d%s", band, ctl_chan, sb); - } else { - snprintf(buf, CHANSPEC_STR_LEN, "%s%d/%s", band, ctl_chan, bw); - } -#endif /* CHANSPEC_NEW_40MHZ_FORMAT */ - - } else { - /* 80+80 */ - uint chan1 = (chspec & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT; - uint chan2 = (chspec & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT; - - /* convert to channel number */ - chan1 = (chan1 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan1] : 0; - chan2 = (chan2 < WF_NUM_5G_80M_CHANS) ? wf_5g_80m_chans[chan2] : 0; - - /* Outputs a max of CHANSPEC_STR_LEN chars including '\0' */ - snprintf(buf, CHANSPEC_STR_LEN, "%d/80+80/%d-%d", ctl_chan, chan1, chan2); - } - - return (buf); -} - -static int -read_uint(const char **p, unsigned int *num) -{ - unsigned long val; - char *endp = NULL; - - val = strtoul(*p, &endp, 10); - /* if endp is the initial pointer value, then a number was not read */ - if (endp == *p) - return 0; - - /* advance the buffer pointer to the end of the integer string */ - *p = endp; - /* return the parsed integer */ - *num = (unsigned int)val; - - return 1; -} - -/* given a chanspec string, convert to a chanspec. - * On error return 0 - */ -chanspec_t -wf_chspec_aton(const char *a) -{ - chanspec_t chspec; - uint chspec_ch, chspec_band, bw, chspec_bw, chspec_sb; - uint num, ctl_ch; - uint ch1, ch2; - char c, sb_ul = '\0'; - int i; - - bw = 20; - chspec_sb = 0; - chspec_ch = ch1 = ch2 = 0; - - /* parse channel num or band */ - if (!read_uint(&a, &num)) - return 0; - /* if we are looking at a 'g', then the first number was a band */ - c = tolower((int)a[0]); - if (c == 'g') { - a++; /* consume the char */ - - /* band must be "2" or "5" */ - if (num == 2) - chspec_band = WL_CHANSPEC_BAND_2G; - else if (num == 5) - chspec_band = WL_CHANSPEC_BAND_5G; - else - return 0; - - /* read the channel number */ - if (!read_uint(&a, &ctl_ch)) - return 0; - - c = tolower((int)a[0]); - } - else { - /* first number is channel, use default for band */ - ctl_ch = num; - chspec_band = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? - WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); - } - - if (c == '\0') { - /* default BW of 20MHz */ - chspec_bw = WL_CHANSPEC_BW_20; - goto done_read; - } - - a ++; /* consume the 'u','l', or '/' */ - - /* check 'u'/'l' */ - if (c == 'u' || c == 'l') { - sb_ul = c; - chspec_bw = WL_CHANSPEC_BW_40; - goto done_read; - } - - /* next letter must be '/' */ - if (c != '/') - return 0; - - /* read bandwidth */ - if (!read_uint(&a, &bw)) - return 0; - - /* convert to chspec value */ - if (bw == 2) { - chspec_bw = WL_CHANSPEC_BW_2P5; - } else if (bw == 5) { - chspec_bw = WL_CHANSPEC_BW_5; - } else if (bw == 10) { - chspec_bw = WL_CHANSPEC_BW_10; - } else if (bw == 20) { - chspec_bw = WL_CHANSPEC_BW_20; - } else if (bw == 40) { - chspec_bw = WL_CHANSPEC_BW_40; - } else if (bw == 80) { - chspec_bw = WL_CHANSPEC_BW_80; - } else if (bw == 160) { - chspec_bw = WL_CHANSPEC_BW_160; - } else { - return 0; - } - - /* So far we have <band>g<chan>/<bw> - * Can now be followed by u/l if bw = 40, - * or '+80' if bw = 80, to make '80+80' bw, - * or '.5' if bw = 2.5 to make '2.5' bw . - */ - - c = tolower((int)a[0]); - - /* if we have a 2g/40 channel, we should have a l/u spec now */ - if (chspec_band == WL_CHANSPEC_BAND_2G && bw == 40) { - if (c == 'u' || c == 'l') { - a ++; /* consume the u/l char */ - sb_ul = c; - goto done_read; - } - } - - /* check for 80+80 */ - if (c == '+') { - /* 80+80 */ - const char plus80[] = "80/"; - - /* must be looking at '+80/' - * check and consume this string. - */ - chspec_bw = WL_CHANSPEC_BW_8080; - - a ++; /* consume the char '+' */ - - /* consume the '80/' string */ - for (i = 0; i < 3; i++) { - if (*a++ != plus80[i]) { - return 0; - } - } - - /* read primary 80MHz channel */ - if (!read_uint(&a, &ch1)) - return 0; - - /* must followed by '-' */ - if (a[0] != '-') - return 0; - a ++; /* consume the char */ - - /* read secondary 80MHz channel */ - if (!read_uint(&a, &ch2)) - return 0; - } else if (c == '.') { - /* 2.5 */ - /* must be looking at '.5' - * check and consume this string. - */ - chspec_bw = WL_CHANSPEC_BW_2P5; - - a ++; /* consume the char '.' */ - - /* consume the '5' string */ - if (*a++ != '5') { - return 0; - } - } - -done_read: - /* skip trailing white space */ - while (a[0] == ' ') { - a ++; - } - - /* must be end of string */ - if (a[0] != '\0') - return 0; - - /* Now have all the chanspec string parts read; - * chspec_band, ctl_ch, chspec_bw, sb_ul, ch1, ch2. - * chspec_band and chspec_bw are chanspec values. - * Need to convert ctl_ch, sb_ul, and ch1,ch2 into - * a center channel (or two) and sideband. - */ - - /* if a sb u/l string was given, just use that, - * guaranteed to be bw = 40 by sting parse. - */ - if (sb_ul != '\0') { - if (sb_ul == 'l') { - chspec_ch = UPPER_20_SB(ctl_ch); - chspec_sb = WL_CHANSPEC_CTL_SB_LLL; - } else if (sb_ul == 'u') { - chspec_ch = LOWER_20_SB(ctl_ch); - chspec_sb = WL_CHANSPEC_CTL_SB_LLU; - } - } - /* if the bw is 20, center and sideband are trivial */ - else if (BW_LE20(chspec_bw)) { - chspec_ch = ctl_ch; - chspec_sb = WL_CHANSPEC_CTL_SB_NONE; - } - /* if the bw is 40/80/160, not 80+80, a single method - * can be used to to find the center and sideband - */ - else if (chspec_bw != WL_CHANSPEC_BW_8080) { - /* figure out ctl sideband based on ctl channel and bandwidth */ - const uint8 *center_ch = NULL; - int num_ch = 0; - int sb = -1; - - if (chspec_bw == WL_CHANSPEC_BW_40) { - center_ch = wf_5g_40m_chans; - num_ch = WF_NUM_5G_40M_CHANS; - } else if (chspec_bw == WL_CHANSPEC_BW_80) { - center_ch = wf_5g_80m_chans; - num_ch = WF_NUM_5G_80M_CHANS; - } else if (chspec_bw == WL_CHANSPEC_BW_160) { - center_ch = wf_5g_160m_chans; - num_ch = WF_NUM_5G_160M_CHANS; - } else { - return 0; - } - - for (i = 0; i < num_ch; i ++) { - sb = channel_to_sb(center_ch[i], ctl_ch, bw); - if (sb >= 0) { - chspec_ch = center_ch[i]; - chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; - break; - } - } - - /* check for no matching sb/center */ - if (sb < 0) { - return 0; - } - } - /* Otherwise, bw is 80+80. Figure out channel pair and sb */ - else { - int ch1_id = 0, ch2_id = 0; - int sb; - - /* look up the channel ID for the specified channel numbers */ - ch1_id = channel_80mhz_to_id(ch1); - ch2_id = channel_80mhz_to_id(ch2); - - /* validate channels */ - if (ch1_id < 0 || ch2_id < 0) - return 0; - - /* combine 2 channel IDs in channel field of chspec */ - chspec_ch = (((uint)ch1_id << WL_CHANSPEC_CHAN1_SHIFT) | - ((uint)ch2_id << WL_CHANSPEC_CHAN2_SHIFT)); - - /* figure out primary 20 MHz sideband */ - - /* is the primary channel contained in the 1st 80MHz channel? */ - sb = channel_to_sb(ch1, ctl_ch, bw); - if (sb < 0) { - /* no match for primary channel 'ctl_ch' in segment0 80MHz channel */ - return 0; - } - - chspec_sb = sb << WL_CHANSPEC_CTL_SB_SHIFT; - } - - chspec = (chspec_ch | chspec_band | chspec_bw | chspec_sb); - - if (wf_chspec_malformed(chspec)) - return 0; - - return chspec; -} - -/* - * Verify the chanspec is using a legal set of parameters, i.e. that the - * chanspec specified a band, bw, ctl_sb and channel and that the - * combination could be legal given any set of circumstances. - * RETURNS: TRUE is the chanspec is malformed, false if it looks good. - */ -bool -wf_chspec_malformed(chanspec_t chanspec) -{ - uint chspec_bw = CHSPEC_BW(chanspec); - uint chspec_ch = CHSPEC_CHANNEL(chanspec); - - /* must be 2G or 5G band */ - if (CHSPEC_IS2G(chanspec)) { - /* must be valid bandwidth */ - if (!BW_LE40(chspec_bw)) { - return TRUE; - } - } else if (CHSPEC_IS5G(chanspec)) { - if (chspec_bw == WL_CHANSPEC_BW_8080) { - uint ch1_id, ch2_id; - - /* channel IDs in 80+80 must be in range */ - ch1_id = CHSPEC_CHAN1(chanspec); - ch2_id = CHSPEC_CHAN2(chanspec); - if (ch1_id >= WF_NUM_5G_80M_CHANS || ch2_id >= WF_NUM_5G_80M_CHANS) - return TRUE; - - } else if (BW_LE160(chspec_bw)) { - if (chspec_ch > MAXCHANNEL) { - return TRUE; - } - } else { - /* invalid bandwidth */ - return TRUE; - } - } else { - /* must be 2G or 5G band */ - return TRUE; - } - - /* side band needs to be consistent with bandwidth */ - if (BW_LE20(chspec_bw)) { - if (CHSPEC_CTL_SB(chanspec) != WL_CHANSPEC_CTL_SB_LLL) - return TRUE; - } else if (chspec_bw == WL_CHANSPEC_BW_40) { - if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LLU) - return TRUE; - } else if (chspec_bw == WL_CHANSPEC_BW_80 || - chspec_bw == WL_CHANSPEC_BW_8080) { - if (CHSPEC_CTL_SB(chanspec) > WL_CHANSPEC_CTL_SB_LUU) - return TRUE; - } - else if (chspec_bw == WL_CHANSPEC_BW_160) { - ASSERT(CHSPEC_CTL_SB(chanspec) <= WL_CHANSPEC_CTL_SB_UUU); - } - return FALSE; -} - -/* - * Verify the chanspec specifies a valid channel according to 802.11. - * RETURNS: TRUE if the chanspec is a valid 802.11 channel - */ -bool -wf_chspec_valid(chanspec_t chanspec) -{ - uint chspec_bw = CHSPEC_BW(chanspec); - uint chspec_ch = CHSPEC_CHANNEL(chanspec); - - if (wf_chspec_malformed(chanspec)) - return FALSE; - - if (CHSPEC_IS2G(chanspec)) { - /* must be valid bandwidth and channel range */ - if (BW_LE20(chspec_bw)) { - if (chspec_ch >= 1 && chspec_ch <= 14) - return TRUE; - } else if (chspec_bw == WL_CHANSPEC_BW_40) { - if (chspec_ch >= 3 && chspec_ch <= 11) - return TRUE; - } - } else if (CHSPEC_IS5G(chanspec)) { - if (chspec_bw == WL_CHANSPEC_BW_8080) { - uint16 ch1, ch2; - - ch1 = wf_5g_80m_chans[CHSPEC_CHAN1(chanspec)]; - ch2 = wf_5g_80m_chans[CHSPEC_CHAN2(chanspec)]; - - /* the two channels must be separated by more than 80MHz by VHT req */ - if ((ch2 > ch1 + CH_80MHZ_APART) || - (ch1 > ch2 + CH_80MHZ_APART)) - return TRUE; - } else { - const uint8 *center_ch; - uint num_ch, i; - - if (BW_LE40(chspec_bw)) { - center_ch = wf_5g_40m_chans; - num_ch = WF_NUM_5G_40M_CHANS; - } else if (chspec_bw == WL_CHANSPEC_BW_80) { - center_ch = wf_5g_80m_chans; - num_ch = WF_NUM_5G_80M_CHANS; - } else if (chspec_bw == WL_CHANSPEC_BW_160) { - center_ch = wf_5g_160m_chans; - num_ch = WF_NUM_5G_160M_CHANS; - } else { - /* invalid bandwidth */ - return FALSE; - } - - /* check for a valid center channel */ - if (BW_LE20(chspec_bw)) { - /* We don't have an array of legal 20MHz 5G channels, but they are - * each side of the legal 40MHz channels. Check the chanspec - * channel against either side of the 40MHz channels. - */ - for (i = 0; i < num_ch; i ++) { - if (chspec_ch == (uint)LOWER_20_SB(center_ch[i]) || - chspec_ch == (uint)UPPER_20_SB(center_ch[i])) - break; /* match found */ - } - - if (i == num_ch) { - /* check for channel 165 which is not the side band - * of 40MHz 5G channel - */ - if (chspec_ch == 165) - i = 0; - - /* check for legacy JP channels on failure */ - if (chspec_ch == 34 || chspec_ch == 38 || - chspec_ch == 42 || chspec_ch == 46) - i = 0; - } - } else { - /* check the chanspec channel to each legal channel */ - for (i = 0; i < num_ch; i ++) { - if (chspec_ch == center_ch[i]) - break; /* match found */ - } - } - - if (i < num_ch) { - /* match found */ - return TRUE; - } - } - } - - return FALSE; -} - -/* - * This function returns the channel number that control traffic is being sent on, for 20MHz - * channels this is just the channel number, for 40MHZ, 80MHz, 160MHz channels it is the 20MHZ - * sideband depending on the chanspec selected - */ -uint8 -wf_chspec_ctlchan(chanspec_t chspec) -{ - uint center_chan; - uint bw_mhz; - uint sb; - - ASSERT(!wf_chspec_malformed(chspec)); - - /* Is there a sideband ? */ - if (CHSPEC_BW_LE20(chspec)) { - return CHSPEC_CHANNEL(chspec); - } else { - sb = CHSPEC_CTL_SB(chspec) >> WL_CHANSPEC_CTL_SB_SHIFT; - - if (CHSPEC_IS8080(chspec)) { - /* For an 80+80 MHz channel, the sideband 'sb' field is an 80 MHz sideband - * (LL, LU, UL, LU) for the 80 MHz frequency segment 0. - */ - uint chan_id = CHSPEC_CHAN1(chspec); - - bw_mhz = 80; - - /* convert from channel index to channel number */ - center_chan = wf_5g_80m_chans[chan_id]; - } - else { - bw_mhz = bw_chspec_to_mhz(chspec); - center_chan = CHSPEC_CHANNEL(chspec) >> WL_CHANSPEC_CHAN_SHIFT; - } - - return (channel_to_ctl_chan(center_chan, bw_mhz, sb)); - } -} - -/* given a chanspec, return the bandwidth string */ -const char * -wf_chspec_to_bw_str(chanspec_t chspec) -{ - return wf_chspec_bw_str[(CHSPEC_BW(chspec) >> WL_CHANSPEC_BW_SHIFT)]; -} - -/* - * This function returns the chanspec of the control channel of a given chanspec - */ -chanspec_t -wf_chspec_ctlchspec(chanspec_t chspec) -{ - chanspec_t ctl_chspec = chspec; - uint8 ctl_chan; - - ASSERT(!wf_chspec_malformed(chspec)); - - /* Is there a sideband ? */ - if (!CHSPEC_BW_LE20(chspec)) { - ctl_chan = wf_chspec_ctlchan(chspec); - ctl_chspec = ctl_chan | WL_CHANSPEC_BW_20; - ctl_chspec |= CHSPEC_BAND(chspec); - } - return ctl_chspec; -} - -/* return chanspec given control channel and bandwidth - * return 0 on error - */ -uint16 -wf_channel2chspec(uint ctl_ch, uint bw) -{ - uint16 chspec; - const uint8 *center_ch = NULL; - int num_ch = 0; - int sb = -1; - int i = 0; - - chspec = ((ctl_ch <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G); - - chspec |= bw; - - if (bw == WL_CHANSPEC_BW_40) { - center_ch = wf_5g_40m_chans; - num_ch = WF_NUM_5G_40M_CHANS; - bw = 40; - } else if (bw == WL_CHANSPEC_BW_80) { - center_ch = wf_5g_80m_chans; - num_ch = WF_NUM_5G_80M_CHANS; - bw = 80; - } else if (bw == WL_CHANSPEC_BW_160) { - center_ch = wf_5g_160m_chans; - num_ch = WF_NUM_5G_160M_CHANS; - bw = 160; - } else if (BW_LE20(bw)) { - chspec |= ctl_ch; - return chspec; - } else { - return 0; - } - - for (i = 0; i < num_ch; i ++) { - sb = channel_to_sb(center_ch[i], ctl_ch, bw); - if (sb >= 0) { - chspec |= center_ch[i]; - chspec |= (sb << WL_CHANSPEC_CTL_SB_SHIFT); - break; - } - } - - /* check for no matching sb/center */ - if (sb < 0) { - return 0; - } - - return chspec; -} - -/* - * This function returns the chanspec for the primary 40MHz of an 80MHz channel. - * The control sideband specifies the same 20MHz channel that the 80MHz channel is using - * as the primary 20MHz channel. - */ -extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec) -{ - chanspec_t chspec40 = chspec; - uint center_chan; - uint sb; - - ASSERT(!wf_chspec_malformed(chspec)); - - /* if the chanspec is > 80MHz, use the helper routine to find the primary 80 MHz channel */ - if (CHSPEC_IS8080(chspec) || CHSPEC_IS160(chspec)) { - chspec = wf_chspec_primary80_chspec(chspec); - } - - /* determine primary 40 MHz sub-channel of an 80 MHz chanspec */ - if (CHSPEC_IS80(chspec)) { - center_chan = CHSPEC_CHANNEL(chspec); - sb = CHSPEC_CTL_SB(chspec); - - if (sb < WL_CHANSPEC_CTL_SB_UL) { - /* Primary 40MHz is on lower side */ - center_chan -= CH_20MHZ_APART; - /* sideband bits are the same for LL/LU and L/U */ - } else { - /* Primary 40MHz is on upper side */ - center_chan += CH_20MHZ_APART; - /* sideband bits need to be adjusted by UL offset */ - sb -= WL_CHANSPEC_CTL_SB_UL; - } - - /* Create primary 40MHz chanspec */ - chspec40 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_40 | - sb | center_chan); - } - - return chspec40; -} - -/* - * Return the channel number for a given frequency and base frequency. - * The returned channel number is relative to the given base frequency. - * If the given base frequency is zero, a base frequency of 5 GHz is assumed for - * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. - * - * Frequency is specified in MHz. - * The base frequency is specified as (start_factor * 500 kHz). - * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for - * 2.4 GHz and 5 GHz bands. - * - * The returned channel will be in the range [1, 14] in the 2.4 GHz band - * and [0, 200] otherwise. - * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the - * frequency is not a 2.4 GHz channel, or if the frequency is not and even - * multiple of 5 MHz from the base frequency to the base plus 1 GHz. - * - * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 - */ -int -wf_mhz2channel(uint freq, uint start_factor) -{ - int ch = -1; - uint base; - int offset; - - /* take the default channel start frequency */ - if (start_factor == 0) { - if (freq >= 2400 && freq <= 2500) - start_factor = WF_CHAN_FACTOR_2_4_G; - else if (freq >= 5000 && freq <= 6000) - start_factor = WF_CHAN_FACTOR_5_G; - } - - if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G) - return 14; - - base = start_factor / 2; - - /* check that the frequency is in 1GHz range of the base */ - if ((freq < base) || (freq > base + 1000)) - return -1; - - offset = freq - base; - ch = offset / 5; - - /* check that frequency is a 5MHz multiple from the base */ - if (offset != (ch * 5)) - return -1; - - /* restricted channel range check for 2.4G */ - if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13)) - return -1; - - return ch; -} - -/* - * 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_4_G, and WF_CHAN_FACTOR_5_G - * are defined for 2.4 GHz, 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 = 2407 * 2). - * Odd start_factors produce channels on .5 MHz boundaries, in which case - * the answer is rounded down to an integral MHz. - * -1 is returned for an out of range channel. - * - * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 - */ -int -wf_channel2mhz(uint ch, uint start_factor) -{ - int freq; - - if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) || - (ch > 200)) - freq = -1; - else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14)) - freq = 2484; - else - freq = ch * 5 + start_factor / 2; - - return freq; -} - -static const uint16 sidebands[] = { - WL_CHANSPEC_CTL_SB_LLL, WL_CHANSPEC_CTL_SB_LLU, - WL_CHANSPEC_CTL_SB_LUL, WL_CHANSPEC_CTL_SB_LUU, - WL_CHANSPEC_CTL_SB_ULL, WL_CHANSPEC_CTL_SB_ULU, - WL_CHANSPEC_CTL_SB_UUL, WL_CHANSPEC_CTL_SB_UUU -}; - -/* - * 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 - */ -chanspec_t -wf_chspec_80(uint8 center_channel, uint8 primary_channel) -{ - - chanspec_t chanspec = INVCHANSPEC; - chanspec_t chanspec_cur; - uint i; - - for (i = 0; i < WF_NUM_SIDEBANDS_80MHZ; i++) { - chanspec_cur = CH80MHZ_CHSPEC(center_channel, sidebands[i]); - if (primary_channel == wf_chspec_ctlchan(chanspec_cur)) { - chanspec = chanspec_cur; - break; - } - } - /* If the loop ended early, we are good, otherwise we did not - * find a 80MHz chanspec with the given center_channel that had a primary channel - *matching the given primary_channel. - */ - return chanspec; -} - -/* - * Returns the 80+80 chanspec corresponding to the following input parameters - * - * primary_20mhz - Primary 20 MHz channel - * chan0 - center channel number of one frequency segment - * chan1 - center channel number of the other frequency segment - * - * Parameters chan0 and chan1 are channel numbers in {42, 58, 106, 122, 138, 155}. - * The primary channel must be contained in one of the 80MHz channels. This routine - * will determine which frequency segment is the primary 80 MHz segment. - * - * Returns INVCHANSPEC in case of error. - * - * Refer to IEEE802.11ac section 22.3.14 "Channelization". - */ -chanspec_t -wf_chspec_get8080_chspec(uint8 primary_20mhz, uint8 chan0, uint8 chan1) -{ - int sb = 0; - uint16 chanspec = 0; - int chan0_id = 0, chan1_id = 0; - int seg0, seg1; - - chan0_id = channel_80mhz_to_id(chan0); - chan1_id = channel_80mhz_to_id(chan1); - - /* make sure the channel numbers were valid */ - if (chan0_id == -1 || chan1_id == -1) - return INVCHANSPEC; - - /* does the primary channel fit with the 1st 80MHz channel ? */ - sb = channel_to_sb(chan0, primary_20mhz, 80); - if (sb >= 0) { - /* yes, so chan0 is frequency segment 0, and chan1 is seg 1 */ - seg0 = chan0_id; - seg1 = chan1_id; - } else { - /* no, so does the primary channel fit with the 2nd 80MHz channel ? */ - sb = channel_to_sb(chan1, primary_20mhz, 80); - if (sb < 0) { - /* no match for ctl_ch to either 80MHz center channel */ - return INVCHANSPEC; - } - /* swapped, so chan1 is frequency segment 0, and chan0 is seg 1 */ - seg0 = chan1_id; - seg1 = chan0_id; - } - - chanspec = ((seg0 << WL_CHANSPEC_CHAN1_SHIFT) | - (seg1 << WL_CHANSPEC_CHAN2_SHIFT) | - (sb << WL_CHANSPEC_CTL_SB_SHIFT) | - WL_CHANSPEC_BW_8080 | - WL_CHANSPEC_BAND_5G); - - return chanspec; -} - -/* - * This function returns the 80Mhz channel for the given id. - */ -static uint8 -wf_chspec_get80Mhz_ch(uint8 chan_80Mhz_id) -{ - if (chan_80Mhz_id < WF_NUM_5G_80M_CHANS) - return wf_5g_80m_chans[chan_80Mhz_id]; - - return 0; -} - -/* - * Returns the primary 80 Mhz channel for the provided chanspec - * - * chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved - * - * returns -1 in case the provided channel is 20/40 Mhz chanspec - */ - -uint8 -wf_chspec_primary80_channel(chanspec_t chanspec) -{ - uint8 primary80_chan; - - if (CHSPEC_IS80(chanspec)) { - primary80_chan = CHSPEC_CHANNEL(chanspec); - } - else if (CHSPEC_IS8080(chanspec)) { - /* Channel ID 1 corresponds to frequency segment 0, the primary 80 MHz segment */ - primary80_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chanspec)); - } - else if (CHSPEC_IS160(chanspec)) { - uint8 center_chan = CHSPEC_CHANNEL(chanspec); - uint sb = CHSPEC_CTL_SB(chanspec) >> WL_CHANSPEC_CTL_SB_SHIFT; - - /* based on the sb value primary 80 channel can be retrieved - * if sb is in range 0 to 3 the lower band is the 80Mhz primary band - */ - if (sb < 4) { - primary80_chan = center_chan - CH_40MHZ_APART; - } - /* if sb is in range 4 to 7 the upper band is the 80Mhz primary band */ - else - { - primary80_chan = center_chan + CH_40MHZ_APART; - } - } - else { - /* for 20 and 40 Mhz */ - primary80_chan = -1; - } - return primary80_chan; -} - -/* - * Returns the secondary 80 Mhz channel for the provided chanspec - * - * chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved - * - * returns -1 in case the provided channel is 20/40/80 Mhz chanspec - */ -uint8 -wf_chspec_secondary80_channel(chanspec_t chanspec) -{ - uint8 secondary80_chan; - - if (CHSPEC_IS8080(chanspec)) { - secondary80_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN2(chanspec)); - } - else if (CHSPEC_IS160(chanspec)) { - uint8 center_chan = CHSPEC_CHANNEL(chanspec); - uint sb = CHSPEC_CTL_SB(chanspec) >> WL_CHANSPEC_CTL_SB_SHIFT; - - /* based on the sb value secondary 80 channel can be retrieved - * if sb is in range 0 to 3 upper band is the secondary 80Mhz band - */ - if (sb < 4) { - secondary80_chan = center_chan + CH_40MHZ_APART; - } - /* if sb is in range 4 to 7 the lower band is the secondary 80Mhz band */ - else - { - secondary80_chan = center_chan - CH_40MHZ_APART; - } - } - else { - /* for 20, 40, and 80 Mhz */ - secondary80_chan = -1; - } - return secondary80_chan; -} - -/* - * This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel. - * - * chanspec - Input chanspec for which the primary 80Mhz chanspec has to be retreived - * - * returns the input chanspec in case the provided chanspec is an 80 MHz chanspec - * returns INVCHANSPEC in case the provided channel is 20/40 MHz chanspec - */ -chanspec_t -wf_chspec_primary80_chspec(chanspec_t chspec) -{ - chanspec_t chspec80; - uint center_chan; - uint sb; - - ASSERT(!wf_chspec_malformed(chspec)); - if (CHSPEC_IS80(chspec)) { - chspec80 = chspec; - } - else if (CHSPEC_IS8080(chspec)) { - - /* Channel ID 1 corresponds to frequency segment 0, the primary 80 MHz segment */ - center_chan = wf_chspec_get80Mhz_ch(CHSPEC_CHAN1(chspec)); - - sb = CHSPEC_CTL_SB(chspec); - - /* Create primary 80MHz chanspec */ - chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan); - } - else if (CHSPEC_IS160(chspec)) { - center_chan = CHSPEC_CHANNEL(chspec); - sb = CHSPEC_CTL_SB(chspec); - - if (sb < WL_CHANSPEC_CTL_SB_ULL) { - /* Primary 80MHz is on lower side */ - center_chan -= CH_40MHZ_APART; - } - else { - /* Primary 80MHz is on upper side */ - center_chan += CH_40MHZ_APART; - sb -= WL_CHANSPEC_CTL_SB_ULL; - } - /* Create primary 80MHz chanspec */ - chspec80 = (WL_CHANSPEC_BAND_5G | WL_CHANSPEC_BW_80 | sb | center_chan); - } - else { - chspec80 = INVCHANSPEC; - } - - return chspec80; -} - -#ifdef WL11AC_80P80 -uint8 -wf_chspec_channel(chanspec_t chspec) -{ - if (CHSPEC_IS8080(chspec)) { - return wf_chspec_primary80_channel(chspec); - } - else { - return ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)); - } -} -#endif /* WL11AC_80P80 */ - -/* This routine returns the chanspec for a given operating class and - * channel number - */ -chanspec_t -wf_channel_create_chspec_frm_opclass(uint8 opclass, uint8 channel) -{ - chanspec_t chanspec = 0; - uint16 opclass_info = 0; - uint16 lookupindex = 0; - switch (opclass) { - case 115: - lookupindex = 1; - break; - case 124: - lookupindex = 3; - break; - case 125: - lookupindex = 5; - break; - case 81: - lookupindex = 12; - break; - case 116: - lookupindex = 22; - break; - case 119: - lookupindex = 23; - break; - case 126: - lookupindex = 25; - break; - case 83: - lookupindex = 32; - break; - case 84: - lookupindex = 33; - break; - default: - lookupindex = 12; - } - - if (lookupindex < 33) { - opclass_info = opclass_data[lookupindex-1]; - } - else { - opclass_info = opclass_data[11]; - } - chanspec = opclass_info | (uint16)channel; - return chanspec; -} - -/* This routine returns the opclass for a given chanspec */ -int -wf_channel_create_opclass_frm_chspec(chanspec_t chspec) -{ - BCM_REFERENCE(chspec); - /* TODO: Implement this function ! */ - return 12; /* opclass 12 for basic 2G channels */ -}
diff --git a/bcmdhd.1.579.77.41.x/bcmwifi_channels.h b/bcmdhd.1.579.77.41.x/bcmwifi_channels.h deleted file mode 100644 index 28c6e27..0000000 --- a/bcmdhd.1.579.77.41.x/bcmwifi_channels.h +++ /dev/null
@@ -1,645 +0,0 @@ -/* - * Misc utility routines for WL and Apps - * This header file housing the define and function prototype use by - * both the wl driver, tools & Apps. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: bcmwifi_channels.h 612483 2016-01-14 03:44:27Z $ - */ - -#ifndef _bcmwifi_channels_h_ -#define _bcmwifi_channels_h_ - - -/* A chanspec holds the channel number, band, bandwidth and control sideband */ -typedef uint16 chanspec_t; - -/* channel defines */ -#define CH_UPPER_SB 0x01 -#define CH_LOWER_SB 0x02 -#define CH_EWA_VALID 0x04 -#define CH_80MHZ_APART 16 -#define CH_40MHZ_APART 8 -#define CH_20MHZ_APART 4 -#define CH_10MHZ_APART 2 -#define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */ -#define CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */ - -/* maximum # channels the s/w supports */ -#define MAXCHANNEL 224 /* max # supported channels. The max channel no is above, - * this is that + 1 rounded up to a multiple of NBBY (8). - * DO NOT MAKE it > 255: channels are uint8's all over - */ -#define MAXCHANNEL_NUM (MAXCHANNEL - 1) /* max channel number */ - -/* channel bitvec */ -typedef struct { - uint8 vec[MAXCHANNEL/8]; /* bitvec of channels */ -} chanvec_t; - -/* make sure channel num is within valid range */ -#define CH_NUM_VALID_RANGE(ch_num) ((ch_num) > 0 && (ch_num) <= MAXCHANNEL_NUM) - -#define CHSPEC_CTLOVLP(sp1, sp2, sep) \ - (ABS(wf_chspec_ctlchan(sp1) - wf_chspec_ctlchan(sp2)) < (sep)) - -/* All builds use the new 11ac ratespec/chanspec */ -#undef D11AC_IOTYPES -#define D11AC_IOTYPES - -#define WL_CHANSPEC_CHAN_MASK 0x00ff -#define WL_CHANSPEC_CHAN_SHIFT 0 -#define WL_CHANSPEC_CHAN1_MASK 0x000f -#define WL_CHANSPEC_CHAN1_SHIFT 0 -#define WL_CHANSPEC_CHAN2_MASK 0x00f0 -#define WL_CHANSPEC_CHAN2_SHIFT 4 - -#define WL_CHANSPEC_CTL_SB_MASK 0x0700 -#define WL_CHANSPEC_CTL_SB_SHIFT 8 -#define WL_CHANSPEC_CTL_SB_LLL 0x0000 -#define WL_CHANSPEC_CTL_SB_LLU 0x0100 -#define WL_CHANSPEC_CTL_SB_LUL 0x0200 -#define WL_CHANSPEC_CTL_SB_LUU 0x0300 -#define WL_CHANSPEC_CTL_SB_ULL 0x0400 -#define WL_CHANSPEC_CTL_SB_ULU 0x0500 -#define WL_CHANSPEC_CTL_SB_UUL 0x0600 -#define WL_CHANSPEC_CTL_SB_UUU 0x0700 -#define WL_CHANSPEC_CTL_SB_LL WL_CHANSPEC_CTL_SB_LLL -#define WL_CHANSPEC_CTL_SB_LU WL_CHANSPEC_CTL_SB_LLU -#define WL_CHANSPEC_CTL_SB_UL WL_CHANSPEC_CTL_SB_LUL -#define WL_CHANSPEC_CTL_SB_UU WL_CHANSPEC_CTL_SB_LUU -#define WL_CHANSPEC_CTL_SB_L WL_CHANSPEC_CTL_SB_LLL -#define WL_CHANSPEC_CTL_SB_U WL_CHANSPEC_CTL_SB_LLU -#define WL_CHANSPEC_CTL_SB_LOWER WL_CHANSPEC_CTL_SB_LLL -#define WL_CHANSPEC_CTL_SB_UPPER WL_CHANSPEC_CTL_SB_LLU -#define WL_CHANSPEC_CTL_SB_NONE WL_CHANSPEC_CTL_SB_LLL - -#define WL_CHANSPEC_BW_MASK 0x3800 -#define WL_CHANSPEC_BW_SHIFT 11 -#define WL_CHANSPEC_BW_5 0x0000 -#define WL_CHANSPEC_BW_10 0x0800 -#define WL_CHANSPEC_BW_20 0x1000 -#define WL_CHANSPEC_BW_40 0x1800 -#define WL_CHANSPEC_BW_80 0x2000 -#define WL_CHANSPEC_BW_160 0x2800 -#define WL_CHANSPEC_BW_8080 0x3000 -#define WL_CHANSPEC_BW_2P5 0x3800 - -#define WL_CHANSPEC_BAND_MASK 0xc000 -#define WL_CHANSPEC_BAND_SHIFT 14 -#define WL_CHANSPEC_BAND_2G 0x0000 -#define WL_CHANSPEC_BAND_3G 0x4000 -#define WL_CHANSPEC_BAND_4G 0x8000 -#define WL_CHANSPEC_BAND_5G 0xc000 -#define INVCHANSPEC 255 -#define MAX_CHANSPEC 0xFFFF - -#define WL_CHANNEL_BAND(ch) (((ch) <= CH_MAX_2G_CHANNEL) ? \ - WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G) - -/* channel defines */ -#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? \ - ((channel) - CH_10MHZ_APART) : 0) -#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \ - ((channel) + CH_10MHZ_APART) : 0) - -#define LL_20_SB(channel) (((channel) > 3 * CH_10MHZ_APART) ? ((channel) - 3 * CH_10MHZ_APART) : 0) -#define UU_20_SB(channel) (((channel) < (MAXCHANNEL - 3 * CH_10MHZ_APART)) ? \ - ((channel) + 3 * CH_10MHZ_APART) : 0) -#define LU_20_SB(channel) LOWER_20_SB(channel) -#define UL_20_SB(channel) UPPER_20_SB(channel) - -#define LOWER_40_SB(channel) ((channel) - CH_20MHZ_APART) -#define UPPER_40_SB(channel) ((channel) + CH_20MHZ_APART) -#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX) -#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \ - (((channel) <= CH_MAX_2G_CHANNEL) ? \ - WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) -#define CH2P5MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_2P5 | \ - (((channel) <= CH_MAX_2G_CHANNEL) ? \ - WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) -#define CH5MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_5 | \ - (((channel) <= CH_MAX_2G_CHANNEL) ? \ - WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) -#define CH10MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_10 | \ - (((channel) <= CH_MAX_2G_CHANNEL) ? \ - WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) -#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \ - ((channel) + CH_20MHZ_APART) : 0) -#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ - ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \ - ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \ - WL_CHANSPEC_BAND_5G)) -#define CH80MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ - ((channel) | (ctlsb) | \ - WL_CHANSPEC_BW_80 | WL_CHANSPEC_BAND_5G) -#define CH160MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \ - ((channel) | (ctlsb) | \ - WL_CHANSPEC_BW_160 | WL_CHANSPEC_BAND_5G) -#define CHBW_CHSPEC(bw, channel) (chanspec_t)((chanspec_t)(channel) | (bw) | \ - (((channel) <= CH_MAX_2G_CHANNEL) ? \ - WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G)) - -/* simple MACROs to get different fields of chanspec */ -#ifdef WL11AC_80P80 -#define CHSPEC_CHANNEL(chspec) wf_chspec_channel(chspec) -#else -#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK)) -#endif -#define CHSPEC_CHAN1(chspec) ((chspec) & WL_CHANSPEC_CHAN1_MASK) >> WL_CHANSPEC_CHAN1_SHIFT -#define CHSPEC_CHAN2(chspec) ((chspec) & WL_CHANSPEC_CHAN2_MASK) >> WL_CHANSPEC_CHAN2_SHIFT -#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) -#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK) -#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK) - -#ifdef WL11N_20MHZONLY -#ifdef WL11ULB -#define CHSPEC_IS2P5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_2P5) -#define CHSPEC_IS5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_5) -#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) -#else -#define CHSPEC_IS2P5(chspec) 0 -#define CHSPEC_IS5(chspec) 0 -#define CHSPEC_IS10(chspec) 0 -#endif -#define CHSPEC_IS20(chspec) 1 -#define CHSPEC_IS20_2G(chspec) ((((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) && \ - CHSPEC_IS2G(chspec)) -#ifndef CHSPEC_IS40 -#define CHSPEC_IS40(chspec) 0 -#endif -#ifndef CHSPEC_IS80 -#define CHSPEC_IS80(chspec) 0 -#endif -#ifndef CHSPEC_IS160 -#define CHSPEC_IS160(chspec) 0 -#endif -#ifndef CHSPEC_IS8080 -#define CHSPEC_IS8080(chspec) 0 -#endif -#define BW_LE20(bw) TRUE -#define CHSPEC_ISLE20(chspec) TRUE -#else /* !WL11N_20MHZONLY */ - -#define CHSPEC_IS2P5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_2P5) -#define CHSPEC_IS5(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_5) -#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) -#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) -#define CHSPEC_IS20_5G(chspec) ((((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) && \ - CHSPEC_IS5G(chspec)) -#ifndef CHSPEC_IS40 -#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) -#endif -#ifndef CHSPEC_IS80 -#define CHSPEC_IS80(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_80) -#endif -#ifndef CHSPEC_IS160 -#define CHSPEC_IS160(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_160) -#endif -#ifndef CHSPEC_IS8080 -#define CHSPEC_IS8080(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_8080) -#endif - -#ifdef WL11ULB -#define BW_LT20(bw) (((bw) == WL_CHANSPEC_BW_2P5) || \ - ((bw) == WL_CHANSPEC_BW_5) || \ - ((bw) == WL_CHANSPEC_BW_10)) -#define CHSPEC_BW_LT20(chspec) (BW_LT20(CHSPEC_BW(chspec))) -/* This MACRO is strictly to avoid abandons in existing code with ULB feature and is in no way - * optimial to use. Should be replaced with CHSPEC_BW_LE() instead - */ -#define BW_LE20(bw) (((bw) == WL_CHANSPEC_BW_2P5) || \ - ((bw) == WL_CHANSPEC_BW_5) || \ - ((bw) == WL_CHANSPEC_BW_10) || \ - ((bw) == WL_CHANSPEC_BW_20)) -#define CHSPEC_ISLE20(chspec) (BW_LE20(CHSPEC_BW(chspec))) - -#else /* WL11ULB */ -#define BW_LE20(bw) ((bw) == WL_CHANSPEC_BW_20) -#define CHSPEC_ISLE20(chspec) (CHSPEC_IS20(chspec)) -#endif /* WL11ULB */ -#endif /* !WL11N_20MHZONLY */ - -#define BW_LE40(bw) (BW_LE20(bw) || ((bw) == WL_CHANSPEC_BW_40)) -#define BW_LE80(bw) (BW_LE40(bw) || ((bw) == WL_CHANSPEC_BW_80)) -#define BW_LE160(bw) (BW_LE80(bw) || ((bw) == WL_CHANSPEC_BW_160)) -#define CHSPEC_BW_LE20(chspec) (BW_LE20(CHSPEC_BW(chspec))) -#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) -#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) -#define CHSPEC_SB_UPPER(chspec) \ - ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) && \ - (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) -#define CHSPEC_SB_LOWER(chspec) \ - ((((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) && \ - (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)) -#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G) - -/** - * Number of chars needed for wf_chspec_ntoa() destination character buffer. - */ -#define CHANSPEC_STR_LEN 20 - - -#define CHSPEC_IS_BW_160_WIDE(chspec) (CHSPEC_BW(chspec) == WL_CHANSPEC_BW_160 ||\ - CHSPEC_BW(chspec) == WL_CHANSPEC_BW_8080) - -/* BW inequality comparisons, LE (<=), GE (>=), LT (<), GT (>), comparisons can be made -* as simple numeric comparisons, with the exception that 160 is the same BW as 80+80, -* but have different numeric values; (WL_CHANSPEC_BW_160 < WL_CHANSPEC_BW_8080). -* -* The LT/LE/GT/GE macros check first checks whether both chspec bandwidth and bw are 160 wide. -* If both chspec bandwidth and bw is not 160 wide, then the comparison is made. -*/ -#ifdef WL11ULB -#define CHSPEC_BW_GE(chspec, bw) \ - (((CHSPEC_IS_BW_160_WIDE(chspec) &&\ - ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\ - (CHSPEC_BW(chspec) >= (bw))) && \ - (!(CHSPEC_BW(chspec) == WL_CHANSPEC_BW_2P5 && (bw) != WL_CHANSPEC_BW_2P5))) -#else /* WL11ULB */ -#define CHSPEC_BW_GE(chspec, bw) \ - ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ - ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\ - (CHSPEC_BW(chspec) >= (bw))) -#endif /* WL11ULB */ - -#ifdef WL11ULB -#define CHSPEC_BW_LE(chspec, bw) \ - (((CHSPEC_IS_BW_160_WIDE(chspec) &&\ - ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\ - (CHSPEC_BW(chspec) <= (bw))) || \ - (CHSPEC_BW(chspec) == WL_CHANSPEC_BW_2P5)) -#else /* WL11ULB */ -#define CHSPEC_BW_LE(chspec, bw) \ - ((CHSPEC_IS_BW_160_WIDE(chspec) &&\ - ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) ||\ - (CHSPEC_BW(chspec) <= (bw))) -#endif /* WL11ULB */ - -#ifdef WL11ULB -#define CHSPEC_BW_GT(chspec, bw) \ - ((!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ - ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\ - (CHSPEC_BW(chspec) > (bw))) && \ - (CHSPEC_BW(chspec) != WL_CHANSPEC_BW_2P5)) -#else /* WL11ULB */ -#define CHSPEC_BW_GT(chspec, bw) \ - (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ - ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\ - (CHSPEC_BW(chspec) > (bw))) -#endif /* WL11ULB */ - -#ifdef WL11ULB -#define CHSPEC_BW_LT(chspec, bw) \ - ((!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ - ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\ - (CHSPEC_BW(chspec) < (bw))) || \ - ((CHSPEC_BW(chspec) == WL_CHANSPEC_BW_2P5 && (bw) != WL_CHANSPEC_BW_2P5))) -#else /* WL11ULB */ -#define CHSPEC_BW_LT(chspec, bw) \ - (!(CHSPEC_IS_BW_160_WIDE(chspec) &&\ - ((bw) == WL_CHANSPEC_BW_160 || (bw) == WL_CHANSPEC_BW_8080)) &&\ - (CHSPEC_BW(chspec) < (bw))) -#endif /* WL11ULB */ - -/* Legacy Chanspec defines - * These are the defines for the previous format of the chanspec_t - */ -#define WL_LCHANSPEC_CHAN_MASK 0x00ff -#define WL_LCHANSPEC_CHAN_SHIFT 0 - -#define WL_LCHANSPEC_CTL_SB_MASK 0x0300 -#define WL_LCHANSPEC_CTL_SB_SHIFT 8 -#define WL_LCHANSPEC_CTL_SB_LOWER 0x0100 -#define WL_LCHANSPEC_CTL_SB_UPPER 0x0200 -#define WL_LCHANSPEC_CTL_SB_NONE 0x0300 - -#define WL_LCHANSPEC_BW_MASK 0x0C00 -#define WL_LCHANSPEC_BW_SHIFT 10 -#define WL_LCHANSPEC_BW_10 0x0400 -#define WL_LCHANSPEC_BW_20 0x0800 -#define WL_LCHANSPEC_BW_40 0x0C00 - -#define WL_LCHANSPEC_BAND_MASK 0xf000 -#define WL_LCHANSPEC_BAND_SHIFT 12 -#define WL_LCHANSPEC_BAND_5G 0x1000 -#define WL_LCHANSPEC_BAND_2G 0x2000 - -#define LCHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_LCHANSPEC_CHAN_MASK)) -#define LCHSPEC_BAND(chspec) ((chspec) & WL_LCHANSPEC_BAND_MASK) -#define LCHSPEC_CTL_SB(chspec) ((chspec) & WL_LCHANSPEC_CTL_SB_MASK) -#define LCHSPEC_BW(chspec) ((chspec) & WL_LCHANSPEC_BW_MASK) -#define LCHSPEC_IS10(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_10) -#define LCHSPEC_IS20(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_20) -#define LCHSPEC_IS40(chspec) (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40) -#define LCHSPEC_IS5G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_5G) -#define LCHSPEC_IS2G(chspec) (((chspec) & WL_LCHANSPEC_BAND_MASK) == WL_LCHANSPEC_BAND_2G) - -#define LCHSPEC_SB_UPPER(chspec) \ - ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_UPPER) && \ - (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)) -#define LCHSPEC_SB_LOWER(chspec) \ - ((((chspec) & WL_LCHANSPEC_CTL_SB_MASK) == WL_LCHANSPEC_CTL_SB_LOWER) && \ - (((chspec) & WL_LCHANSPEC_BW_MASK) == WL_LCHANSPEC_BW_40)) - -#define LCHSPEC_CREATE(chan, band, bw, sb) ((uint16)((chan) | (sb) | (bw) | (band))) - -#define CH20MHZ_LCHSPEC(channel) \ - (chanspec_t)((chanspec_t)(channel) | WL_LCHANSPEC_BW_20 | \ - WL_LCHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \ - WL_LCHANSPEC_BAND_2G : WL_LCHANSPEC_BAND_5G)) - -/* - * WF_CHAN_FACTOR_* constants are used to calculate channel frequency - * given a channel number. - * chan_freq = chan_factor * 500Mhz + chan_number * 5 - */ - -/** - * Channel Factor for the starting frequence of 2.4 GHz channels. - * The value corresponds to 2407 MHz. - */ -#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */ - -/** - * Channel Factor for the starting frequence of 5 GHz channels. - * The value corresponds to 5000 MHz. - */ -#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */ - -/** - * Channel Factor for the starting frequence of 4.9 GHz channels. - * The value corresponds to 4000 MHz. - */ -#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */ - -#define WLC_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */ - -/** - * No of sub-band vlaue of the specified Mhz chanspec - */ -#define WF_NUM_SIDEBANDS_40MHZ 2 -#define WF_NUM_SIDEBANDS_80MHZ 4 -#define WF_NUM_SIDEBANDS_8080MHZ 4 -#define WF_NUM_SIDEBANDS_160MHZ 8 - -/** - * Convert chanspec to ascii string - * - * @param chspec chanspec format - * @param buf ascii string of chanspec - * - * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes - * Original chanspec in case of error - * - * @see CHANSPEC_STR_LEN - */ -extern char * wf_chspec_ntoa_ex(chanspec_t chspec, char *buf); - -/** - * Convert chanspec to ascii string - * - * @param chspec chanspec format - * @param buf ascii string of chanspec - * - * @return pointer to buf with room for at least CHANSPEC_STR_LEN bytes - * NULL in case of error - * - * @see CHANSPEC_STR_LEN - */ -extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf); - -/** - * Convert ascii string to chanspec - * - * @param a pointer to input string - * - * @return >= 0 if successful or 0 otherwise - */ -extern chanspec_t wf_chspec_aton(const char *a); - -/** - * Verify the chanspec fields are valid. - * - * Verify the chanspec is using a legal set field values, i.e. that the chanspec - * specified a band, bw, ctl_sb and channel and that the combination could be - * legal given some set of circumstances. - * - * @param chanspec input chanspec to verify - * - * @return TRUE if the chanspec is malformed, FALSE if it looks good. - */ -extern bool wf_chspec_malformed(chanspec_t chanspec); - -/** - * Verify the chanspec specifies a valid channel according to 802.11. - * - * @param chanspec input chanspec to verify - * - * @return TRUE if the chanspec is a valid 802.11 channel - */ -extern bool wf_chspec_valid(chanspec_t chanspec); - -/** - * Return the primary (control) channel. - * - * This function returns the channel number of the primary 20MHz channel. For - * 20MHz channels this is just the channel number. For 40MHz or wider channels - * it is the primary 20MHz channel specified by the chanspec. - * - * @param chspec input chanspec - * - * @return Returns the channel number of the primary 20MHz channel - */ -extern uint8 wf_chspec_ctlchan(chanspec_t chspec); - -/* - * Return the bandwidth string. - * - * This function returns the bandwidth string for the passed chanspec. - * - * @param chspec input chanspec - * - * @return Returns the bandwidth string - */ -extern const char *wf_chspec_to_bw_str(chanspec_t chspec); - -/** - * Return the primary (control) chanspec. - * - * This function returns the chanspec of the primary 20MHz channel. For 20MHz - * channels this is just the chanspec. For 40MHz or wider channels it is the - * chanspec of the primary 20MHZ channel specified by the chanspec. - * - * @param chspec input chanspec - * - * @return Returns the chanspec of the primary 20MHz channel - */ -extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec); - -/** - * Return a channel number corresponding to a frequency. - * - * This function returns the chanspec for the primary 40MHz of an 80MHz channel. - * The control sideband specifies the same 20MHz channel that the 80MHz channel is using - * as the primary 20MHz channel. - */ -extern chanspec_t wf_chspec_primary40_chspec(chanspec_t chspec); - -/* - * Return the channel number for a given frequency and base frequency. - * The returned channel number is relative to the given base frequency. - * If the given base frequency is zero, a base frequency of 5 GHz is assumed for - * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz. - * - * Frequency is specified in MHz. - * The base frequency is specified as (start_factor * 500 kHz). - * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for - * 2.4 GHz and 5 GHz bands. - * - * The returned channel will be in the range [1, 14] in the 2.4 GHz band - * and [0, 200] otherwise. - * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the - * frequency is not a 2.4 GHz channel, or if the frequency is not and even - * multiple of 5 MHz from the base frequency to the base plus 1 GHz. - * - * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 - * - * @param freq frequency in MHz - * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz - * - * @return Returns a channel number - * - * @see WF_CHAN_FACTOR_2_4_G - * @see WF_CHAN_FACTOR_5_G - */ -extern int wf_mhz2channel(uint freq, uint start_factor); - -/** - * Return the center frequency in MHz of the given channel and base frequency. - * - * Return the center frequency in MHz of the given channel and base frequency. - * The channel number is interpreted relative to the given base frequency. - * - * The valid channel range is [1, 14] in the 2.4 GHz band and [0, 200] otherwise. - * The base frequency is specified as (start_factor * 500 kHz). - * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for - * 2.4 GHz and 5 GHz bands. - * The channel range of [1, 14] is only checked for a start_factor of - * WF_CHAN_FACTOR_2_4_G (4814). - * Odd start_factors produce channels on .5 MHz boundaries, in which case - * the answer is rounded down to an integral MHz. - * -1 is returned for an out of range channel. - * - * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2 - * - * @param channel input channel number - * @param start_factor base frequency in 500 kHz units, e.g. 10000 for 5 GHz - * - * @return Returns a frequency in MHz - * - * @see WF_CHAN_FACTOR_2_4_G - * @see WF_CHAN_FACTOR_5_G - */ -extern int wf_channel2mhz(uint channel, uint start_factor); - -/** - * Returns the chanspec 80Mhz channel corresponding to the following input - * parameters - * - * primary_channel - primary 20Mhz channel - * center_channel - center frequecny of the 80Mhz channel - * - * The center_channel can be one of {42, 58, 106, 122, 138, 155} - * - * returns INVCHANSPEC in case of error - */ -extern chanspec_t wf_chspec_80(uint8 center_channel, uint8 primary_channel); - -/** - * Convert ctl chan and bw to chanspec - * - * @param ctl_ch channel - * @param bw bandwidth - * - * @return > 0 if successful or 0 otherwise - * - */ -extern uint16 wf_channel2chspec(uint ctl_ch, uint bw); - -extern uint wf_channel2freq(uint channel); -extern uint wf_freq2channel(uint freq); - -/* - * Returns the 80+80 MHz chanspec corresponding to the following input parameters - * - * primary_20mhz - Primary 20 MHz channel - * chan0_80MHz - center channel number of one frequency segment - * chan1_80MHz - center channel number of the other frequency segment - * - * Parameters chan0_80MHz and chan1_80MHz are channel numbers in {42, 58, 106, 122, 138, 155}. - * The primary channel must be contained in one of the 80MHz channels. This routine - * will determine which frequency segment is the primary 80 MHz segment. - * - * Returns INVCHANSPEC in case of error. - * - * Refer to IEEE802.11ac section 22.3.14 "Channelization". - */ -extern chanspec_t wf_chspec_get8080_chspec(uint8 primary_20mhz, - uint8 chan0_80Mhz, uint8 chan1_80Mhz); - -/* - * Returns the primary 80 Mhz channel for the provided chanspec - * - * chanspec - Input chanspec for which the 80MHz primary channel has to be retrieved - * - * returns -1 in case the provided channel is 20/40 Mhz chanspec - */ -extern uint8 wf_chspec_primary80_channel(chanspec_t chanspec); - -/* - * Returns the secondary 80 Mhz channel for the provided chanspec - * - * chanspec - Input chanspec for which the 80MHz secondary channel has to be retrieved - * - * returns -1 in case the provided channel is 20/40 Mhz chanspec - */ -extern uint8 wf_chspec_secondary80_channel(chanspec_t chanspec); - -/* - * This function returns the chanspec for the primary 80MHz of an 160MHz or 80+80 channel. - */ -extern chanspec_t wf_chspec_primary80_chspec(chanspec_t chspec); - -#ifdef WL11AC_80P80 -/* - * This function returns the centre chanel for the given chanspec. - * In case of 80+80 chanspec it returns the primary 80 Mhz centre channel - */ -extern uint8 wf_chspec_channel(chanspec_t chspec); -#endif -extern chanspec_t wf_channel_create_chspec_frm_opclass(uint8 opclass, uint8 channel); -extern int wf_channel_create_opclass_frm_chspec(chanspec_t chspec); -#endif /* _bcmwifi_channels_h_ */
diff --git a/bcmdhd.1.579.77.41.x/bcmwifi_rates.h b/bcmdhd.1.579.77.41.x/bcmwifi_rates.h deleted file mode 100644 index 542055d..0000000 --- a/bcmdhd.1.579.77.41.x/bcmwifi_rates.h +++ /dev/null
@@ -1,793 +0,0 @@ -/* - * Indices for 802.11 a/b/g/n/ac 1-3 chain symmetric transmit rates - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: bcmwifi_rates.h 612483 2016-01-14 03:44:27Z $ - */ - -#ifndef _bcmwifi_rates_h_ -#define _bcmwifi_rates_h_ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - - -#define WL_RATESET_SZ_DSSS 4 -#define WL_RATESET_SZ_OFDM 8 -#define WL_RATESET_SZ_VHT_MCS 10 -#define WL_RATESET_SZ_VHT_MCS_P 12 - -#if defined(WLPROPRIETARY_11N_RATES) -#define WL_RATESET_SZ_HT_MCS WL_RATESET_SZ_VHT_MCS -#else -#define WL_RATESET_SZ_HT_MCS 8 -#endif - -#define WL_RATESET_SZ_HT_IOCTL 8 /* MAC histogram, compatibility with wl utility */ - -#define WL_TX_CHAINS_MAX 4 - -#define WL_RATE_DISABLED (-128) /* Power value corresponding to unsupported rate */ - -/* Transmit channel bandwidths */ -typedef enum wl_tx_bw { - WL_TX_BW_20, - WL_TX_BW_40, - WL_TX_BW_80, - WL_TX_BW_20IN40, - WL_TX_BW_20IN80, - WL_TX_BW_40IN80, - WL_TX_BW_160, - WL_TX_BW_20IN160, - WL_TX_BW_40IN160, - WL_TX_BW_80IN160, - WL_TX_BW_ALL, - WL_TX_BW_8080, - WL_TX_BW_8080CHAN2, - WL_TX_BW_20IN8080, - WL_TX_BW_40IN8080, - WL_TX_BW_80IN8080, - WL_TX_BW_2P5, - WL_TX_BW_5, - WL_TX_BW_10 -} wl_tx_bw_t; - - -/* - * Transmit modes. - * Not all modes are listed here, only those required for disambiguation. e.g. SPEXP is not listed - */ -typedef enum wl_tx_mode { - WL_TX_MODE_NONE, - WL_TX_MODE_STBC, - WL_TX_MODE_CDD, - WL_TX_MODE_TXBF, - WL_NUM_TX_MODES -} wl_tx_mode_t; - - -/* Number of transmit chains */ -typedef enum wl_tx_chains { - WL_TX_CHAINS_1 = 1, - WL_TX_CHAINS_2, - WL_TX_CHAINS_3, - WL_TX_CHAINS_4 -} wl_tx_chains_t; - - -/* Number of transmit streams */ -typedef enum wl_tx_nss { - WL_TX_NSS_1 = 1, - WL_TX_NSS_2, - WL_TX_NSS_3, - WL_TX_NSS_4 -} wl_tx_nss_t; - - -/* This enum maps each rate to a CLM index */ - -typedef enum clm_rates { - /************ - * 1 chain * - ************ - */ - - /* 1 Stream */ - WL_RATE_1X1_DSSS_1 = 0, - WL_RATE_1X1_DSSS_2 = 1, - WL_RATE_1X1_DSSS_5_5 = 2, - WL_RATE_1X1_DSSS_11 = 3, - - WL_RATE_1X1_OFDM_6 = 4, - WL_RATE_1X1_OFDM_9 = 5, - WL_RATE_1X1_OFDM_12 = 6, - WL_RATE_1X1_OFDM_18 = 7, - WL_RATE_1X1_OFDM_24 = 8, - WL_RATE_1X1_OFDM_36 = 9, - WL_RATE_1X1_OFDM_48 = 10, - WL_RATE_1X1_OFDM_54 = 11, - - WL_RATE_1X1_MCS0 = 12, - WL_RATE_1X1_MCS1 = 13, - WL_RATE_1X1_MCS2 = 14, - WL_RATE_1X1_MCS3 = 15, - WL_RATE_1X1_MCS4 = 16, - WL_RATE_1X1_MCS5 = 17, - WL_RATE_1X1_MCS6 = 18, - WL_RATE_1X1_MCS7 = 19, - WL_RATE_P_1X1_MCS87 = 20, - WL_RATE_P_1X1_MCS88 = 21, - - WL_RATE_1X1_VHT0SS1 = 12, - WL_RATE_1X1_VHT1SS1 = 13, - WL_RATE_1X1_VHT2SS1 = 14, - WL_RATE_1X1_VHT3SS1 = 15, - WL_RATE_1X1_VHT4SS1 = 16, - WL_RATE_1X1_VHT5SS1 = 17, - WL_RATE_1X1_VHT6SS1 = 18, - WL_RATE_1X1_VHT7SS1 = 19, - WL_RATE_1X1_VHT8SS1 = 20, - WL_RATE_1X1_VHT9SS1 = 21, - WL_RATE_P_1X1_VHT10SS1 = 22, - WL_RATE_P_1X1_VHT11SS1 = 23, - - - /************ - * 2 chains * - ************ - */ - - /* 1 Stream expanded + 1 */ - WL_RATE_1X2_DSSS_1 = 24, - WL_RATE_1X2_DSSS_2 = 25, - WL_RATE_1X2_DSSS_5_5 = 26, - WL_RATE_1X2_DSSS_11 = 27, - - WL_RATE_1X2_CDD_OFDM_6 = 28, - WL_RATE_1X2_CDD_OFDM_9 = 29, - WL_RATE_1X2_CDD_OFDM_12 = 30, - WL_RATE_1X2_CDD_OFDM_18 = 31, - WL_RATE_1X2_CDD_OFDM_24 = 32, - WL_RATE_1X2_CDD_OFDM_36 = 33, - WL_RATE_1X2_CDD_OFDM_48 = 34, - WL_RATE_1X2_CDD_OFDM_54 = 35, - - WL_RATE_1X2_CDD_MCS0 = 36, - WL_RATE_1X2_CDD_MCS1 = 37, - WL_RATE_1X2_CDD_MCS2 = 38, - WL_RATE_1X2_CDD_MCS3 = 39, - WL_RATE_1X2_CDD_MCS4 = 40, - WL_RATE_1X2_CDD_MCS5 = 41, - WL_RATE_1X2_CDD_MCS6 = 42, - WL_RATE_1X2_CDD_MCS7 = 43, - WL_RATE_P_1X2_CDD_MCS87 = 44, - WL_RATE_P_1X2_CDD_MCS88 = 45, - - WL_RATE_1X2_VHT0SS1 = 36, - WL_RATE_1X2_VHT1SS1 = 37, - WL_RATE_1X2_VHT2SS1 = 38, - WL_RATE_1X2_VHT3SS1 = 39, - WL_RATE_1X2_VHT4SS1 = 40, - WL_RATE_1X2_VHT5SS1 = 41, - WL_RATE_1X2_VHT6SS1 = 42, - WL_RATE_1X2_VHT7SS1 = 43, - WL_RATE_1X2_VHT8SS1 = 44, - WL_RATE_1X2_VHT9SS1 = 45, - WL_RATE_P_1X2_VHT10SS1 = 46, - WL_RATE_P_1X2_VHT11SS1 = 47, - - /* 2 Streams */ - WL_RATE_2X2_STBC_MCS0 = 48, - WL_RATE_2X2_STBC_MCS1 = 49, - WL_RATE_2X2_STBC_MCS2 = 50, - WL_RATE_2X2_STBC_MCS3 = 51, - WL_RATE_2X2_STBC_MCS4 = 52, - WL_RATE_2X2_STBC_MCS5 = 53, - WL_RATE_2X2_STBC_MCS6 = 54, - WL_RATE_2X2_STBC_MCS7 = 55, - WL_RATE_P_2X2_STBC_MCS87 = 56, - WL_RATE_P_2X2_STBC_MCS88 = 57, - - WL_RATE_2X2_STBC_VHT0SS1 = 48, - WL_RATE_2X2_STBC_VHT1SS1 = 49, - WL_RATE_2X2_STBC_VHT2SS1 = 50, - WL_RATE_2X2_STBC_VHT3SS1 = 51, - WL_RATE_2X2_STBC_VHT4SS1 = 52, - WL_RATE_2X2_STBC_VHT5SS1 = 53, - WL_RATE_2X2_STBC_VHT6SS1 = 54, - WL_RATE_2X2_STBC_VHT7SS1 = 55, - WL_RATE_2X2_STBC_VHT8SS1 = 56, - WL_RATE_2X2_STBC_VHT9SS1 = 57, - WL_RATE_P_2X2_STBC_VHT10SS1 = 58, - WL_RATE_P_2X2_STBC_VHT11SS1 = 59, - - WL_RATE_2X2_SDM_MCS8 = 60, - WL_RATE_2X2_SDM_MCS9 = 61, - WL_RATE_2X2_SDM_MCS10 = 62, - WL_RATE_2X2_SDM_MCS11 = 63, - WL_RATE_2X2_SDM_MCS12 = 64, - WL_RATE_2X2_SDM_MCS13 = 65, - WL_RATE_2X2_SDM_MCS14 = 66, - WL_RATE_2X2_SDM_MCS15 = 67, - WL_RATE_P_2X2_SDM_MCS99 = 68, - WL_RATE_P_2X2_SDM_MCS100 = 69, - - WL_RATE_2X2_VHT0SS2 = 60, - WL_RATE_2X2_VHT1SS2 = 61, - WL_RATE_2X2_VHT2SS2 = 62, - WL_RATE_2X2_VHT3SS2 = 63, - WL_RATE_2X2_VHT4SS2 = 64, - WL_RATE_2X2_VHT5SS2 = 65, - WL_RATE_2X2_VHT6SS2 = 66, - WL_RATE_2X2_VHT7SS2 = 67, - WL_RATE_2X2_VHT8SS2 = 68, - WL_RATE_2X2_VHT9SS2 = 69, - WL_RATE_P_2X2_VHT10SS2 = 70, - WL_RATE_P_2X2_VHT11SS2 = 71, - - /**************************** - * TX Beamforming, 2 chains * - **************************** - */ - - /* 1 Stream expanded + 1 */ - WL_RATE_1X2_TXBF_OFDM_6 = 72, - WL_RATE_1X2_TXBF_OFDM_9 = 73, - WL_RATE_1X2_TXBF_OFDM_12 = 74, - WL_RATE_1X2_TXBF_OFDM_18 = 75, - WL_RATE_1X2_TXBF_OFDM_24 = 76, - WL_RATE_1X2_TXBF_OFDM_36 = 77, - WL_RATE_1X2_TXBF_OFDM_48 = 78, - WL_RATE_1X2_TXBF_OFDM_54 = 79, - - WL_RATE_1X2_TXBF_MCS0 = 80, - WL_RATE_1X2_TXBF_MCS1 = 81, - WL_RATE_1X2_TXBF_MCS2 = 82, - WL_RATE_1X2_TXBF_MCS3 = 83, - WL_RATE_1X2_TXBF_MCS4 = 84, - WL_RATE_1X2_TXBF_MCS5 = 85, - WL_RATE_1X2_TXBF_MCS6 = 86, - WL_RATE_1X2_TXBF_MCS7 = 87, - WL_RATE_P_1X2_TXBF_MCS87 = 88, - WL_RATE_P_1X2_TXBF_MCS88 = 89, - - WL_RATE_1X2_TXBF_VHT0SS1 = 80, - WL_RATE_1X2_TXBF_VHT1SS1 = 81, - WL_RATE_1X2_TXBF_VHT2SS1 = 82, - WL_RATE_1X2_TXBF_VHT3SS1 = 83, - WL_RATE_1X2_TXBF_VHT4SS1 = 84, - WL_RATE_1X2_TXBF_VHT5SS1 = 85, - WL_RATE_1X2_TXBF_VHT6SS1 = 86, - WL_RATE_1X2_TXBF_VHT7SS1 = 87, - WL_RATE_1X2_TXBF_VHT8SS1 = 88, - WL_RATE_1X2_TXBF_VHT9SS1 = 89, - WL_RATE_P_1X2_TXBF_VHT10SS1 = 90, - WL_RATE_P_1X2_TXBF_VHT11SS1 = 91, - - /* 2 Streams */ - WL_RATE_2X2_TXBF_SDM_MCS8 = 92, - WL_RATE_2X2_TXBF_SDM_MCS9 = 93, - WL_RATE_2X2_TXBF_SDM_MCS10 = 94, - WL_RATE_2X2_TXBF_SDM_MCS11 = 95, - WL_RATE_2X2_TXBF_SDM_MCS12 = 96, - WL_RATE_2X2_TXBF_SDM_MCS13 = 97, - WL_RATE_2X2_TXBF_SDM_MCS14 = 98, - WL_RATE_2X2_TXBF_SDM_MCS15 = 99, - WL_RATE_P_2X2_TXBF_SDM_MCS99 = 100, - WL_RATE_P_2X2_TXBF_SDM_MCS100 = 101, - - WL_RATE_2X2_TXBF_VHT0SS2 = 92, - WL_RATE_2X2_TXBF_VHT1SS2 = 93, - WL_RATE_2X2_TXBF_VHT2SS2 = 94, - WL_RATE_2X2_TXBF_VHT3SS2 = 95, - WL_RATE_2X2_TXBF_VHT4SS2 = 96, - WL_RATE_2X2_TXBF_VHT5SS2 = 97, - WL_RATE_2X2_TXBF_VHT6SS2 = 98, - WL_RATE_2X2_TXBF_VHT7SS2 = 99, - WL_RATE_2X2_TXBF_VHT8SS2 = 100, - WL_RATE_2X2_TXBF_VHT9SS2 = 101, - WL_RATE_P_2X2_TXBF_VHT10SS2 = 102, - WL_RATE_P_2X2_TXBF_VHT11SS2 = 103, - - - /************ - * 3 chains * - ************ - */ - - /* 1 Stream expanded + 2 */ - WL_RATE_1X3_DSSS_1 = 104, - WL_RATE_1X3_DSSS_2 = 105, - WL_RATE_1X3_DSSS_5_5 = 106, - WL_RATE_1X3_DSSS_11 = 107, - - WL_RATE_1X3_CDD_OFDM_6 = 108, - WL_RATE_1X3_CDD_OFDM_9 = 109, - WL_RATE_1X3_CDD_OFDM_12 = 110, - WL_RATE_1X3_CDD_OFDM_18 = 111, - WL_RATE_1X3_CDD_OFDM_24 = 112, - WL_RATE_1X3_CDD_OFDM_36 = 113, - WL_RATE_1X3_CDD_OFDM_48 = 114, - WL_RATE_1X3_CDD_OFDM_54 = 115, - - WL_RATE_1X3_CDD_MCS0 = 116, - WL_RATE_1X3_CDD_MCS1 = 117, - WL_RATE_1X3_CDD_MCS2 = 118, - WL_RATE_1X3_CDD_MCS3 = 119, - WL_RATE_1X3_CDD_MCS4 = 120, - WL_RATE_1X3_CDD_MCS5 = 121, - WL_RATE_1X3_CDD_MCS6 = 122, - WL_RATE_1X3_CDD_MCS7 = 123, - WL_RATE_P_1X3_CDD_MCS87 = 124, - WL_RATE_P_1X3_CDD_MCS88 = 125, - - WL_RATE_1X3_VHT0SS1 = 116, - WL_RATE_1X3_VHT1SS1 = 117, - WL_RATE_1X3_VHT2SS1 = 118, - WL_RATE_1X3_VHT3SS1 = 119, - WL_RATE_1X3_VHT4SS1 = 120, - WL_RATE_1X3_VHT5SS1 = 121, - WL_RATE_1X3_VHT6SS1 = 122, - WL_RATE_1X3_VHT7SS1 = 123, - WL_RATE_1X3_VHT8SS1 = 124, - WL_RATE_1X3_VHT9SS1 = 125, - WL_RATE_P_1X3_VHT10SS1 = 126, - WL_RATE_P_1X3_VHT11SS1 = 127, - - /* 2 Streams expanded + 1 */ - WL_RATE_2X3_STBC_MCS0 = 128, - WL_RATE_2X3_STBC_MCS1 = 129, - WL_RATE_2X3_STBC_MCS2 = 130, - WL_RATE_2X3_STBC_MCS3 = 131, - WL_RATE_2X3_STBC_MCS4 = 132, - WL_RATE_2X3_STBC_MCS5 = 133, - WL_RATE_2X3_STBC_MCS6 = 134, - WL_RATE_2X3_STBC_MCS7 = 135, - WL_RATE_P_2X3_STBC_MCS87 = 136, - WL_RATE_P_2X3_STBC_MCS88 = 137, - - WL_RATE_2X3_STBC_VHT0SS1 = 128, - WL_RATE_2X3_STBC_VHT1SS1 = 129, - WL_RATE_2X3_STBC_VHT2SS1 = 130, - WL_RATE_2X3_STBC_VHT3SS1 = 131, - WL_RATE_2X3_STBC_VHT4SS1 = 132, - WL_RATE_2X3_STBC_VHT5SS1 = 133, - WL_RATE_2X3_STBC_VHT6SS1 = 134, - WL_RATE_2X3_STBC_VHT7SS1 = 135, - WL_RATE_2X3_STBC_VHT8SS1 = 136, - WL_RATE_2X3_STBC_VHT9SS1 = 137, - WL_RATE_P_2X3_STBC_VHT10SS1 = 138, - WL_RATE_P_2X3_STBC_VHT11SS1 = 139, - - WL_RATE_2X3_SDM_MCS8 = 140, - WL_RATE_2X3_SDM_MCS9 = 141, - WL_RATE_2X3_SDM_MCS10 = 142, - WL_RATE_2X3_SDM_MCS11 = 143, - WL_RATE_2X3_SDM_MCS12 = 144, - WL_RATE_2X3_SDM_MCS13 = 145, - WL_RATE_2X3_SDM_MCS14 = 146, - WL_RATE_2X3_SDM_MCS15 = 147, - WL_RATE_P_2X3_SDM_MCS99 = 148, - WL_RATE_P_2X3_SDM_MCS100 = 149, - - WL_RATE_2X3_VHT0SS2 = 140, - WL_RATE_2X3_VHT1SS2 = 141, - WL_RATE_2X3_VHT2SS2 = 142, - WL_RATE_2X3_VHT3SS2 = 143, - WL_RATE_2X3_VHT4SS2 = 144, - WL_RATE_2X3_VHT5SS2 = 145, - WL_RATE_2X3_VHT6SS2 = 146, - WL_RATE_2X3_VHT7SS2 = 147, - WL_RATE_2X3_VHT8SS2 = 148, - WL_RATE_2X3_VHT9SS2 = 149, - WL_RATE_P_2X3_VHT10SS2 = 150, - WL_RATE_P_2X3_VHT11SS2 = 151, - - /* 3 Streams */ - WL_RATE_3X3_SDM_MCS16 = 152, - WL_RATE_3X3_SDM_MCS17 = 153, - WL_RATE_3X3_SDM_MCS18 = 154, - WL_RATE_3X3_SDM_MCS19 = 155, - WL_RATE_3X3_SDM_MCS20 = 156, - WL_RATE_3X3_SDM_MCS21 = 157, - WL_RATE_3X3_SDM_MCS22 = 158, - WL_RATE_3X3_SDM_MCS23 = 159, - WL_RATE_P_3X3_SDM_MCS101 = 160, - WL_RATE_P_3X3_SDM_MCS102 = 161, - - WL_RATE_3X3_VHT0SS3 = 152, - WL_RATE_3X3_VHT1SS3 = 153, - WL_RATE_3X3_VHT2SS3 = 154, - WL_RATE_3X3_VHT3SS3 = 155, - WL_RATE_3X3_VHT4SS3 = 156, - WL_RATE_3X3_VHT5SS3 = 157, - WL_RATE_3X3_VHT6SS3 = 158, - WL_RATE_3X3_VHT7SS3 = 159, - WL_RATE_3X3_VHT8SS3 = 160, - WL_RATE_3X3_VHT9SS3 = 161, - WL_RATE_P_3X3_VHT10SS3 = 162, - WL_RATE_P_3X3_VHT11SS3 = 163, - - - /**************************** - * TX Beamforming, 3 chains * - **************************** - */ - - /* 1 Stream expanded + 2 */ - WL_RATE_1X3_TXBF_OFDM_6 = 164, - WL_RATE_1X3_TXBF_OFDM_9 = 165, - WL_RATE_1X3_TXBF_OFDM_12 = 166, - WL_RATE_1X3_TXBF_OFDM_18 = 167, - WL_RATE_1X3_TXBF_OFDM_24 = 168, - WL_RATE_1X3_TXBF_OFDM_36 = 169, - WL_RATE_1X3_TXBF_OFDM_48 = 170, - WL_RATE_1X3_TXBF_OFDM_54 = 171, - - WL_RATE_1X3_TXBF_MCS0 = 172, - WL_RATE_1X3_TXBF_MCS1 = 173, - WL_RATE_1X3_TXBF_MCS2 = 174, - WL_RATE_1X3_TXBF_MCS3 = 175, - WL_RATE_1X3_TXBF_MCS4 = 176, - WL_RATE_1X3_TXBF_MCS5 = 177, - WL_RATE_1X3_TXBF_MCS6 = 178, - WL_RATE_1X3_TXBF_MCS7 = 179, - WL_RATE_P_1X3_TXBF_MCS87 = 180, - WL_RATE_P_1X3_TXBF_MCS88 = 181, - - WL_RATE_1X3_TXBF_VHT0SS1 = 172, - WL_RATE_1X3_TXBF_VHT1SS1 = 173, - WL_RATE_1X3_TXBF_VHT2SS1 = 174, - WL_RATE_1X3_TXBF_VHT3SS1 = 175, - WL_RATE_1X3_TXBF_VHT4SS1 = 176, - WL_RATE_1X3_TXBF_VHT5SS1 = 177, - WL_RATE_1X3_TXBF_VHT6SS1 = 178, - WL_RATE_1X3_TXBF_VHT7SS1 = 179, - WL_RATE_1X3_TXBF_VHT8SS1 = 180, - WL_RATE_1X3_TXBF_VHT9SS1 = 181, - WL_RATE_P_1X3_TXBF_VHT10SS1 = 182, - WL_RATE_P_1X3_TXBF_VHT11SS1 = 183, - - /* 2 Streams expanded + 1 */ - WL_RATE_2X3_TXBF_SDM_MCS8 = 184, - WL_RATE_2X3_TXBF_SDM_MCS9 = 185, - WL_RATE_2X3_TXBF_SDM_MCS10 = 186, - WL_RATE_2X3_TXBF_SDM_MCS11 = 187, - WL_RATE_2X3_TXBF_SDM_MCS12 = 188, - WL_RATE_2X3_TXBF_SDM_MCS13 = 189, - WL_RATE_2X3_TXBF_SDM_MCS14 = 190, - WL_RATE_2X3_TXBF_SDM_MCS15 = 191, - WL_RATE_P_2X3_TXBF_SDM_MCS99 = 192, - WL_RATE_P_2X3_TXBF_SDM_MCS100 = 193, - - WL_RATE_2X3_TXBF_VHT0SS2 = 184, - WL_RATE_2X3_TXBF_VHT1SS2 = 185, - WL_RATE_2X3_TXBF_VHT2SS2 = 186, - WL_RATE_2X3_TXBF_VHT3SS2 = 187, - WL_RATE_2X3_TXBF_VHT4SS2 = 188, - WL_RATE_2X3_TXBF_VHT5SS2 = 189, - WL_RATE_2X3_TXBF_VHT6SS2 = 190, - WL_RATE_2X3_TXBF_VHT7SS2 = 191, - WL_RATE_2X3_TXBF_VHT8SS2 = 192, - WL_RATE_2X3_TXBF_VHT9SS2 = 193, - WL_RATE_P_2X3_TXBF_VHT10SS2 = 194, - WL_RATE_P_2X3_TXBF_VHT11SS2 = 195, - - /* 3 Streams */ - WL_RATE_3X3_TXBF_SDM_MCS16 = 196, - WL_RATE_3X3_TXBF_SDM_MCS17 = 197, - WL_RATE_3X3_TXBF_SDM_MCS18 = 198, - WL_RATE_3X3_TXBF_SDM_MCS19 = 199, - WL_RATE_3X3_TXBF_SDM_MCS20 = 200, - WL_RATE_3X3_TXBF_SDM_MCS21 = 201, - WL_RATE_3X3_TXBF_SDM_MCS22 = 202, - WL_RATE_3X3_TXBF_SDM_MCS23 = 203, - WL_RATE_P_3X3_TXBF_SDM_MCS101 = 204, - WL_RATE_P_3X3_TXBF_SDM_MCS102 = 205, - - WL_RATE_3X3_TXBF_VHT0SS3 = 196, - WL_RATE_3X3_TXBF_VHT1SS3 = 197, - WL_RATE_3X3_TXBF_VHT2SS3 = 198, - WL_RATE_3X3_TXBF_VHT3SS3 = 199, - WL_RATE_3X3_TXBF_VHT4SS3 = 200, - WL_RATE_3X3_TXBF_VHT5SS3 = 201, - WL_RATE_3X3_TXBF_VHT6SS3 = 202, - WL_RATE_3X3_TXBF_VHT7SS3 = 203, - WL_RATE_3X3_TXBF_VHT8SS3 = 204, - WL_RATE_3X3_TXBF_VHT9SS3 = 205, - WL_RATE_P_3X3_TXBF_VHT10SS3 = 206, - WL_RATE_P_3X3_TXBF_VHT11SS3 = 207, - - - /************ - * 4 chains * - ************ - */ - - /* 1 Stream expanded + 3 */ - WL_RATE_1X4_DSSS_1 = 208, - WL_RATE_1X4_DSSS_2 = 209, - WL_RATE_1X4_DSSS_5_5 = 210, - WL_RATE_1X4_DSSS_11 = 211, - - WL_RATE_1X4_CDD_OFDM_6 = 212, - WL_RATE_1X4_CDD_OFDM_9 = 213, - WL_RATE_1X4_CDD_OFDM_12 = 214, - WL_RATE_1X4_CDD_OFDM_18 = 215, - WL_RATE_1X4_CDD_OFDM_24 = 216, - WL_RATE_1X4_CDD_OFDM_36 = 217, - WL_RATE_1X4_CDD_OFDM_48 = 218, - WL_RATE_1X4_CDD_OFDM_54 = 219, - - WL_RATE_1X4_CDD_MCS0 = 220, - WL_RATE_1X4_CDD_MCS1 = 221, - WL_RATE_1X4_CDD_MCS2 = 222, - WL_RATE_1X4_CDD_MCS3 = 223, - WL_RATE_1X4_CDD_MCS4 = 224, - WL_RATE_1X4_CDD_MCS5 = 225, - WL_RATE_1X4_CDD_MCS6 = 226, - WL_RATE_1X4_CDD_MCS7 = 227, - WL_RATE_P_1X4_CDD_MCS87 = 228, - WL_RATE_P_1X4_CDD_MCS88 = 229, - - WL_RATE_1X4_VHT0SS1 = 220, - WL_RATE_1X4_VHT1SS1 = 221, - WL_RATE_1X4_VHT2SS1 = 222, - WL_RATE_1X4_VHT3SS1 = 223, - WL_RATE_1X4_VHT4SS1 = 224, - WL_RATE_1X4_VHT5SS1 = 225, - WL_RATE_1X4_VHT6SS1 = 226, - WL_RATE_1X4_VHT7SS1 = 227, - WL_RATE_1X4_VHT8SS1 = 228, - WL_RATE_1X4_VHT9SS1 = 229, - WL_RATE_P_1X4_VHT10SS1 = 230, - WL_RATE_P_1X4_VHT11SS1 = 231, - - /* 2 Streams expanded + 2 */ - WL_RATE_2X4_STBC_MCS0 = 232, - WL_RATE_2X4_STBC_MCS1 = 233, - WL_RATE_2X4_STBC_MCS2 = 234, - WL_RATE_2X4_STBC_MCS3 = 235, - WL_RATE_2X4_STBC_MCS4 = 236, - WL_RATE_2X4_STBC_MCS5 = 237, - WL_RATE_2X4_STBC_MCS6 = 238, - WL_RATE_2X4_STBC_MCS7 = 239, - WL_RATE_P_2X4_STBC_MCS87 = 240, - WL_RATE_P_2X4_STBC_MCS88 = 241, - - WL_RATE_2X4_STBC_VHT0SS1 = 232, - WL_RATE_2X4_STBC_VHT1SS1 = 233, - WL_RATE_2X4_STBC_VHT2SS1 = 234, - WL_RATE_2X4_STBC_VHT3SS1 = 235, - WL_RATE_2X4_STBC_VHT4SS1 = 236, - WL_RATE_2X4_STBC_VHT5SS1 = 237, - WL_RATE_2X4_STBC_VHT6SS1 = 238, - WL_RATE_2X4_STBC_VHT7SS1 = 239, - WL_RATE_2X4_STBC_VHT8SS1 = 240, - WL_RATE_2X4_STBC_VHT9SS1 = 241, - WL_RATE_P_2X4_STBC_VHT10SS1 = 242, - WL_RATE_P_2X4_STBC_VHT11SS1 = 243, - - WL_RATE_2X4_SDM_MCS8 = 244, - WL_RATE_2X4_SDM_MCS9 = 245, - WL_RATE_2X4_SDM_MCS10 = 246, - WL_RATE_2X4_SDM_MCS11 = 247, - WL_RATE_2X4_SDM_MCS12 = 248, - WL_RATE_2X4_SDM_MCS13 = 249, - WL_RATE_2X4_SDM_MCS14 = 250, - WL_RATE_2X4_SDM_MCS15 = 251, - WL_RATE_P_2X4_SDM_MCS99 = 252, - WL_RATE_P_2X4_SDM_MCS100 = 253, - - WL_RATE_2X4_VHT0SS2 = 244, - WL_RATE_2X4_VHT1SS2 = 245, - WL_RATE_2X4_VHT2SS2 = 246, - WL_RATE_2X4_VHT3SS2 = 247, - WL_RATE_2X4_VHT4SS2 = 248, - WL_RATE_2X4_VHT5SS2 = 249, - WL_RATE_2X4_VHT6SS2 = 250, - WL_RATE_2X4_VHT7SS2 = 251, - WL_RATE_2X4_VHT8SS2 = 252, - WL_RATE_2X4_VHT9SS2 = 253, - WL_RATE_P_2X4_VHT10SS2 = 254, - WL_RATE_P_2X4_VHT11SS2 = 255, - - /* 3 Streams expanded + 1 */ - WL_RATE_3X4_SDM_MCS16 = 256, - WL_RATE_3X4_SDM_MCS17 = 257, - WL_RATE_3X4_SDM_MCS18 = 258, - WL_RATE_3X4_SDM_MCS19 = 259, - WL_RATE_3X4_SDM_MCS20 = 260, - WL_RATE_3X4_SDM_MCS21 = 261, - WL_RATE_3X4_SDM_MCS22 = 262, - WL_RATE_3X4_SDM_MCS23 = 263, - WL_RATE_P_3X4_SDM_MCS101 = 264, - WL_RATE_P_3X4_SDM_MCS102 = 265, - - WL_RATE_3X4_VHT0SS3 = 256, - WL_RATE_3X4_VHT1SS3 = 257, - WL_RATE_3X4_VHT2SS3 = 258, - WL_RATE_3X4_VHT3SS3 = 259, - WL_RATE_3X4_VHT4SS3 = 260, - WL_RATE_3X4_VHT5SS3 = 261, - WL_RATE_3X4_VHT6SS3 = 262, - WL_RATE_3X4_VHT7SS3 = 263, - WL_RATE_3X4_VHT8SS3 = 264, - WL_RATE_3X4_VHT9SS3 = 265, - WL_RATE_P_3X4_VHT10SS3 = 266, - WL_RATE_P_3X4_VHT11SS3 = 267, - - - /* 4 Streams */ - WL_RATE_4X4_SDM_MCS24 = 268, - WL_RATE_4X4_SDM_MCS25 = 269, - WL_RATE_4X4_SDM_MCS26 = 270, - WL_RATE_4X4_SDM_MCS27 = 271, - WL_RATE_4X4_SDM_MCS28 = 272, - WL_RATE_4X4_SDM_MCS29 = 273, - WL_RATE_4X4_SDM_MCS30 = 274, - WL_RATE_4X4_SDM_MCS31 = 275, - WL_RATE_P_4X4_SDM_MCS103 = 276, - WL_RATE_P_4X4_SDM_MCS104 = 277, - - WL_RATE_4X4_VHT0SS4 = 268, - WL_RATE_4X4_VHT1SS4 = 269, - WL_RATE_4X4_VHT2SS4 = 270, - WL_RATE_4X4_VHT3SS4 = 271, - WL_RATE_4X4_VHT4SS4 = 272, - WL_RATE_4X4_VHT5SS4 = 273, - WL_RATE_4X4_VHT6SS4 = 274, - WL_RATE_4X4_VHT7SS4 = 275, - WL_RATE_4X4_VHT8SS4 = 276, - WL_RATE_4X4_VHT9SS4 = 277, - WL_RATE_P_4X4_VHT10SS4 = 278, - WL_RATE_P_4X4_VHT11SS4 = 279, - - - /**************************** - * TX Beamforming, 4 chains * - **************************** - */ - - /* 1 Stream expanded + 3 */ - WL_RATE_1X4_TXBF_OFDM_6 = 280, - WL_RATE_1X4_TXBF_OFDM_9 = 281, - WL_RATE_1X4_TXBF_OFDM_12 = 282, - WL_RATE_1X4_TXBF_OFDM_18 = 283, - WL_RATE_1X4_TXBF_OFDM_24 = 284, - WL_RATE_1X4_TXBF_OFDM_36 = 285, - WL_RATE_1X4_TXBF_OFDM_48 = 286, - WL_RATE_1X4_TXBF_OFDM_54 = 287, - - WL_RATE_1X4_TXBF_MCS0 = 288, - WL_RATE_1X4_TXBF_MCS1 = 289, - WL_RATE_1X4_TXBF_MCS2 = 290, - WL_RATE_1X4_TXBF_MCS3 = 291, - WL_RATE_1X4_TXBF_MCS4 = 292, - WL_RATE_1X4_TXBF_MCS5 = 293, - WL_RATE_1X4_TXBF_MCS6 = 294, - WL_RATE_1X4_TXBF_MCS7 = 295, - WL_RATE_P_1X4_TXBF_MCS87 = 296, - WL_RATE_P_1X4_TXBF_MCS88 = 297, - - WL_RATE_1X4_TXBF_VHT0SS1 = 288, - WL_RATE_1X4_TXBF_VHT1SS1 = 289, - WL_RATE_1X4_TXBF_VHT2SS1 = 290, - WL_RATE_1X4_TXBF_VHT3SS1 = 291, - WL_RATE_1X4_TXBF_VHT4SS1 = 292, - WL_RATE_1X4_TXBF_VHT5SS1 = 293, - WL_RATE_1X4_TXBF_VHT6SS1 = 294, - WL_RATE_1X4_TXBF_VHT7SS1 = 295, - WL_RATE_1X4_TXBF_VHT8SS1 = 296, - WL_RATE_1X4_TXBF_VHT9SS1 = 297, - WL_RATE_P_1X4_TXBF_VHT10SS1 = 298, - WL_RATE_P_1X4_TXBF_VHT11SS1 = 299, - - /* 2 Streams expanded + 2 */ - WL_RATE_2X4_TXBF_SDM_MCS8 = 300, - WL_RATE_2X4_TXBF_SDM_MCS9 = 301, - WL_RATE_2X4_TXBF_SDM_MCS10 = 302, - WL_RATE_2X4_TXBF_SDM_MCS11 = 303, - WL_RATE_2X4_TXBF_SDM_MCS12 = 304, - WL_RATE_2X4_TXBF_SDM_MCS13 = 305, - WL_RATE_2X4_TXBF_SDM_MCS14 = 306, - WL_RATE_2X4_TXBF_SDM_MCS15 = 307, - WL_RATE_P_2X4_TXBF_SDM_MCS99 = 308, - WL_RATE_P_2X4_TXBF_SDM_MCS100 = 309, - - WL_RATE_2X4_TXBF_VHT0SS2 = 300, - WL_RATE_2X4_TXBF_VHT1SS2 = 301, - WL_RATE_2X4_TXBF_VHT2SS2 = 302, - WL_RATE_2X4_TXBF_VHT3SS2 = 303, - WL_RATE_2X4_TXBF_VHT4SS2 = 304, - WL_RATE_2X4_TXBF_VHT5SS2 = 305, - WL_RATE_2X4_TXBF_VHT6SS2 = 306, - WL_RATE_2X4_TXBF_VHT7SS2 = 307, - WL_RATE_2X4_TXBF_VHT8SS2 = 308, - WL_RATE_2X4_TXBF_VHT9SS2 = 309, - WL_RATE_P_2X4_TXBF_VHT10SS2 = 310, - WL_RATE_P_2X4_TXBF_VHT11SS2 = 311, - - /* 3 Streams expanded + 1 */ - WL_RATE_3X4_TXBF_SDM_MCS16 = 312, - WL_RATE_3X4_TXBF_SDM_MCS17 = 313, - WL_RATE_3X4_TXBF_SDM_MCS18 = 314, - WL_RATE_3X4_TXBF_SDM_MCS19 = 315, - WL_RATE_3X4_TXBF_SDM_MCS20 = 316, - WL_RATE_3X4_TXBF_SDM_MCS21 = 317, - WL_RATE_3X4_TXBF_SDM_MCS22 = 318, - WL_RATE_3X4_TXBF_SDM_MCS23 = 319, - WL_RATE_P_3X4_TXBF_SDM_MCS101 = 320, - WL_RATE_P_3X4_TXBF_SDM_MCS102 = 321, - - WL_RATE_3X4_TXBF_VHT0SS3 = 312, - WL_RATE_3X4_TXBF_VHT1SS3 = 313, - WL_RATE_3X4_TXBF_VHT2SS3 = 314, - WL_RATE_3X4_TXBF_VHT3SS3 = 315, - WL_RATE_3X4_TXBF_VHT4SS3 = 316, - WL_RATE_3X4_TXBF_VHT5SS3 = 317, - WL_RATE_3X4_TXBF_VHT6SS3 = 318, - WL_RATE_3X4_TXBF_VHT7SS3 = 319, - WL_RATE_P_3X4_TXBF_VHT8SS3 = 320, - WL_RATE_P_3X4_TXBF_VHT9SS3 = 321, - WL_RATE_P_3X4_TXBF_VHT10SS3 = 322, - WL_RATE_P_3X4_TXBF_VHT11SS3 = 323, - - /* 4 Streams */ - WL_RATE_4X4_TXBF_SDM_MCS24 = 324, - WL_RATE_4X4_TXBF_SDM_MCS25 = 325, - WL_RATE_4X4_TXBF_SDM_MCS26 = 326, - WL_RATE_4X4_TXBF_SDM_MCS27 = 327, - WL_RATE_4X4_TXBF_SDM_MCS28 = 328, - WL_RATE_4X4_TXBF_SDM_MCS29 = 329, - WL_RATE_4X4_TXBF_SDM_MCS30 = 330, - WL_RATE_4X4_TXBF_SDM_MCS31 = 331, - WL_RATE_P_4X4_TXBF_SDM_MCS103 = 332, - WL_RATE_P_4X4_TXBF_SDM_MCS104 = 333, - - WL_RATE_4X4_TXBF_VHT0SS4 = 324, - WL_RATE_4X4_TXBF_VHT1SS4 = 325, - WL_RATE_4X4_TXBF_VHT2SS4 = 326, - WL_RATE_4X4_TXBF_VHT3SS4 = 327, - WL_RATE_4X4_TXBF_VHT4SS4 = 328, - WL_RATE_4X4_TXBF_VHT5SS4 = 329, - WL_RATE_4X4_TXBF_VHT6SS4 = 330, - WL_RATE_4X4_TXBF_VHT7SS4 = 331, - WL_RATE_P_4X4_TXBF_VHT8SS4 = 332, - WL_RATE_P_4X4_TXBF_VHT9SS4 = 333, - WL_RATE_P_4X4_TXBF_VHT10SS4 = 334, - WL_RATE_P_4X4_TXBF_VHT11SS4 = 335 - -} clm_rates_t; - -/* Number of rate codes */ -#define WL_NUMRATES 336 - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* _bcmwifi_rates_h_ */
diff --git a/bcmdhd.1.579.77.41.x/bcmxtlv.c b/bcmdhd.1.579.77.41.x/bcmxtlv.c deleted file mode 100644 index d6bef6f..0000000 --- a/bcmdhd.1.579.77.41.x/bcmxtlv.c +++ /dev/null
@@ -1,457 +0,0 @@ -/* - * Driver O/S-independent utility routines - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: bcmxtlv.c 628611 2016-03-31 17:53:25Z $ - */ - -#include <bcm_cfg.h> - -#include <typedefs.h> -#include <bcmdefs.h> - -#include <stdarg.h> - -#ifdef BCMDRIVER -#include <osl.h> -#else /* !BCMDRIVER */ - #include <stdlib.h> /* AS!!! */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#ifndef ASSERT -#define ASSERT(exp) -#endif -INLINE void* MALLOCZ(void *o, size_t s) { BCM_REFERENCE(o); return calloc(1, s); } -INLINE void MFREE(void *o, void *p, size_t s) { BCM_REFERENCE(o); BCM_REFERENCE(s); free(p); } -#endif /* !BCMDRIVER */ - -#include <bcmendian.h> -#include <bcmutils.h> - -static INLINE int bcm_xtlv_size_for_data(int dlen, bcm_xtlv_opts_t opts) -{ - return ((opts & BCM_XTLV_OPTION_ALIGN32) ? ALIGN_SIZE(dlen + BCM_XTLV_HDR_SIZE, 4) - : (dlen + BCM_XTLV_HDR_SIZE)); -} - -bcm_xtlv_t * -bcm_next_xtlv(bcm_xtlv_t *elt, int *buflen, bcm_xtlv_opts_t opts) -{ - int sz; - /* advance to next elt */ - sz = BCM_XTLV_SIZE(elt, opts); - elt = (bcm_xtlv_t*)((uint8 *)elt + sz); - *buflen -= sz; - - /* validate next elt */ - if (!bcm_valid_xtlv(elt, *buflen, opts)) - return NULL; - - return elt; -} - -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) -{ - if (tbuf == NULL) return 0; - return (uint16)(tbuf->buf - tbuf->head); -} -uint16 -bcm_xtlv_buf_rlen(bcm_xtlvbuf_t *tbuf) -{ - if (tbuf == NULL) return 0; - return tbuf->size - bcm_xtlv_buf_len(tbuf); -} -uint8 * -bcm_xtlv_buf(bcm_xtlvbuf_t *tbuf) -{ - if (tbuf == NULL) return NULL; - return tbuf->buf; -} -uint8 * -bcm_xtlv_head(bcm_xtlvbuf_t *tbuf) -{ - if (tbuf == NULL) return NULL; - return tbuf->head; -} -int -bcm_xtlv_put_data(bcm_xtlvbuf_t *tbuf, uint16 type, const void *data, uint16 dlen) -{ - bcm_xtlv_t *xtlv; - int size; - - if (tbuf == NULL) - return BCME_BADARG; - size = bcm_xtlv_size_for_data(dlen, tbuf->opts); - if (bcm_xtlv_buf_rlen(tbuf) < size) - return BCME_NOMEM; - xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); - xtlv->id = htol16(type); - xtlv->len = htol16(dlen); - memcpy(xtlv->data, data, dlen); - tbuf->buf += size; - return BCME_OK; -} -int -bcm_xtlv_put_8(bcm_xtlvbuf_t *tbuf, uint16 type, const int8 data) -{ - bcm_xtlv_t *xtlv; - int size; - - if (tbuf == NULL) - return BCME_BADARG; - size = bcm_xtlv_size_for_data(1, tbuf->opts); - if (bcm_xtlv_buf_rlen(tbuf) < size) - return BCME_NOMEM; - xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); - xtlv->id = htol16(type); - xtlv->len = htol16(sizeof(data)); - xtlv->data[0] = data; - tbuf->buf += size; - return BCME_OK; -} -int -bcm_xtlv_put_16(bcm_xtlvbuf_t *tbuf, uint16 type, const int16 data) -{ - bcm_xtlv_t *xtlv; - int size; - - if (tbuf == NULL) - return BCME_BADARG; - size = bcm_xtlv_size_for_data(2, tbuf->opts); - if (bcm_xtlv_buf_rlen(tbuf) < size) - return BCME_NOMEM; - - xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); - xtlv->id = htol16(type); - xtlv->len = htol16(sizeof(data)); - htol16_ua_store(data, xtlv->data); - tbuf->buf += size; - return BCME_OK; -} -int -bcm_xtlv_put_32(bcm_xtlvbuf_t *tbuf, uint16 type, const int32 data) -{ - bcm_xtlv_t *xtlv; - int size; - - if (tbuf == NULL) - return BCME_BADARG; - size = bcm_xtlv_size_for_data(4, tbuf->opts); - if (bcm_xtlv_buf_rlen(tbuf) < size) - return BCME_NOMEM; - xtlv = (bcm_xtlv_t *)bcm_xtlv_buf(tbuf); - xtlv->id = htol16(type); - xtlv->len = htol16(sizeof(data)); - htol32_ua_store(data, xtlv->data); - tbuf->buf += size; - return BCME_OK; -} - -/* - * 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(uint8 **tlv_buf, uint16 xpct_type, uint16 xpct_len, void *dst, - bcm_xtlv_opts_t opts) -{ - bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf; - uint16 len; - uint16 type; - - ASSERT(ptlv); - /* tlv headr is always packed in LE order */ - len = ltoh16(ptlv->len); - type = ltoh16(ptlv->id); - if (len == 0) { - /* z-len tlv headers: allow, but don't process */ - printf("z-len, skip unpack\n"); - } else { - if ((type != xpct_type) || - (len > xpct_len)) { - printf("xtlv_unpack Error: found[type:%d,len:%d] != xpct[type:%d,len:%d]\n", - type, len, xpct_type, xpct_len); - return BCME_BADARG; - } - /* copy tlv record to caller's buffer */ - memcpy(dst, ptlv->data, ptlv->len); - } - *tlv_buf = (uint8*)(*tlv_buf) + BCM_XTLV_SIZE(ptlv, opts); - return BCME_OK; -} - -/* - * packs user data into tlv record - * advances tlv pointer to next xtlv slot - * buflen is used for tlv_buf space check - */ -int -bcm_pack_xtlv_entry(uint8 **tlv_buf, uint16 *buflen, uint16 type, uint16 len, void *src, - bcm_xtlv_opts_t opts) -{ - bcm_xtlv_t *ptlv = (bcm_xtlv_t *)*tlv_buf; - int size; - - ASSERT(ptlv); - ASSERT(src); - - size = bcm_xtlv_size_for_data(len, opts); - - /* copy data from tlv buffer to dst provided by user */ - if (size > *buflen) { - printf("bcm_pack_xtlv_entry: no space tlv_buf: requested:%d, available:%d\n", - size, *buflen); - return BCME_BADLEN; - } - ptlv->id = htol16(type); - ptlv->len = htol16(len); - - /* copy callers data */ - memcpy(ptlv->data, src, len); - - /* 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, uint8 *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts, - bcm_xtlv_unpack_cbfn_t *cbfn) -{ - uint16 len; - uint16 type; - int res = BCME_OK; - int size; - bcm_xtlv_t *ptlv; - int sbuflen = buflen; - - ASSERT(!buflen || tlv_buf); - ASSERT(!buflen || cbfn); - - while (sbuflen >= (int)BCM_XTLV_HDR_SIZE) { - ptlv = (bcm_xtlv_t *)tlv_buf; - - /* tlv header is always packed in LE order */ - len = ltoh16(ptlv->len); - type = ltoh16(ptlv->id); - - size = bcm_xtlv_size_for_data(len, opts); - - sbuflen -= size; - /* check for possible buffer overrun */ - if (sbuflen < 0) - break; - - if ((res = cbfn(ctx, ptlv->data, type, len)) != BCME_OK) - break; - tlv_buf = (uint8*)tlv_buf + size; - } - return res; -} - -int -bcm_pack_xtlv_buf(void *ctx, void *tlv_buf, uint16 buflen, bcm_xtlv_opts_t opts, - bcm_pack_xtlv_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; - - ASSERT(get_next && pack_next); - - buf = (uint8 *)tlv_buf; - startp = buf; - endp = (uint8 *)buf + buflen; - more = TRUE; - 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; - } - - htol16_ua_store(tlv_id, buf); - htol16_ua_store(tlv_len, buf + sizeof(tlv_id)); - pack_next(ctx, tlv_id, tlv_len, buf + BCM_XTLV_HDR_SIZE); - 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(void **tlv_buf, uint16 *buflen, xtlv_desc_t *items, - bcm_xtlv_opts_t opts) -{ - int res = BCME_OK; - uint8 *ptlv = (uint8 *)*tlv_buf; - - while (items->type != 0) { - if ((items->len > 0) && (res = bcm_pack_xtlv_entry(&ptlv, - buflen, items->type, - items->len, items->ptr, opts) != BCME_OK)) { - break; - } - 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(void *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 = ltoh16(elt->len); - - while (dst_desc->type != 0) { - if (ltoh16(elt->id) == dst_desc->type) { - if (len != dst_desc->len) { - res = BCME_BADLEN; - } else { - memcpy(dst_desc->ptr, elt->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 *data_len_out will contain - * the the data length of the xTLV ID. - */ -void * -bcm_get_data_from_xtlv_buf(uint8 *tlv_buf, uint16 buflen, uint16 id, - uint16 *datalen_out, bcm_xtlv_opts_t opts) -{ - void *retptr = NULL; - uint16 type, len; - int size; - bcm_xtlv_t *ptlv; - int sbuflen = buflen; - - while (sbuflen >= (int)BCM_XTLV_HDR_SIZE) { - ptlv = (bcm_xtlv_t *)tlv_buf; - - /* tlv header is always packed in LE order */ - type = ltoh16(ptlv->id); - len = ltoh16(ptlv->len); - size = bcm_xtlv_size_for_data(len, opts); - - sbuflen -= size; - /* check for possible buffer overrun */ - if (sbuflen < 0) { - printf("%s %d: Invalid sbuflen %d\n", - __FUNCTION__, __LINE__, sbuflen); - break; - } - - if (id == type) { - retptr = ptlv->data; - if (datalen_out) { - *datalen_out = len; - } - break; - } - tlv_buf += size; - } - - return retptr; -} - -int bcm_xtlv_size(const bcm_xtlv_t *elt, bcm_xtlv_opts_t opts) -{ - int size; /* entire size of the XTLV including header, data, and optional padding */ - int len; /* XTLV's value real length wthout padding */ - - len = BCM_XTLV_LEN(elt); - - size = bcm_xtlv_size_for_data(len, opts); - - return size; -}
diff --git a/bcmdhd.1.579.77.41.x/dbus.c b/bcmdhd.1.579.77.41.x/dbus.c deleted file mode 100644 index b1dc74d..0000000 --- a/bcmdhd.1.579.77.41.x/dbus.c +++ /dev/null
@@ -1,2934 +0,0 @@ -/** @file dbus.c - * - * Hides details of USB / SDIO / SPI interfaces and OS details. It is intended to shield details and - * provide the caller with one common bus interface for all dongle devices. In practice, it is only - * used for USB interfaces. DBUS is not a protocol, but an abstraction layer. - * - * Copyright (C) 1999-2016, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dbus.c 553311 2015-04-29 10:23:08Z $ - */ - - -#include "osl.h" -#include "dbus.h" -#include <bcmutils.h> -#include <dngl_stats.h> -#include <dhd.h> -#include <dhd_proto.h> -#ifdef PROP_TXSTATUS /* a form of flow control between host and dongle */ -#include <dhd_wlfc.h> -#endif -#include <dhd_config.h> - -#if defined(BCM_REQUEST_FW) -#include <bcmsrom_fmt.h> -#include <trxhdr.h> -#include <usbrdl.h> -#include <bcmendian.h> -#include <sbpcmcia.h> -#include <bcmnvram.h> -#include <bcmdevs.h> -#endif - - - -#if defined(BCM_REQUEST_FW) -#ifndef VARS_MAX -#define VARS_MAX 8192 -#endif -#endif - -#ifdef DBUS_USB_LOOPBACK -extern bool is_loopback_pkt(void *buf); -extern int matches_loopback_pkt(void *buf); -#endif - -/** General info for all BUS types */ -typedef struct dbus_irbq { - dbus_irb_t *head; - dbus_irb_t *tail; - int cnt; -} dbus_irbq_t; - -/** - * This private structure dhd_bus_t is also declared in dbus_usb_linux.c. - * All the fields must be consistent in both declarations. - */ -typedef struct dhd_bus { - dbus_pub_t pub; /* MUST BE FIRST */ - dhd_pub_t *dhd; - - void *cbarg; - dbus_callbacks_t *cbs; /* callbacks to higher level, e.g. dhd_linux.c */ - void *bus_info; - dbus_intf_t *drvintf; /* callbacks to lower level, e.g. dbus_usb.c or dbus_usb_linux.c */ - uint8 *fw; - int fwlen; - uint32 errmask; - int rx_low_watermark; /* avoid rx overflow by filling rx with free IRBs */ - int tx_low_watermark; - bool txoff; - bool txoverride; /* flow control related */ - bool rxoff; - bool tx_timer_ticking; - - - dbus_irbq_t *rx_q; - dbus_irbq_t *tx_q; - - uint8 *nvram; - int nvram_len; - uint8 *image; /* buffer for combine fw and nvram */ - int image_len; - uint8 *orig_fw; - int origfw_len; - int decomp_memsize; - dbus_extdl_t extdl; - int nvram_nontxt; -#if defined(BCM_REQUEST_FW) - void *firmware; - void *nvfile; -#endif - char *fw_path; /* module_param: path to firmware image */ - char *nv_path; /* module_param: path to nvram vars file */ -} dhd_bus_t; - -struct exec_parms { - union { - /* Can consolidate same params, if need be, but this shows - * group of parameters per function - */ - struct { - dbus_irbq_t *q; - dbus_irb_t *b; - } qenq; - - struct { - dbus_irbq_t *q; - } qdeq; - }; -}; - -#define EXEC_RXLOCK(info, fn, a) \ - info->drvintf->exec_rxlock(dhd_bus->bus_info, ((exec_cb_t)fn), ((struct exec_parms *) a)) - -#define EXEC_TXLOCK(info, fn, a) \ - info->drvintf->exec_txlock(dhd_bus->bus_info, ((exec_cb_t)fn), ((struct exec_parms *) a)) - -/* - * Callbacks common for all BUS - */ -static void dbus_if_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb); -static void dbus_if_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status); -static void dbus_if_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status); -static void dbus_if_errhandler(void *handle, int err); -static void dbus_if_ctl_complete(void *handle, int type, int status); -static void dbus_if_state_change(void *handle, int state); -static void *dbus_if_pktget(void *handle, uint len, bool send); -static void dbus_if_pktfree(void *handle, void *p, bool send); -static struct dbus_irb *dbus_if_getirb(void *cbarg, bool send); -static void dbus_if_rxerr_indicate(void *handle, bool on); - -void * dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype, - uint16 bus_no, uint16 slot, uint32 hdrlen); -void dhd_dbus_disconnect_cb(void *arg); -void dbus_detach(dhd_bus_t *pub); - -/** functions in this file that are called by lower DBUS levels, e.g. dbus_usb.c */ -static dbus_intf_callbacks_t dbus_intf_cbs = { - dbus_if_send_irb_timeout, - dbus_if_send_irb_complete, - dbus_if_recv_irb_complete, - dbus_if_errhandler, - dbus_if_ctl_complete, - dbus_if_state_change, - NULL, /* isr */ - NULL, /* dpc */ - NULL, /* watchdog */ - dbus_if_pktget, - dbus_if_pktfree, - dbus_if_getirb, - dbus_if_rxerr_indicate -}; - -/* - * Need global for probe() and disconnect() since - * attach() is not called at probe and detach() - * can be called inside disconnect() - */ -static dbus_intf_t *g_busintf = NULL; -static probe_cb_t probe_cb = NULL; -static disconnect_cb_t disconnect_cb = NULL; -static void *probe_arg = NULL; -static void *disc_arg = NULL; - -#if defined(BCM_REQUEST_FW) -int8 *nonfwnvram = NULL; /* stand-alone multi-nvram given with driver load */ -int nonfwnvramlen = 0; -#endif /* #if defined(BCM_REQUEST_FW) */ - -static void* q_enq(dbus_irbq_t *q, dbus_irb_t *b); -static void* q_enq_exec(struct exec_parms *args); -static dbus_irb_t*q_deq(dbus_irbq_t *q); -static void* q_deq_exec(struct exec_parms *args); -static int dbus_tx_timer_init(dhd_bus_t *dhd_bus); -static int dbus_tx_timer_start(dhd_bus_t *dhd_bus, uint timeout); -static int dbus_tx_timer_stop(dhd_bus_t *dhd_bus); -static int dbus_irbq_init(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int nq, int size_irb); -static int dbus_irbq_deinit(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int size_irb); -static int dbus_rxirbs_fill(dhd_bus_t *dhd_bus); -static int dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt, void *info); -static void dbus_disconnect(void *handle); -static void *dbus_probe(void *arg, const char *desc, uint32 bustype, - uint16 bus_no, uint16 slot, uint32 hdrlen); - -#if defined(BCM_REQUEST_FW) -extern char * dngl_firmware; -extern unsigned int dngl_fwlen; -#ifndef EXTERNAL_FW_PATH -static int dbus_get_nvram(dhd_bus_t *dhd_bus); -static int dbus_jumbo_nvram(dhd_bus_t *dhd_bus); -static int dbus_otp(dhd_bus_t *dhd_bus, uint16 *boardtype, uint16 *boardrev); -static int dbus_select_nvram(dhd_bus_t *dhd_bus, int8 *jumbonvram, int jumbolen, -uint16 boardtype, uint16 boardrev, int8 **nvram, int *nvram_len); -#endif /* !EXTERNAL_FW_PATH */ -extern int dbus_zlib_decomp(dhd_bus_t *dhd_bus); -extern void *dbus_zlib_calloc(int num, int size); -extern void dbus_zlib_free(void *ptr); -#endif - -/* function */ -void -dbus_flowctrl_tx(void *dbi, bool on) -{ - dhd_bus_t *dhd_bus = dbi; - - if (dhd_bus == NULL) - return; - - DBUSTRACE(("%s on %d\n", __FUNCTION__, on)); - - if (dhd_bus->txoff == on) - return; - - dhd_bus->txoff = on; - - if (dhd_bus->cbs && dhd_bus->cbs->txflowcontrol) - dhd_bus->cbs->txflowcontrol(dhd_bus->cbarg, on); -} - -/** - * if lower level DBUS signaled a rx error, more free rx IRBs should be allocated or flow control - * should kick in to make more free rx IRBs available. - */ -static void -dbus_if_rxerr_indicate(void *handle, bool on) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; - - DBUSTRACE(("%s, on %d\n", __FUNCTION__, on)); - - if (dhd_bus == NULL) - return; - - if (dhd_bus->txoverride == on) - return; - - dhd_bus->txoverride = on; /* flow control */ - - if (!on) - dbus_rxirbs_fill(dhd_bus); - -} - -/** q_enq()/q_deq() are executed with protection via exec_rxlock()/exec_txlock() */ -static void* -q_enq(dbus_irbq_t *q, dbus_irb_t *b) -{ - ASSERT(q->tail != b); - ASSERT(b->next == NULL); - b->next = NULL; - if (q->tail) { - q->tail->next = b; - q->tail = b; - } else - q->head = q->tail = b; - - q->cnt++; - - return b; -} - -static void* -q_enq_exec(struct exec_parms *args) -{ - return q_enq(args->qenq.q, args->qenq.b); -} - -static dbus_irb_t* -q_deq(dbus_irbq_t *q) -{ - dbus_irb_t *b; - - b = q->head; - if (b) { - q->head = q->head->next; - b->next = NULL; - - if (q->head == NULL) - q->tail = q->head; - - q->cnt--; - } - return b; -} - -static void* -q_deq_exec(struct exec_parms *args) -{ - return q_deq(args->qdeq.q); -} - -/** - * called during attach phase. Status @ Dec 2012: this function does nothing since for all of the - * lower DBUS levels dhd_bus->drvintf->tx_timer_init is NULL. - */ -static int -dbus_tx_timer_init(dhd_bus_t *dhd_bus) -{ - if (dhd_bus && dhd_bus->drvintf && dhd_bus->drvintf->tx_timer_init) - return dhd_bus->drvintf->tx_timer_init(dhd_bus->bus_info); - else - return DBUS_ERR; -} - -static int -dbus_tx_timer_start(dhd_bus_t *dhd_bus, uint timeout) -{ - if (dhd_bus == NULL) - return DBUS_ERR; - - if (dhd_bus->tx_timer_ticking) - return DBUS_OK; - - if (dhd_bus->drvintf && dhd_bus->drvintf->tx_timer_start) { - if (dhd_bus->drvintf->tx_timer_start(dhd_bus->bus_info, timeout) == DBUS_OK) { - dhd_bus->tx_timer_ticking = TRUE; - return DBUS_OK; - } - } - - return DBUS_ERR; -} - -static int -dbus_tx_timer_stop(dhd_bus_t *dhd_bus) -{ - if (dhd_bus == NULL) - return DBUS_ERR; - - if (!dhd_bus->tx_timer_ticking) - return DBUS_OK; - - if (dhd_bus->drvintf && dhd_bus->drvintf->tx_timer_stop) { - if (dhd_bus->drvintf->tx_timer_stop(dhd_bus->bus_info) == DBUS_OK) { - dhd_bus->tx_timer_ticking = FALSE; - return DBUS_OK; - } - } - - return DBUS_ERR; -} - -/** called during attach phase. */ -static int -dbus_irbq_init(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int nq, int size_irb) -{ - int i; - dbus_irb_t *irb; - - ASSERT(q); - ASSERT(dhd_bus); - - for (i = 0; i < nq; i++) { - /* MALLOC dbus_irb_tx or dbus_irb_rx, but cast to simple dbus_irb_t linkedlist */ - irb = (dbus_irb_t *) MALLOC(dhd_bus->pub.osh, size_irb); - if (irb == NULL) { - ASSERT(irb); - return DBUS_ERR; - } - bzero(irb, size_irb); - - /* q_enq() does not need to go through EXEC_xxLOCK() during init() */ - q_enq(q, irb); - } - - return DBUS_OK; -} - -/** called during detach phase or when attach failed */ -static int -dbus_irbq_deinit(dhd_bus_t *dhd_bus, dbus_irbq_t *q, int size_irb) -{ - dbus_irb_t *irb; - - ASSERT(q); - ASSERT(dhd_bus); - - /* q_deq() does not need to go through EXEC_xxLOCK() - * during deinit(); all callbacks are stopped by this time - */ - while ((irb = q_deq(q)) != NULL) { - MFREE(dhd_bus->pub.osh, irb, size_irb); - } - - if (q->cnt) - DBUSERR(("deinit: q->cnt=%d > 0\n", q->cnt)); - return DBUS_OK; -} - -/** multiple code paths require the rx queue to be filled with more free IRBs */ -static int -dbus_rxirbs_fill(dhd_bus_t *dhd_bus) -{ - int err = DBUS_OK; - - - dbus_irb_rx_t *rxirb; - struct exec_parms args; - - ASSERT(dhd_bus); - if (dhd_bus->pub.busstate != DBUS_STATE_UP) { - DBUSERR(("dbus_rxirbs_fill: DBUS not up \n")); - return DBUS_ERR; - } else if (!dhd_bus->drvintf || (dhd_bus->drvintf->recv_irb == NULL)) { - /* Lower edge bus interface does not support recv_irb(). - * No need to pre-submit IRBs in this case. - */ - return DBUS_ERR; - } - - /* The dongle recv callback is freerunning without lock. So multiple callbacks(and this - * refill) can run in parallel. While the rxoff condition is triggered outside, - * below while loop has to check and abort posting more to avoid RPC rxq overflow. - */ - args.qdeq.q = dhd_bus->rx_q; - while ((!dhd_bus->rxoff) && - (rxirb = (EXEC_RXLOCK(dhd_bus, q_deq_exec, &args))) != NULL) { - err = dhd_bus->drvintf->recv_irb(dhd_bus->bus_info, rxirb); - if (err == DBUS_ERR_RXDROP || err == DBUS_ERR_RXFAIL) { - /* Add the the free rxirb back to the queue - * and wait till later - */ - bzero(rxirb, sizeof(dbus_irb_rx_t)); - args.qenq.q = dhd_bus->rx_q; - args.qenq.b = (dbus_irb_t *) rxirb; - EXEC_RXLOCK(dhd_bus, q_enq_exec, &args); - break; - } else if (err != DBUS_OK) { - int i = 0; - while (i++ < 100) { - DBUSERR(("%s :: memory leak for rxirb note?\n", __FUNCTION__)); - } - } - } - return err; -} /* dbus_rxirbs_fill */ - -/** called when the DBUS interface state changed. */ -void -dbus_flowctrl_rx(dbus_pub_t *pub, bool on) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - - if (dhd_bus == NULL) - return; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (dhd_bus->rxoff == on) - return; - - dhd_bus->rxoff = on; - - if (dhd_bus->pub.busstate == DBUS_STATE_UP) { - if (!on) { - /* post more irbs, resume rx if necessary */ - dbus_rxirbs_fill(dhd_bus); - if (dhd_bus && dhd_bus->drvintf->recv_resume) { - dhd_bus->drvintf->recv_resume(dhd_bus->bus_info); - } - } else { - /* ??? cancell posted irbs first */ - - if (dhd_bus && dhd_bus->drvintf->recv_stop) { - dhd_bus->drvintf->recv_stop(dhd_bus->bus_info); - } - } - } -} - -/** - * Several code paths in this file want to send a buffer to the dongle. This function handles both - * sending of a buffer or a pkt. - */ -static int -dbus_send_irb(dbus_pub_t *pub, uint8 *buf, int len, void *pkt, void *info) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - int err = DBUS_OK; - dbus_irb_tx_t *txirb = NULL; - int txirb_pending; - struct exec_parms args; - - if (dhd_bus == NULL) - return DBUS_ERR; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (dhd_bus->pub.busstate == DBUS_STATE_UP || - dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { - args.qdeq.q = dhd_bus->tx_q; - if (dhd_bus->drvintf) - txirb = EXEC_TXLOCK(dhd_bus, q_deq_exec, &args); - - if (txirb == NULL) { - DBUSERR(("Out of tx dbus_bufs\n")); - return DBUS_ERR; - } - - if (pkt != NULL) { - txirb->pkt = pkt; - txirb->buf = NULL; - txirb->len = 0; - } else if (buf != NULL) { - txirb->pkt = NULL; - txirb->buf = buf; - txirb->len = len; - } else { - ASSERT(0); /* Should not happen */ - } - txirb->info = info; - txirb->arg = NULL; - txirb->retry_count = 0; - - if (dhd_bus->drvintf && dhd_bus->drvintf->send_irb) { - /* call lower DBUS level send_irb function */ - err = dhd_bus->drvintf->send_irb(dhd_bus->bus_info, txirb); - if (err == DBUS_ERR_TXDROP) { - /* tx fail and no completion routine to clean up, reclaim irb NOW */ - DBUSERR(("%s: send_irb failed, status = %d\n", __FUNCTION__, err)); - bzero(txirb, sizeof(dbus_irb_tx_t)); - args.qenq.q = dhd_bus->tx_q; - args.qenq.b = (dbus_irb_t *) txirb; - EXEC_TXLOCK(dhd_bus, q_enq_exec, &args); - } else { - dbus_tx_timer_start(dhd_bus, DBUS_TX_TIMEOUT_INTERVAL); - txirb_pending = dhd_bus->pub.ntxq - dhd_bus->tx_q->cnt; - if (txirb_pending > (dhd_bus->tx_low_watermark * 3)) { - dbus_flowctrl_tx(dhd_bus, TRUE); - } - } - } - } else { - err = DBUS_ERR_TXFAIL; - DBUSTRACE(("%s: bus down, send_irb failed\n", __FUNCTION__)); - } - - return err; -} /* dbus_send_irb */ - -#if defined(BCM_REQUEST_FW) - -/** - * Before downloading a firmware image into the dongle, the validity of the image must be checked. - */ -static int -check_file(osl_t *osh, unsigned char *headers) -{ - struct trx_header *trx; - int actual_len = -1; - - /* Extract trx header */ - trx = (struct trx_header *)headers; - if (ltoh32(trx->magic) != TRX_MAGIC) { - printf("Error: trx bad hdr %x\n", ltoh32(trx->magic)); - return -1; - } - - headers += SIZEOF_TRX(trx); - - /* TRX V1: get firmware len */ - /* TRX V2: get firmware len and DSG/CFG lengths */ - if (ltoh32(trx->flag_version) & TRX_UNCOMP_IMAGE) { - actual_len = ltoh32(trx->offsets[TRX_OFFSETS_DLFWLEN_IDX]) + - SIZEOF_TRX(trx); -#ifdef BCMTRXV2 - if (ISTRX_V2(trx)) { - actual_len += ltoh32(trx->offsets[TRX_OFFSETS_DSG_LEN_IDX]) + - ltoh32(trx->offsets[TRX_OFFSETS_CFG_LEN_IDX]); - } -#endif - return actual_len; - } else { - printf("compressed image\n"); - } - - return -1; -} - -#ifdef EXTERNAL_FW_PATH -static int -dbus_get_fw_nvram(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path) -{ - int bcmerror = -1, i; - uint len, total_len; - void *nv_image = NULL, *fw_image = NULL; - char *nv_memblock = NULL, *fw_memblock = NULL; - char *bufp; - bool file_exists; - uint8 nvram_words_pad = 0; - uint memblock_size = 2048; - uint8 *memptr; - int actual_fwlen; - struct trx_header *hdr; - uint32 img_offset = 0; - int offset = 0; - - /* For Get nvram */ - file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); - if (file_exists) { - nv_image = dhd_os_open_image(pnv_path); - if (nv_image == NULL) { - printf("%s: Open nvram file failed %s\n", __FUNCTION__, pnv_path); - goto err; - } - } - nv_memblock = MALLOC(dhd_bus->pub.osh, MAX_NVRAMBUF_SIZE); - if (nv_memblock == NULL) { - DBUSERR(("%s: Failed to allocate memory %d bytes\n", - __FUNCTION__, MAX_NVRAMBUF_SIZE)); - goto err; - } - len = dhd_os_get_image_block(nv_memblock, MAX_NVRAMBUF_SIZE, nv_image); - if (len > 0 && len < MAX_NVRAMBUF_SIZE) { - bufp = (char *)nv_memblock; - bufp[len] = 0; - dhd_bus->nvram_len = process_nvram_vars(bufp, len); - if (dhd_bus->nvram_len % 4) - nvram_words_pad = 4 - dhd_bus->nvram_len % 4; - } else { - DBUSERR(("%s: error reading nvram file: %d\n", __FUNCTION__, len)); - bcmerror = DBUS_ERR_NVRAM; - goto err; - } - if (nv_image) - dhd_os_close_image(nv_image); - - /* For Get first block of fw to calculate total_len */ - file_exists = ((pfw_path != NULL) && (pfw_path[0] != '\0')); - if (file_exists) { - fw_image = dhd_os_open_image(pfw_path); - if (fw_image == NULL) { - printf("%s: Open fw file failed %s\n", __FUNCTION__, pfw_path); - goto err; - } - } - memptr = fw_memblock = MALLOC(dhd_bus->pub.osh, memblock_size); - if (fw_memblock == NULL) { - DBUSERR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, - memblock_size)); - goto err; - } - len = dhd_os_get_image_block((char*)memptr, memblock_size, fw_image); - if ((actual_fwlen = check_file(dhd_bus->pub.osh, memptr)) <= 0) { - DBUSERR(("%s: bad firmware format!\n", __FUNCTION__)); - goto err; - } - - total_len = actual_fwlen + dhd_bus->nvram_len + nvram_words_pad; - dhd_bus->image = MALLOC(dhd_bus->pub.osh, total_len); - dhd_bus->image_len = total_len; - if (dhd_bus->image == NULL) { - DBUSERR(("%s: malloc failed!\n", __FUNCTION__)); - goto err; - } - - /* Step1: Copy trx header + firmwre */ - memptr = fw_memblock; - do { - if (len < 0) { - DBUSERR(("%s: dhd_os_get_image_block failed (%d)\n", __FUNCTION__, len)); - bcmerror = BCME_ERROR; - goto err; - } - bcopy(memptr, dhd_bus->image+offset, len); - offset += len; - } while ((len = dhd_os_get_image_block((char*)memptr, memblock_size, fw_image))); - /* Step2: Copy NVRAM + pad */ - hdr = (struct trx_header *)dhd_bus->image; - img_offset = SIZEOF_TRX(hdr) + hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX]; - bcopy(nv_memblock, (uint8 *)(dhd_bus->image + img_offset), - dhd_bus->nvram_len); - img_offset += dhd_bus->nvram_len; - if (nvram_words_pad) { - bzero(&dhd_bus->image[img_offset], nvram_words_pad); - img_offset += nvram_words_pad; - } -#ifdef BCMTRXV2 - /* Step3: Copy DSG/CFG for V2 */ - if (ISTRX_V2(hdr) && - (hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] || - hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX])) { - DBUSERR(("%s: fix me\n", __FUNCTION__)); - } -#endif /* BCMTRXV2 */ - /* Step4: update TRX header for nvram size */ - hdr = (struct trx_header *)dhd_bus->image; - hdr->len = htol32(total_len); - /* Pass the actual fw len */ - hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX] = - htol32(dhd_bus->nvram_len + nvram_words_pad); - /* Calculate CRC over header */ - hdr->crc32 = hndcrc32((uint8 *)&hdr->flag_version, - SIZEOF_TRX(hdr) - OFFSETOF(struct trx_header, flag_version), - CRC32_INIT_VALUE); - - /* Calculate CRC over data */ - for (i = SIZEOF_TRX(hdr); i < total_len; ++i) - hdr->crc32 = hndcrc32((uint8 *)&dhd_bus->image[i], 1, hdr->crc32); - hdr->crc32 = htol32(hdr->crc32); - - bcmerror = DBUS_OK; - -err: - if (fw_memblock) - MFREE(dhd_bus->pub.osh, fw_memblock, MAX_NVRAMBUF_SIZE); - if (fw_image) - dhd_os_close_image(fw_image); - if (nv_memblock) - MFREE(dhd_bus->pub.osh, nv_memblock, MAX_NVRAMBUF_SIZE); - if (nv_image) - dhd_os_close_image(nv_image); - - return bcmerror; -} - -/** - * during driver initialization ('attach') or after PnP 'resume', firmware needs to be loaded into - * the dongle - */ -static int -dbus_do_download(dhd_bus_t *dhd_bus, char *pfw_path, char *pnv_path) -{ - int err = DBUS_OK; - - err = dbus_get_fw_nvram(dhd_bus, pfw_path, pnv_path); - if (err) { - DBUSERR(("dbus_do_download: fail to get nvram %d\n", err)); - return err; - } - - if (dhd_bus->drvintf->dlstart && dhd_bus->drvintf->dlrun) { - err = dhd_bus->drvintf->dlstart(dhd_bus->bus_info, - dhd_bus->image, dhd_bus->image_len); - if (err == DBUS_OK) { - err = dhd_bus->drvintf->dlrun(dhd_bus->bus_info); - } - } else - err = DBUS_ERR; - - if (dhd_bus->image) { - MFREE(dhd_bus->pub.osh, dhd_bus->image, dhd_bus->image_len); - dhd_bus->image = NULL; - dhd_bus->image_len = 0; - } - - return err; -} /* dbus_do_download */ -#else - -/** - * It is easy for the user to pass one jumbo nvram file to the driver than a set of smaller files. - * The 'jumbo nvram' file format is essentially a set of nvram files. Before commencing firmware - * download, the dongle needs to be probed so that the correct nvram contents within the jumbo nvram - * file is selected. - */ -static int -dbus_jumbo_nvram(dhd_bus_t *dhd_bus) -{ - int8 *nvram = NULL; - int nvram_len = 0; - int ret = DBUS_OK; - uint16 boardrev = 0xFFFF; - uint16 boardtype = 0xFFFF; - - /* read the otp for boardrev & boardtype - * if boardtype/rev are present in otp - * select nvram data for that boardtype/rev - */ - dbus_otp(dhd_bus, &boardtype, &boardrev); - - ret = dbus_select_nvram(dhd_bus, dhd_bus->extdl.vars, dhd_bus->extdl.varslen, - boardtype, boardrev, &nvram, &nvram_len); - - if (ret == DBUS_JUMBO_BAD_FORMAT) - return DBUS_ERR_NVRAM; - else if (ret == DBUS_JUMBO_NOMATCH && - (boardtype != 0xFFFF || boardrev != 0xFFFF)) { - DBUSERR(("No matching NVRAM for boardtype 0x%02x boardrev 0x%02x\n", - boardtype, boardrev)); - return DBUS_ERR_NVRAM; - } - dhd_bus->nvram = nvram; - dhd_bus->nvram_len = nvram_len; - - return DBUS_OK; -} - -/** before commencing fw download, the correct NVRAM image to download has to be picked */ -static int -dbus_get_nvram(dhd_bus_t *dhd_bus) -{ - int len, i; - struct trx_header *hdr; - int actual_fwlen; - uint32 img_offset = 0; - - dhd_bus->nvram_len = 0; - if (dhd_bus->extdl.varslen) { - if (DBUS_OK != dbus_jumbo_nvram(dhd_bus)) - return DBUS_ERR_NVRAM; - DBUSERR(("NVRAM %d bytes downloaded\n", dhd_bus->nvram_len)); - } -#if defined(BCM_REQUEST_FW) - else if (nonfwnvram) { - dhd_bus->nvram = nonfwnvram; - dhd_bus->nvram_len = nonfwnvramlen; - DBUSERR(("NVRAM %d bytes downloaded\n", dhd_bus->nvram_len)); - } -#endif - if (dhd_bus->nvram) { - uint8 nvram_words_pad = 0; - /* Validate the format/length etc of the file */ - if ((actual_fwlen = check_file(dhd_bus->pub.osh, dhd_bus->fw)) <= 0) { - DBUSERR(("%s: bad firmware format!\n", __FUNCTION__)); - return DBUS_ERR_NVRAM; - } - - if (!dhd_bus->nvram_nontxt) { - /* host supplied nvram could be in .txt format - * with all the comments etc... - */ - dhd_bus->nvram_len = process_nvram_vars(dhd_bus->nvram, - dhd_bus->nvram_len); - } - if (dhd_bus->nvram_len % 4) - nvram_words_pad = 4 - dhd_bus->nvram_len % 4; - - len = actual_fwlen + dhd_bus->nvram_len + nvram_words_pad; - dhd_bus->image = MALLOC(dhd_bus->pub.osh, len); - dhd_bus->image_len = len; - if (dhd_bus->image == NULL) { - DBUSERR(("%s: malloc failed!\n", __FUNCTION__)); - return DBUS_ERR_NVRAM; - } - hdr = (struct trx_header *)dhd_bus->fw; - /* Step1: Copy trx header + firmwre */ - img_offset = SIZEOF_TRX(hdr) + hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX]; - bcopy(dhd_bus->fw, dhd_bus->image, img_offset); - /* Step2: Copy NVRAM + pad */ - bcopy(dhd_bus->nvram, (uint8 *)(dhd_bus->image + img_offset), - dhd_bus->nvram_len); - img_offset += dhd_bus->nvram_len; - if (nvram_words_pad) { - bzero(&dhd_bus->image[img_offset], - nvram_words_pad); - img_offset += nvram_words_pad; - } -#ifdef BCMTRXV2 - /* Step3: Copy DSG/CFG for V2 */ - if (ISTRX_V2(hdr) && - (hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] || - hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX])) { - - bcopy(dhd_bus->fw + SIZEOF_TRX(hdr) + - hdr->offsets[TRX_OFFSETS_DLFWLEN_IDX] + - hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX], - dhd_bus->image + img_offset, - hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] + - hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX]); - - img_offset += hdr->offsets[TRX_OFFSETS_DSG_LEN_IDX] + - hdr->offsets[TRX_OFFSETS_CFG_LEN_IDX]; - } -#endif /* BCMTRXV2 */ - /* Step4: update TRX header for nvram size */ - hdr = (struct trx_header *)dhd_bus->image; - hdr->len = htol32(len); - /* Pass the actual fw len */ - hdr->offsets[TRX_OFFSETS_NVM_LEN_IDX] = - htol32(dhd_bus->nvram_len + nvram_words_pad); - /* Calculate CRC over header */ - hdr->crc32 = hndcrc32((uint8 *)&hdr->flag_version, - SIZEOF_TRX(hdr) - OFFSETOF(struct trx_header, flag_version), - CRC32_INIT_VALUE); - - /* Calculate CRC over data */ - for (i = SIZEOF_TRX(hdr); i < len; ++i) - hdr->crc32 = hndcrc32((uint8 *)&dhd_bus->image[i], 1, hdr->crc32); - hdr->crc32 = htol32(hdr->crc32); - } else { - dhd_bus->image = dhd_bus->fw; - dhd_bus->image_len = (uint32)dhd_bus->fwlen; - } - - return DBUS_OK; -} /* dbus_get_nvram */ - -/** - * during driver initialization ('attach') or after PnP 'resume', firmware needs to be loaded into - * the dongle - */ -static int -dbus_do_download(dhd_bus_t *dhd_bus) -{ - int err = DBUS_OK; -#ifndef BCM_REQUEST_FW - int decomp_override = 0; -#endif -#ifdef BCM_REQUEST_FW - uint16 boardrev = 0xFFFF, boardtype = 0xFFFF; - int8 *temp_nvram; - int temp_len; -#endif - -#if defined(BCM_REQUEST_FW) - dhd_bus->firmware = dbus_get_fw_nvfile(dhd_bus->pub.attrib.devid, - dhd_bus->pub.attrib.chiprev, &dhd_bus->fw, &dhd_bus->fwlen, - DBUS_FIRMWARE, 0, 0); - if (!dhd_bus->firmware) - return DBUS_ERR; -#endif - - dhd_bus->image = dhd_bus->fw; - dhd_bus->image_len = (uint32)dhd_bus->fwlen; - -#ifndef BCM_REQUEST_FW - if (UNZIP_ENAB(dhd_bus) && !decomp_override) { - err = dbus_zlib_decomp(dhd_bus); - if (err) { - DBUSERR(("dbus_attach: fw decompress fail %d\n", err)); - return err; - } - } -#endif - -#if defined(BCM_REQUEST_FW) - /* check if firmware is appended with nvram file */ - err = dbus_otp(dhd_bus, &boardtype, &boardrev); - /* check if nvram is provided as separte file */ - nonfwnvram = NULL; - nonfwnvramlen = 0; - dhd_bus->nvfile = dbus_get_fw_nvfile(dhd_bus->pub.attrib.devid, - dhd_bus->pub.attrib.chiprev, (void *)&temp_nvram, &temp_len, - DBUS_NVFILE, boardtype, boardrev); - if (dhd_bus->nvfile) { - int8 *tmp = MALLOC(dhd_bus->pub.osh, temp_len); - if (tmp) { - bcopy(temp_nvram, tmp, temp_len); - nonfwnvram = tmp; - nonfwnvramlen = temp_len; - } else { - err = DBUS_ERR; - goto fail; - } - } -#endif /* defined(BCM_REQUEST_FW) */ - - err = dbus_get_nvram(dhd_bus); - if (err) { - DBUSERR(("dbus_do_download: fail to get nvram %d\n", err)); - return err; - } - - - if (dhd_bus->drvintf->dlstart && dhd_bus->drvintf->dlrun) { - err = dhd_bus->drvintf->dlstart(dhd_bus->bus_info, - dhd_bus->image, dhd_bus->image_len); - - if (err == DBUS_OK) - err = dhd_bus->drvintf->dlrun(dhd_bus->bus_info); - } else - err = DBUS_ERR; - - if (dhd_bus->nvram) { - MFREE(dhd_bus->pub.osh, dhd_bus->image, dhd_bus->image_len); - dhd_bus->image = dhd_bus->fw; - dhd_bus->image_len = (uint32)dhd_bus->fwlen; - } - -#ifndef BCM_REQUEST_FW - if (UNZIP_ENAB(dhd_bus) && (!decomp_override) && dhd_bus->orig_fw) { - MFREE(dhd_bus->pub.osh, dhd_bus->fw, dhd_bus->decomp_memsize); - dhd_bus->image = dhd_bus->fw = dhd_bus->orig_fw; - dhd_bus->image_len = dhd_bus->fwlen = dhd_bus->origfw_len; - } -#endif - -#if defined(BCM_REQUEST_FW) -fail: - if (dhd_bus->firmware) { - dbus_release_fw_nvfile(dhd_bus->firmware); - dhd_bus->firmware = NULL; - } - if (dhd_bus->nvfile) { - dbus_release_fw_nvfile(dhd_bus->nvfile); - dhd_bus->nvfile = NULL; - } - if (nonfwnvram) { - MFREE(dhd_bus->pub.osh, nonfwnvram, nonfwnvramlen); - nonfwnvram = NULL; - nonfwnvramlen = 0; - } -#endif - return err; -} /* dbus_do_download */ -#endif /* EXTERNAL_FW_PATH */ -#endif - -/** required for DBUS deregistration */ -static void -dbus_disconnect(void *handle) -{ - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (disconnect_cb) - disconnect_cb(disc_arg); -} - -/** - * This function is called when the sent irb times out without a tx response status. - * DBUS adds reliability by resending timed out IRBs DBUS_TX_RETRY_LIMIT times. - */ -static void -dbus_if_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; - - if ((dhd_bus == NULL) || (dhd_bus->drvintf == NULL) || (txirb == NULL)) { - return; - } - - DBUSTRACE(("%s\n", __FUNCTION__)); - - return; - -} /* dbus_if_send_irb_timeout */ - -/** - * When lower DBUS level signals that a send IRB completed, either successful or not, the higher - * level (e.g. dhd_linux.c) has to be notified, and transmit flow control has to be evaluated. - */ -static void BCMFASTPATH -dbus_if_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; - int txirb_pending; - struct exec_parms args; - void *pktinfo; - - if ((dhd_bus == NULL) || (txirb == NULL)) { - return; - } - - DBUSTRACE(("%s: status = %d\n", __FUNCTION__, status)); - - dbus_tx_timer_stop(dhd_bus); - - /* re-queue BEFORE calling send_complete which will assume that this irb - is now available. - */ - pktinfo = txirb->info; - bzero(txirb, sizeof(dbus_irb_tx_t)); - args.qenq.q = dhd_bus->tx_q; - args.qenq.b = (dbus_irb_t *) txirb; - EXEC_TXLOCK(dhd_bus, q_enq_exec, &args); - - if (dhd_bus->pub.busstate != DBUS_STATE_DOWN) { - if ((status == DBUS_OK) || (status == DBUS_ERR_NODEVICE)) { - if (dhd_bus->cbs && dhd_bus->cbs->send_complete) - dhd_bus->cbs->send_complete(dhd_bus->cbarg, pktinfo, - status); - - if (status == DBUS_OK) { - txirb_pending = dhd_bus->pub.ntxq - dhd_bus->tx_q->cnt; - if (txirb_pending) - dbus_tx_timer_start(dhd_bus, DBUS_TX_TIMEOUT_INTERVAL); - if ((txirb_pending < dhd_bus->tx_low_watermark) && - dhd_bus->txoff && !dhd_bus->txoverride) { - dbus_flowctrl_tx(dhd_bus, OFF); - } - } - } else { - DBUSERR(("%s: %d WARNING freeing orphan pkt %p\n", __FUNCTION__, __LINE__, - pktinfo)); -#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) || defined(BCM_RPC_TOC) - if (pktinfo) - if (dhd_bus->cbs && dhd_bus->cbs->send_complete) - dhd_bus->cbs->send_complete(dhd_bus->cbarg, pktinfo, - status); -#else - dbus_if_pktfree(dhd_bus, (void*)pktinfo, TRUE); -#endif /* defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) || defined(BCM_RPC_TOC) */ - } - } else { - DBUSERR(("%s: %d WARNING freeing orphan pkt %p\n", __FUNCTION__, __LINE__, - pktinfo)); -#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) || defined(BCM_RPC_TOC) - if (pktinfo) - if (dhd_bus->cbs && dhd_bus->cbs->send_complete) - dhd_bus->cbs->send_complete(dhd_bus->cbarg, pktinfo, - status); -#else - dbus_if_pktfree(dhd_bus, (void*)pktinfo, TRUE); -#endif /* defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_TXNOCOPY) defined(BCM_RPC_TOC) */ - } -} /* dbus_if_send_irb_complete */ - -/** - * When lower DBUS level signals that a receive IRB completed, either successful or not, the higher - * level (e.g. dhd_linux.c) has to be notified, and fresh free receive IRBs may have to be given - * to lower levels. - */ -static void BCMFASTPATH -dbus_if_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; - int rxirb_pending; - struct exec_parms args; - - if ((dhd_bus == NULL) || (rxirb == NULL)) { - return; - } - DBUSTRACE(("%s\n", __FUNCTION__)); - if (dhd_bus->pub.busstate != DBUS_STATE_DOWN && - dhd_bus->pub.busstate != DBUS_STATE_SLEEP) { - if (status == DBUS_OK) { - if ((rxirb->buf != NULL) && (rxirb->actual_len > 0)) { -#ifdef DBUS_USB_LOOPBACK - if (is_loopback_pkt(rxirb->buf)) { - matches_loopback_pkt(rxirb->buf); - } else -#endif - if (dhd_bus->cbs && dhd_bus->cbs->recv_buf) { - dhd_bus->cbs->recv_buf(dhd_bus->cbarg, rxirb->buf, - rxirb->actual_len); - } - } else if (rxirb->pkt != NULL) { - if (dhd_bus->cbs && dhd_bus->cbs->recv_pkt) - dhd_bus->cbs->recv_pkt(dhd_bus->cbarg, rxirb->pkt); - } else { - ASSERT(0); /* Should not happen */ - } - - rxirb_pending = dhd_bus->pub.nrxq - dhd_bus->rx_q->cnt - 1; - if ((rxirb_pending <= dhd_bus->rx_low_watermark) && - !dhd_bus->rxoff) { - DBUSTRACE(("Low watermark so submit more %d <= %d \n", - dhd_bus->rx_low_watermark, rxirb_pending)); - dbus_rxirbs_fill(dhd_bus); - } else if (dhd_bus->rxoff) - DBUSTRACE(("rx flow controlled. not filling more. cut_rxq=%d\n", - dhd_bus->rx_q->cnt)); - } else if (status == DBUS_ERR_NODEVICE) { - DBUSERR(("%s: %d status = %d, buf %p\n", __FUNCTION__, __LINE__, status, - rxirb->buf)); -#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) - if (rxirb->buf) { - PKTFRMNATIVE(dhd_bus->pub.osh, rxirb->buf); - PKTFREE(dhd_bus->pub.osh, rxirb->buf, FALSE); - } -#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY || BCM_RPC_TOC */ - } else { - if (status != DBUS_ERR_RXZLP) - DBUSERR(("%s: %d status = %d, buf %p\n", __FUNCTION__, __LINE__, - status, rxirb->buf)); -#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) - if (rxirb->buf) { - PKTFRMNATIVE(dhd_bus->pub.osh, rxirb->buf); - PKTFREE(dhd_bus->pub.osh, rxirb->buf, FALSE); - } -#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY || BCM_RPC_TOC */ - } - } else { - DBUSTRACE(("%s: DBUS down, ignoring recv callback. buf %p\n", __FUNCTION__, - rxirb->buf)); -#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) - if (rxirb->buf) { - PKTFRMNATIVE(dhd_bus->pub.osh, rxirb->buf); - PKTFREE(dhd_bus->pub.osh, rxirb->buf, FALSE); - } -#endif /* BCM_RPC_NOCOPY || BCM_RPC_TXNOCOPY || BCM_RPC_TOC */ - } - if (dhd_bus->rx_q != NULL) { - bzero(rxirb, sizeof(dbus_irb_rx_t)); - args.qenq.q = dhd_bus->rx_q; - args.qenq.b = (dbus_irb_t *) rxirb; - EXEC_RXLOCK(dhd_bus, q_enq_exec, &args); - } else - MFREE(dhd_bus->pub.osh, rxirb, sizeof(dbus_irb_tx_t)); -} /* dbus_if_recv_irb_complete */ - -/** - * Accumulate errors signaled by lower DBUS levels and signal them to higher (e.g. dhd_linux.c) - * level. - */ -static void -dbus_if_errhandler(void *handle, int err) -{ - dhd_bus_t *dhd_bus = handle; - uint32 mask = 0; - - if (dhd_bus == NULL) - return; - - switch (err) { - case DBUS_ERR_TXFAIL: - dhd_bus->pub.stats.tx_errors++; - mask |= ERR_CBMASK_TXFAIL; - break; - case DBUS_ERR_TXDROP: - dhd_bus->pub.stats.tx_dropped++; - mask |= ERR_CBMASK_TXFAIL; - break; - case DBUS_ERR_RXFAIL: - dhd_bus->pub.stats.rx_errors++; - mask |= ERR_CBMASK_RXFAIL; - break; - case DBUS_ERR_RXDROP: - dhd_bus->pub.stats.rx_dropped++; - mask |= ERR_CBMASK_RXFAIL; - break; - default: - break; - } - - if (dhd_bus->cbs && dhd_bus->cbs->errhandler && (dhd_bus->errmask & mask)) - dhd_bus->cbs->errhandler(dhd_bus->cbarg, err); -} - -/** - * When lower DBUS level signals control IRB completed, higher level (e.g. dhd_linux.c) has to be - * notified. - */ -static void -dbus_if_ctl_complete(void *handle, int type, int status) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (dhd_bus == NULL) { - DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__)); - return; - } - - if (dhd_bus->pub.busstate != DBUS_STATE_DOWN) { - if (dhd_bus->cbs && dhd_bus->cbs->ctl_complete) - dhd_bus->cbs->ctl_complete(dhd_bus->cbarg, type, status); - } -} - -/** - * Rx related functionality (flow control, posting of free IRBs to rx queue) is dependent upon the - * bus state. When lower DBUS level signals a change in the interface state, take appropriate action - * and forward the signaling to the higher (e.g. dhd_linux.c) level. - */ -static void -dbus_if_state_change(void *handle, int state) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; - int old_state; - - if (dhd_bus == NULL) - return; - - if (dhd_bus->pub.busstate == state) - return; - old_state = dhd_bus->pub.busstate; - if (state == DBUS_STATE_DISCONNECT) { - DBUSERR(("DBUS disconnected\n")); - } - - /* Ignore USB SUSPEND while not up yet */ - if (state == DBUS_STATE_SLEEP && old_state != DBUS_STATE_UP) - return; - - DBUSTRACE(("dbus state change from %d to to %d\n", old_state, state)); - - /* Don't update state if it's PnP firmware re-download */ - if (state != DBUS_STATE_PNP_FWDL) - dhd_bus->pub.busstate = state; - else - dbus_flowctrl_rx(handle, FALSE); - if (state == DBUS_STATE_SLEEP) - dbus_flowctrl_rx(handle, TRUE); - if (state == DBUS_STATE_UP) { - dbus_rxirbs_fill(dhd_bus); - dbus_flowctrl_rx(handle, FALSE); - } - - if (dhd_bus->cbs && dhd_bus->cbs->state_change) - dhd_bus->cbs->state_change(dhd_bus->cbarg, state); -} - -/** Forward request for packet from lower DBUS layer to higher layer (e.g. dhd_linux.c) */ -static void * -dbus_if_pktget(void *handle, uint len, bool send) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; - void *p = NULL; - - if (dhd_bus == NULL) - return NULL; - - if (dhd_bus->cbs && dhd_bus->cbs->pktget) - p = dhd_bus->cbs->pktget(dhd_bus->cbarg, len, send); - else - ASSERT(0); - - return p; -} - -/** Forward request to free packet from lower DBUS layer to higher layer (e.g. dhd_linux.c) */ -static void -dbus_if_pktfree(void *handle, void *p, bool send) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) handle; - - if (dhd_bus == NULL) - return; - - if (dhd_bus->cbs && dhd_bus->cbs->pktfree) - dhd_bus->cbs->pktfree(dhd_bus->cbarg, p, send); - else - ASSERT(0); -} - -/** Lower DBUS level requests either a send or receive IRB */ -static struct dbus_irb* -dbus_if_getirb(void *cbarg, bool send) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) cbarg; - struct exec_parms args; - struct dbus_irb *irb; - - if ((dhd_bus == NULL) || (dhd_bus->pub.busstate != DBUS_STATE_UP)) - return NULL; - - if (send == TRUE) { - args.qdeq.q = dhd_bus->tx_q; - irb = EXEC_TXLOCK(dhd_bus, q_deq_exec, &args); - } else { - args.qdeq.q = dhd_bus->rx_q; - irb = EXEC_RXLOCK(dhd_bus, q_deq_exec, &args); - } - - return irb; -} - -/** - * Called as part of DBUS bus registration. Calls back into higher level (e.g. dhd_linux.c) probe - * function. - */ -static void * -dbus_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no, - uint16 slot, uint32 hdrlen) -{ - DBUSTRACE(("%s\n", __FUNCTION__)); - if (probe_cb) { - disc_arg = probe_cb(probe_arg, desc, bustype, bus_no, slot, hdrlen); - return disc_arg; - } - - return (void *)DBUS_ERR; -} - -/** - * As part of initialization, higher level (e.g. dhd_linux.c) requests DBUS to prepare for - * action. - */ -int -dhd_bus_register(void) -{ - int err; - - DBUSTRACE(("%s: Enter\n", __FUNCTION__)); - - probe_cb = dhd_dbus_probe_cb; - disconnect_cb = dhd_dbus_disconnect_cb; - probe_arg = NULL; - - err = dbus_bus_register(0xa5c, 0x48f, dbus_probe, /* call lower DBUS level register function */ - dbus_disconnect, NULL, &g_busintf, NULL, NULL); - - /* Device not detected */ - if (err == DBUS_ERR_NODEVICE) - err = DBUS_OK; - - return err; -} - -dhd_pub_t *g_pub = NULL; -void -dhd_bus_unregister(void) -{ - int ret; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - DHD_MUTEX_LOCK(); - if (g_pub) { - g_pub->dhd_remove = TRUE; - if (!g_pub->bus) { - dhd_dbus_disconnect_cb(g_pub->bus); - } - } - probe_cb = NULL; - DHD_MUTEX_UNLOCK(); - ret = dbus_bus_deregister(); - disconnect_cb = NULL; - probe_arg = NULL; -} - -/** As part of initialization, data structures have to be allocated and initialized */ -dhd_bus_t * -dbus_attach(osl_t *osh, int rxsize, int nrxq, int ntxq, dhd_pub_t *pub, - dbus_callbacks_t *cbs, dbus_extdl_t *extdl, struct shared_info *sh) -{ - dhd_bus_t *dhd_bus; - int err; - - if ((g_busintf == NULL) || (g_busintf->attach == NULL) || (cbs == NULL)) - return NULL; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if ((nrxq <= 0) || (ntxq <= 0)) - return NULL; - - dhd_bus = MALLOC(osh, sizeof(dhd_bus_t)); - if (dhd_bus == NULL) { - DBUSERR(("%s: malloc failed %d\n", __FUNCTION__, sizeof(dhd_bus_t))); - return NULL; - } - - bzero(dhd_bus, sizeof(dhd_bus_t)); - - /* BUS-specific driver interface (at a lower DBUS level) */ - dhd_bus->drvintf = g_busintf; - dhd_bus->cbarg = pub; - dhd_bus->cbs = cbs; - - dhd_bus->pub.sh = sh; - dhd_bus->pub.osh = osh; - dhd_bus->pub.rxsize = rxsize; - - dhd_bus->pub.nrxq = nrxq; - dhd_bus->rx_low_watermark = nrxq / 2; /* keep enough posted rx urbs */ - dhd_bus->pub.ntxq = ntxq; - dhd_bus->tx_low_watermark = ntxq / 4; /* flow control when too many tx urbs posted */ - - dhd_bus->tx_q = MALLOC(osh, sizeof(dbus_irbq_t)); - if (dhd_bus->tx_q == NULL) - goto error; - else { - bzero(dhd_bus->tx_q, sizeof(dbus_irbq_t)); - err = dbus_irbq_init(dhd_bus, dhd_bus->tx_q, ntxq, sizeof(dbus_irb_tx_t)); - if (err != DBUS_OK) - goto error; - } - - dhd_bus->rx_q = MALLOC(osh, sizeof(dbus_irbq_t)); - if (dhd_bus->rx_q == NULL) - goto error; - else { - bzero(dhd_bus->rx_q, sizeof(dbus_irbq_t)); - err = dbus_irbq_init(dhd_bus, dhd_bus->rx_q, nrxq, sizeof(dbus_irb_rx_t)); - if (err != DBUS_OK) - goto error; - } - - - dhd_bus->bus_info = (void *)g_busintf->attach(&dhd_bus->pub, - dhd_bus, &dbus_intf_cbs); - if (dhd_bus->bus_info == NULL) - goto error; - - dbus_tx_timer_init(dhd_bus); - -#if defined(BCM_REQUEST_FW) - /* Need to copy external image for re-download */ - if (extdl && extdl->fw && (extdl->fwlen > 0)) { - dhd_bus->extdl.fw = MALLOC(osh, extdl->fwlen); - if (dhd_bus->extdl.fw) { - bcopy(extdl->fw, dhd_bus->extdl.fw, extdl->fwlen); - dhd_bus->extdl.fwlen = extdl->fwlen; - } - } - - if (extdl && extdl->vars && (extdl->varslen > 0)) { - dhd_bus->extdl.vars = MALLOC(osh, extdl->varslen); - if (dhd_bus->extdl.vars) { - bcopy(extdl->vars, dhd_bus->extdl.vars, extdl->varslen); - dhd_bus->extdl.varslen = extdl->varslen; - } - } -#endif - - return (dhd_bus_t *)dhd_bus; - -error: - DBUSERR(("%s: Failed\n", __FUNCTION__)); - dbus_detach(dhd_bus); - return NULL; -} /* dbus_attach */ - -void -dbus_detach(dhd_bus_t *pub) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - osl_t *osh; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (dhd_bus == NULL) - return; - - dbus_tx_timer_stop(dhd_bus); - - osh = pub->pub.osh; - - if (dhd_bus->drvintf && dhd_bus->drvintf->detach) - dhd_bus->drvintf->detach((dbus_pub_t *)dhd_bus, dhd_bus->bus_info); - - if (dhd_bus->tx_q) { - dbus_irbq_deinit(dhd_bus, dhd_bus->tx_q, sizeof(dbus_irb_tx_t)); - MFREE(osh, dhd_bus->tx_q, sizeof(dbus_irbq_t)); - dhd_bus->tx_q = NULL; - } - - if (dhd_bus->rx_q) { - dbus_irbq_deinit(dhd_bus, dhd_bus->rx_q, sizeof(dbus_irb_rx_t)); - MFREE(osh, dhd_bus->rx_q, sizeof(dbus_irbq_t)); - dhd_bus->rx_q = NULL; - } - - - if (dhd_bus->extdl.fw && (dhd_bus->extdl.fwlen > 0)) { - MFREE(osh, dhd_bus->extdl.fw, dhd_bus->extdl.fwlen); - dhd_bus->extdl.fw = NULL; - dhd_bus->extdl.fwlen = 0; - } - - if (dhd_bus->extdl.vars && (dhd_bus->extdl.varslen > 0)) { - MFREE(osh, dhd_bus->extdl.vars, dhd_bus->extdl.varslen); - dhd_bus->extdl.vars = NULL; - dhd_bus->extdl.varslen = 0; - } - - MFREE(osh, dhd_bus, sizeof(dhd_bus_t)); -} /* dbus_detach */ - -int dbus_dlneeded(dhd_bus_t *pub) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - int dlneeded = DBUS_ERR; - - if (!dhd_bus) { - DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__)); - return DBUS_ERR; - } - - DBUSTRACE(("%s: state %d\n", __FUNCTION__, dhd_bus->pub.busstate)); - - if (dhd_bus->drvintf->dlneeded) { - dlneeded = dhd_bus->drvintf->dlneeded(dhd_bus->bus_info); - } - printf("%s: dlneeded=%d\n", __FUNCTION__, dlneeded); - - /* dlneeded > 0: need to download - * dlneeded = 0: downloaded - * dlneeded < 0: bus error*/ - return dlneeded; -} - -#if defined(BCM_REQUEST_FW) -int dbus_download_firmware(dhd_bus_t *pub, char *pfw_path, char *pnv_path) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - int err = DBUS_OK; - - if (!dhd_bus) { - DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__)); - return DBUS_ERR; - } - - DBUSTRACE(("%s: state %d\n", __FUNCTION__, dhd_bus->pub.busstate)); - - dhd_bus->pub.busstate = DBUS_STATE_DL_PENDING; -#ifdef EXTERNAL_FW_PATH - err = dbus_do_download(dhd_bus, pfw_path, pnv_path); -#else - err = dbus_do_download(dhd_bus); -#endif /* EXTERNAL_FW_PATH */ - if (err == DBUS_OK) { - dhd_bus->pub.busstate = DBUS_STATE_DL_DONE; - } else { - DBUSERR(("%s: download failed (%d)\n", __FUNCTION__, err)); - } - - return err; -} -#endif - -/** - * higher layer requests us to 'up' the interface to the dongle. Prerequisite is that firmware (not - * bootloader) must be active in the dongle. - */ -int -dbus_up(struct dhd_bus *pub) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - int err = DBUS_OK; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (dhd_bus == NULL) { - DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__)); - return DBUS_ERR; - } - - if ((dhd_bus->pub.busstate == DBUS_STATE_DL_DONE) || - (dhd_bus->pub.busstate == DBUS_STATE_DOWN) || - (dhd_bus->pub.busstate == DBUS_STATE_SLEEP)) { - if (dhd_bus->drvintf && dhd_bus->drvintf->up) { - err = dhd_bus->drvintf->up(dhd_bus->bus_info); - - if (err == DBUS_OK) { - dbus_rxirbs_fill(dhd_bus); - } - } - } else - err = DBUS_ERR; - - return err; -} - -/** higher layer requests us to 'down' the interface to the dongle. */ -int -dbus_down(dbus_pub_t *pub) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (dhd_bus == NULL) - return DBUS_ERR; - - dbus_tx_timer_stop(dhd_bus); - - if (dhd_bus->pub.busstate == DBUS_STATE_UP || - dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { - if (dhd_bus->drvintf && dhd_bus->drvintf->down) - return dhd_bus->drvintf->down(dhd_bus->bus_info); - } - - return DBUS_ERR; -} - -int -dbus_shutdown(dbus_pub_t *pub) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (dhd_bus == NULL) - return DBUS_ERR; - - if (dhd_bus->drvintf && dhd_bus->drvintf->shutdown) - return dhd_bus->drvintf->shutdown(dhd_bus->bus_info); - - return DBUS_OK; -} - -int -dbus_stop(struct dhd_bus *pub) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (dhd_bus == NULL) - return DBUS_ERR; - - if (dhd_bus->pub.busstate == DBUS_STATE_UP || - dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { - if (dhd_bus->drvintf && dhd_bus->drvintf->stop) - return dhd_bus->drvintf->stop(dhd_bus->bus_info); - } - - return DBUS_ERR; -} - -int dbus_send_txdata(dbus_pub_t *dbus, void *pktbuf) -{ - return dbus_send_pkt(dbus, pktbuf, pktbuf /* pktinfo */); -} - -int -dbus_send_buf(dbus_pub_t *pub, uint8 *buf, int len, void *info) -{ - return dbus_send_irb(pub, buf, len, NULL, info); -} - -int -dbus_send_pkt(dbus_pub_t *pub, void *pkt, void *info) -{ - return dbus_send_irb(pub, NULL, 0, pkt, info); -} - -int -dbus_send_ctl(struct dhd_bus *pub, uint8 *buf, int len) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - - if (dhd_bus == NULL) { - DBUSERR(("%s: dhd_bus is NULL\n", __FUNCTION__)); - return DBUS_ERR; - } - - if (dhd_bus->pub.busstate == DBUS_STATE_UP || - dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { - if (dhd_bus->drvintf && dhd_bus->drvintf->send_ctl) - return dhd_bus->drvintf->send_ctl(dhd_bus->bus_info, buf, len); - } else { - DBUSERR(("%s: bustate=%d\n", __FUNCTION__, dhd_bus->pub.busstate)); - } - - return DBUS_ERR; -} - -int -dbus_recv_ctl(struct dhd_bus *pub, uint8 *buf, int len) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - - if ((dhd_bus == NULL) || (buf == NULL)) - return DBUS_ERR; - - if (dhd_bus->pub.busstate == DBUS_STATE_UP || - dhd_bus->pub.busstate == DBUS_STATE_SLEEP) { - if (dhd_bus->drvintf && dhd_bus->drvintf->recv_ctl) - return dhd_bus->drvintf->recv_ctl(dhd_bus->bus_info, buf, len); - } - - return DBUS_ERR; -} - -/** Only called via RPC (Dec 2012) */ -int -dbus_recv_bulk(dbus_pub_t *pub, uint32 ep_idx) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - - dbus_irb_rx_t *rxirb; - struct exec_parms args; - int status; - - - if (dhd_bus == NULL) - return DBUS_ERR; - - args.qdeq.q = dhd_bus->rx_q; - if (dhd_bus->pub.busstate == DBUS_STATE_UP) { - if (dhd_bus->drvintf && dhd_bus->drvintf->recv_irb_from_ep) { - if ((rxirb = (EXEC_RXLOCK(dhd_bus, q_deq_exec, &args))) != NULL) { - status = dhd_bus->drvintf->recv_irb_from_ep(dhd_bus->bus_info, - rxirb, ep_idx); - if (status == DBUS_ERR_RXDROP) { - bzero(rxirb, sizeof(dbus_irb_rx_t)); - args.qenq.q = dhd_bus->rx_q; - args.qenq.b = (dbus_irb_t *) rxirb; - EXEC_RXLOCK(dhd_bus, q_enq_exec, &args); - } - } - } - } - - return DBUS_ERR; -} - -/** only called by dhd_cdc.c (Dec 2012) */ -int -dbus_poll_intr(dbus_pub_t *pub) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - - int status = DBUS_ERR; - - if (dhd_bus == NULL) - return DBUS_ERR; - - if (dhd_bus->pub.busstate == DBUS_STATE_UP) { - if (dhd_bus->drvintf && dhd_bus->drvintf->recv_irb_from_ep) { - status = dhd_bus->drvintf->recv_irb_from_ep(dhd_bus->bus_info, - NULL, 0xff); - } - } - return status; -} - -/** called by nobody (Dec 2012) */ -void * -dbus_pktget(dbus_pub_t *pub, int len) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - - if ((dhd_bus == NULL) || (len < 0)) - return NULL; - - return PKTGET(dhd_bus->pub.osh, len, TRUE); -} - -/** called by nobody (Dec 2012) */ -void -dbus_pktfree(dbus_pub_t *pub, void* pkt) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - - if ((dhd_bus == NULL) || (pkt == NULL)) - return; - - PKTFREE(dhd_bus->pub.osh, pkt, TRUE); -} - -/** called by nobody (Dec 2012) */ -int -dbus_get_stats(dbus_pub_t *pub, dbus_stats_t *stats) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - - if ((dhd_bus == NULL) || (stats == NULL)) - return DBUS_ERR; - - bcopy(&dhd_bus->pub.stats, stats, sizeof(dbus_stats_t)); - - return DBUS_OK; -} - -int -dbus_get_attrib(dhd_bus_t *pub, dbus_attrib_t *attrib) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - int err = DBUS_ERR; - - if ((dhd_bus == NULL) || (attrib == NULL)) - return DBUS_ERR; - - if (dhd_bus->drvintf && dhd_bus->drvintf->get_attrib) { - err = dhd_bus->drvintf->get_attrib(dhd_bus->bus_info, - &dhd_bus->pub.attrib); - } - - bcopy(&dhd_bus->pub.attrib, attrib, sizeof(dbus_attrib_t)); - return err; -} - -int -dbus_get_device_speed(dbus_pub_t *pub) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - - if (dhd_bus == NULL) - return INVALID_SPEED; - - return (dhd_bus->pub.device_speed); -} - -int -dbus_set_config(dbus_pub_t *pub, dbus_config_t *config) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - int err = DBUS_ERR; - - if ((dhd_bus == NULL) || (config == NULL)) - return DBUS_ERR; - - if (dhd_bus->drvintf && dhd_bus->drvintf->set_config) { - err = dhd_bus->drvintf->set_config(dhd_bus->bus_info, - config); - - if ((config->config_id == DBUS_CONFIG_ID_AGGR_LIMIT) && - (!err) && - (dhd_bus->pub.busstate == DBUS_STATE_UP)) { - dbus_rxirbs_fill(dhd_bus); - } - } - - return err; -} - -int -dbus_get_config(dbus_pub_t *pub, dbus_config_t *config) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - int err = DBUS_ERR; - - if ((dhd_bus == NULL) || (config == NULL)) - return DBUS_ERR; - - if (dhd_bus->drvintf && dhd_bus->drvintf->get_config) { - err = dhd_bus->drvintf->get_config(dhd_bus->bus_info, - config); - } - - return err; -} - -int -dbus_set_errmask(dbus_pub_t *pub, uint32 mask) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - int err = DBUS_OK; - - if (dhd_bus == NULL) - return DBUS_ERR; - - dhd_bus->errmask = mask; - return err; -} - -int -dbus_pnp_resume(dbus_pub_t *pub, int *fw_reload) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - int err = DBUS_ERR; - bool fwdl = FALSE; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (dhd_bus == NULL) - return DBUS_ERR; - - if (dhd_bus->pub.busstate == DBUS_STATE_UP) { - return DBUS_OK; - } - - - - if (dhd_bus->drvintf->pnp) { - err = dhd_bus->drvintf->pnp(dhd_bus->bus_info, - DBUS_PNP_RESUME); - } - - if (dhd_bus->drvintf->recv_needed) { - if (dhd_bus->drvintf->recv_needed(dhd_bus->bus_info)) { - /* Refill after sleep/hibernate */ - dbus_rxirbs_fill(dhd_bus); - } - } - - - if (fw_reload) - *fw_reload = fwdl; - - return err; -} /* dbus_pnp_resume */ - -int -dbus_pnp_sleep(dbus_pub_t *pub) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - int err = DBUS_ERR; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (dhd_bus == NULL) - return DBUS_ERR; - - dbus_tx_timer_stop(dhd_bus); - - if (dhd_bus->drvintf && dhd_bus->drvintf->pnp) { - err = dhd_bus->drvintf->pnp(dhd_bus->bus_info, - DBUS_PNP_SLEEP); - } - - return err; -} - -int -dbus_pnp_disconnect(dbus_pub_t *pub) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) pub; - int err = DBUS_ERR; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (dhd_bus == NULL) - return DBUS_ERR; - - dbus_tx_timer_stop(dhd_bus); - - if (dhd_bus->drvintf && dhd_bus->drvintf->pnp) { - err = dhd_bus->drvintf->pnp(dhd_bus->bus_info, - DBUS_PNP_DISCONNECT); - } - - return err; -} - -int -dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - dhd_bus_t *dhd_bus = (dhd_bus_t *) dhdp->bus; - int err = DBUS_ERR; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (dhd_bus == NULL) - return DBUS_ERR; - - if (dhd_bus->drvintf && dhd_bus->drvintf->iovar_op) { - err = dhd_bus->drvintf->iovar_op(dhd_bus->bus_info, - name, params, plen, arg, len, set); - } - - return err; -} - - -void * -dhd_dbus_txq(const dbus_pub_t *pub) -{ - return NULL; -} - -uint -dhd_dbus_hdrlen(const dbus_pub_t *pub) -{ - return 0; -} - -void * -dbus_get_devinfo(dbus_pub_t *pub) -{ - return pub->dev_info; -} - -#if defined(BCM_REQUEST_FW) && !defined(EXTERNAL_FW_PATH) -static int -dbus_otp(dhd_bus_t *dhd_bus, uint16 *boardtype, uint16 *boardrev) -{ - uint32 value = 0; - uint8 *cis; - uint16 *otpinfo; - uint32 i; - bool standard_cis = TRUE; - uint8 tup, tlen; - bool btype_present = FALSE; - bool brev_present = FALSE; - int ret; - int devid; - uint16 btype = 0; - uint16 brev = 0; - uint32 otp_size = 0, otp_addr = 0, otp_sw_rgn = 0; - - if (dhd_bus == NULL || dhd_bus->drvintf == NULL || - dhd_bus->drvintf->readreg == NULL) - return DBUS_ERR; - - devid = dhd_bus->pub.attrib.devid; - - if ((devid == BCM43234_CHIP_ID) || (devid == BCM43235_CHIP_ID) || - (devid == BCM43236_CHIP_ID)) { - - otp_size = BCM_OTP_SIZE_43236; - otp_sw_rgn = BCM_OTP_SW_RGN_43236; - otp_addr = BCM_OTP_ADDR_43236; - - } else { - return DBUS_ERR_NVRAM; - } - - cis = MALLOC(dhd_bus->pub.osh, otp_size * 2); - if (cis == NULL) - return DBUS_ERR; - - otpinfo = (uint16 *) cis; - - for (i = 0; i < otp_size; i++) { - - ret = dhd_bus->drvintf->readreg(dhd_bus->bus_info, - otp_addr + ((otp_sw_rgn + i) << 1), 2, &value); - - if (ret != DBUS_OK) { - MFREE(dhd_bus->pub.osh, cis, otp_size * 2); - return ret; - } - otpinfo[i] = (uint16) value; - } - - for (i = 0; i < (otp_size << 1); ) { - - if (standard_cis) { - tup = cis[i++]; - if (tup == CISTPL_NULL || tup == CISTPL_END) - tlen = 0; - else - tlen = cis[i++]; - } else { - if (cis[i] == CISTPL_NULL || cis[i] == CISTPL_END) { - tlen = 0; - tup = cis[i]; - } else { - tlen = cis[i]; - tup = CISTPL_BRCM_HNBU; - } - ++i; - } - - if (tup == CISTPL_END || (i + tlen) >= (otp_size << 1)) { - break; - } - - switch (tup) { - - case CISTPL_BRCM_HNBU: - - switch (cis[i]) { - - case HNBU_BOARDTYPE: - - btype = (uint16) ((cis[i + 2] << 8) + cis[i + 1]); - btype_present = TRUE; - DBUSTRACE(("%s: HNBU_BOARDTYPE = 0x%2x\n", __FUNCTION__, - (uint32)btype)); - break; - - case HNBU_BOARDREV: - - if (tlen == 2) - brev = (uint16) cis[i + 1]; - else - brev = (uint16) ((cis[i + 2] << 8) + cis[i + 1]); - brev_present = TRUE; - DBUSTRACE(("%s: HNBU_BOARDREV = 0x%2x\n", __FUNCTION__, - (uint32)*boardrev)); - break; - - case HNBU_HNBUCIS: - DBUSTRACE(("%s: HNBU_HNBUCIS\n", __FUNCTION__)); - tlen++; - standard_cis = FALSE; - break; - } - break; - } - - i += tlen; - } - - MFREE(dhd_bus->pub.osh, cis, otp_size * 2); - - if (btype_present == TRUE && brev_present == TRUE) { - *boardtype = btype; - *boardrev = brev; - DBUSERR(("otp boardtype = 0x%2x boardrev = 0x%2x\n", - *boardtype, *boardrev)); - - return DBUS_OK; - } - else - return DBUS_ERR; -} /* dbus_otp */ - -static int -dbus_select_nvram(dhd_bus_t *dhd_bus, int8 *jumbonvram, int jumbolen, -uint16 boardtype, uint16 boardrev, int8 **nvram, int *nvram_len) -{ - /* Multi board nvram file format is contenation of nvram info with \r - * The file format for two contatenated set is - * \nBroadcom Jumbo Nvram file\nfirst_set\nsecond_set\nthird_set\n - */ - uint8 *nvram_start = NULL, *nvram_end = NULL; - uint8 *nvram_start_prev = NULL, *nvram_end_prev = NULL; - uint16 btype = 0, brev = 0; - int len = 0; - char *field; - - *nvram = NULL; - *nvram_len = 0; - - if (strncmp(BCM_JUMBO_START, jumbonvram, strlen(BCM_JUMBO_START))) { - /* single nvram file in the native format */ - DBUSTRACE(("%s: Non-Jumbo NVRAM File \n", __FUNCTION__)); - *nvram = jumbonvram; - *nvram_len = jumbolen; - return DBUS_OK; - } else { - DBUSTRACE(("%s: Jumbo NVRAM File \n", __FUNCTION__)); - } - - /* sanity test the end of the config sets for proper ending */ - if (jumbonvram[jumbolen - 1] != BCM_JUMBO_NVRAM_DELIMIT || - jumbonvram[jumbolen - 2] != '\0') { - DBUSERR(("%s: Bad Jumbo NVRAM file format\n", __FUNCTION__)); - return DBUS_JUMBO_BAD_FORMAT; - } - - dhd_bus->nvram_nontxt = DBUS_NVRAM_NONTXT; - - nvram_start = jumbonvram; - - while (*nvram_start != BCM_JUMBO_NVRAM_DELIMIT && len < jumbolen) { - - /* consume the first file info line - * \nBroadcom Jumbo Nvram file\nfile1\n ... - */ - len ++; - nvram_start ++; - } - - nvram_end = nvram_start; - - /* search for "boardrev=0xabcd" and "boardtype=0x1234" information in - * the concatenated nvram config files /sets - */ - - while (len < jumbolen) { - - if (*nvram_end == '\0') { - /* end of a config set is marked by multiple null characters */ - len ++; - nvram_end ++; - DBUSTRACE(("%s: NULL chr len = %d char = 0x%x\n", __FUNCTION__, - len, *nvram_end)); - continue; - - } else if (*nvram_end == BCM_JUMBO_NVRAM_DELIMIT) { - - /* config set delimiter is reached */ - /* check if next config set is present or not - * return if next config is not present - */ - - /* start search the next config set */ - nvram_start_prev = nvram_start; - nvram_end_prev = nvram_end; - - nvram_end ++; - nvram_start = nvram_end; - btype = brev = 0; - DBUSTRACE(("%s: going to next record len = %d " - "char = 0x%x \n", __FUNCTION__, len, *nvram_end)); - len ++; - if (len >= jumbolen) { - - *nvram = nvram_start_prev; - *nvram_len = (int)(nvram_end_prev - nvram_start_prev); - - DBUSTRACE(("%s: no more len = %d nvram_end = 0x%p", - __FUNCTION__, len, nvram_end)); - - return DBUS_JUMBO_NOMATCH; - - } else { - continue; - } - - } else { - - DBUSTRACE(("%s: config str = %s\n", __FUNCTION__, nvram_end)); - - if (bcmp(nvram_end, "boardtype", strlen("boardtype")) == 0) { - - field = strchr(nvram_end, '='); - field++; - btype = (uint16)bcm_strtoul(field, NULL, 0); - - DBUSTRACE(("%s: btype = 0x%x boardtype = 0x%x \n", __FUNCTION__, - btype, boardtype)); - } - - if (bcmp(nvram_end, "boardrev", strlen("boardrev")) == 0) { - - field = strchr(nvram_end, '='); - field++; - brev = (uint16)bcm_strtoul(field, NULL, 0); - - DBUSTRACE(("%s: brev = 0x%x boardrev = 0x%x \n", __FUNCTION__, - brev, boardrev)); - } - if (btype == boardtype && brev == boardrev) { - /* locate nvram config set end - ie.find '\r' char */ - while (*nvram_end != BCM_JUMBO_NVRAM_DELIMIT) - nvram_end ++; - *nvram = nvram_start; - *nvram_len = (int) (nvram_end - nvram_start); - DBUSTRACE(("found len = %d nvram_start = 0x%p " - "nvram_end = 0x%p\n", *nvram_len, nvram_start, nvram_end)); - return DBUS_OK; - } - - len += (strlen(nvram_end) + 1); - nvram_end += (strlen(nvram_end) + 1); - } - } - return DBUS_JUMBO_NOMATCH; -} /* dbus_select_nvram */ - -#endif - -#define DBUS_NRXQ 50 -#define DBUS_NTXQ 100 - -static void -dhd_dbus_send_complete(void *handle, void *info, int status) -{ - dhd_pub_t *dhd = (dhd_pub_t *)handle; - void *pkt = info; - - if ((dhd == NULL) || (pkt == NULL)) { - DBUSERR(("dhd or pkt is NULL\n")); - return; - } - - if (status == DBUS_OK) { - dhd->dstats.tx_packets++; - } else { - DBUSERR(("TX error=%d\n", status)); - dhd->dstats.tx_errors++; - } -#ifdef PROP_TXSTATUS - if (DHD_PKTTAG_WLFCPKT(PKTTAG(pkt)) && - (dhd_wlfc_txcomplete(dhd, pkt, status == 0) != WLFC_UNSUPPORTED)) { - return; - } -#endif /* PROP_TXSTATUS */ - PKTFREE(dhd->osh, pkt, TRUE); -} - -static void -dhd_dbus_recv_pkt(void *handle, void *pkt) -{ - uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; - uint reorder_info_len; - uint pkt_count; - dhd_pub_t *dhd = (dhd_pub_t *)handle; - int ifidx = 0; - - if (dhd == NULL) { - DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); - return; - } - - /* If the protocol uses a data header, check and remove it */ - if (dhd_prot_hdrpull(dhd, &ifidx, pkt, reorder_info_buf, - &reorder_info_len) != 0) { - DBUSERR(("rx protocol error\n")); - PKTFREE(dhd->osh, pkt, FALSE); - dhd->rx_errors++; - return; - } - - if (reorder_info_len) { - /* Reordering info from the firmware */ - dhd_process_pkt_reorder_info(dhd, reorder_info_buf, reorder_info_len, - &pkt, &pkt_count); - if (pkt_count == 0) - return; - } - else { - pkt_count = 1; - } - dhd_rx_frame(dhd, ifidx, pkt, pkt_count, 0); -} - -static void -dhd_dbus_recv_buf(void *handle, uint8 *buf, int len) -{ - dhd_pub_t *dhd = (dhd_pub_t *)handle; - void *pkt; - - if (dhd == NULL) { - DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); - return; - } - - if ((pkt = PKTGET(dhd->osh, len, FALSE)) == NULL) { - DBUSERR(("PKTGET (rx) failed=%d\n", len)); - return; - } - - bcopy(buf, PKTDATA(dhd->osh, pkt), len); - dhd_dbus_recv_pkt(dhd, pkt); -} - -static void -dhd_dbus_txflowcontrol(void *handle, bool onoff) -{ - dhd_pub_t *dhd = (dhd_pub_t *)handle; - bool wlfc_enabled = FALSE; - - if (dhd == NULL) { - DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); - return; - } - -#ifdef PROP_TXSTATUS - wlfc_enabled = (dhd_wlfc_flowcontrol(dhd, onoff, !onoff) != WLFC_UNSUPPORTED); -#endif - - if (!wlfc_enabled) { - dhd_txflowcontrol(dhd, ALL_INTERFACES, onoff); - } -} - -static void -dhd_dbus_errhandler(void *handle, int err) -{ -} - -static void -dhd_dbus_ctl_complete(void *handle, int type, int status) -{ - dhd_pub_t *dhd = (dhd_pub_t *)handle; - - if (dhd == NULL) { - DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); - return; - } - - if (type == DBUS_CBCTL_READ) { - if (status == DBUS_OK) - dhd->rx_ctlpkts++; - else - dhd->rx_ctlerrs++; - } else if (type == DBUS_CBCTL_WRITE) { - if (status == DBUS_OK) - dhd->tx_ctlpkts++; - else - dhd->tx_ctlerrs++; - } - - dhd_prot_ctl_complete(dhd); -} - -static void -dhd_dbus_state_change(void *handle, int state) -{ - dhd_pub_t *dhd = (dhd_pub_t *)handle; - - if (dhd == NULL) { - DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); - return; - } - - switch (state) { - - case DBUS_STATE_DL_NEEDED: - DBUSERR(("%s: firmware request cannot be handled\n", __FUNCTION__)); - break; - case DBUS_STATE_DOWN: - DBUSTRACE(("%s: DBUS is down\n", __FUNCTION__)); - dhd->busstate = DHD_BUS_DOWN; - break; - case DBUS_STATE_UP: - DBUSTRACE(("%s: DBUS is up\n", __FUNCTION__)); - dhd->busstate = DHD_BUS_DATA; - break; - default: - break; - } - - DBUSERR(("%s: DBUS current state=%d\n", __FUNCTION__, state)); -} - -static void * -dhd_dbus_pktget(void *handle, uint len, bool send) -{ - dhd_pub_t *dhd = (dhd_pub_t *)handle; - void *p = NULL; - - if (dhd == NULL) { - DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); - return NULL; - } - - if (send == TRUE) { - dhd_os_sdlock_txq(dhd); - p = PKTGET(dhd->osh, len, TRUE); - dhd_os_sdunlock_txq(dhd); - } else { - dhd_os_sdlock_rxq(dhd); - p = PKTGET(dhd->osh, len, FALSE); - dhd_os_sdunlock_rxq(dhd); - } - - return p; -} - -static void -dhd_dbus_pktfree(void *handle, void *p, bool send) -{ - dhd_pub_t *dhd = (dhd_pub_t *)handle; - - if (dhd == NULL) { - DBUSERR(("%s: dhd is NULL\n", __FUNCTION__)); - return; - } - - if (send == TRUE) { -#ifdef PROP_TXSTATUS - if (DHD_PKTTAG_WLFCPKT(PKTTAG(p)) && - (dhd_wlfc_txcomplete(dhd, p, FALSE) != WLFC_UNSUPPORTED)) { - return; - } -#endif /* PROP_TXSTATUS */ - - dhd_os_sdlock_txq(dhd); - PKTFREE(dhd->osh, p, TRUE); - dhd_os_sdunlock_txq(dhd); - } else { - dhd_os_sdlock_rxq(dhd); - PKTFREE(dhd->osh, p, FALSE); - dhd_os_sdunlock_rxq(dhd); - } -} - - -static dbus_callbacks_t dhd_dbus_cbs = { - dhd_dbus_send_complete, - dhd_dbus_recv_buf, - dhd_dbus_recv_pkt, - dhd_dbus_txflowcontrol, - dhd_dbus_errhandler, - dhd_dbus_ctl_complete, - dhd_dbus_state_change, - dhd_dbus_pktget, - dhd_dbus_pktfree -}; - -uint -dhd_bus_chip(struct dhd_bus *bus) -{ - ASSERT(bus != NULL); - return bus->pub.attrib.devid; -} - -uint -dhd_bus_chiprev(struct dhd_bus *bus) -{ - ASSERT(bus); - ASSERT(bus != NULL); - return bus->pub.attrib.chiprev; -} - -void -dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -{ - bcm_bprintf(strbuf, "Bus USB\n"); -} - -void -dhd_bus_clearcounts(dhd_pub_t *dhdp) -{ -} - -int -dhd_bus_txdata(struct dhd_bus *bus, void *pktbuf) -{ - DBUSTRACE(("%s\n", __FUNCTION__)); - if (bus->txoff) { - DBUSTRACE(("txoff\n")); - return BCME_EPERM; - } - return dbus_send_txdata(&bus->pub, pktbuf); -} - -static void -dhd_dbus_advertise_bus_cleanup(dhd_pub_t *dhdp) -{ - unsigned long flags; - int timeleft; - - DHD_LINUX_GENERAL_LOCK(dhdp, flags); - dhdp->busstate = DHD_BUS_DOWN_IN_PROGRESS; - DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); - - timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state); - if ((timeleft == 0) || (timeleft == 1)) { - DBUSERR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n", - __FUNCTION__, dhdp->dhd_bus_busy_state)); - ASSERT(0); - } - - return; -} - -static void -dhd_dbus_advertise_bus_remove(dhd_pub_t *dhdp) -{ - unsigned long flags; - int timeleft; - - DHD_LINUX_GENERAL_LOCK(dhdp, flags); - dhdp->busstate = DHD_BUS_REMOVE; - DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); - - timeleft = dhd_os_busbusy_wait_negation(dhdp, &dhdp->dhd_bus_busy_state); - if ((timeleft == 0) || (timeleft == 1)) { - DBUSERR(("%s : Timeout due to dhd_bus_busy_state=0x%x\n", - __FUNCTION__, dhdp->dhd_bus_busy_state)); - ASSERT(0); - } - - return; -} - -int -dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) -{ - int bcmerror = 0; - unsigned long flags; - wifi_adapter_info_t *adapter = (wifi_adapter_info_t *)dhdp->adapter; - - if (flag == TRUE) { - if (!dhdp->dongle_reset) { - DBUSERR(("%s: == Power OFF ==\n", __FUNCTION__)); - dhd_dbus_advertise_bus_cleanup(dhdp); - dhd_os_wd_timer(dhdp, 0); -#if !defined(IGNORE_ETH0_DOWN) - /* Force flow control as protection when stop come before ifconfig_down */ - dhd_txflowcontrol(dhdp, ALL_INTERFACES, ON); -#endif /* !defined(IGNORE_ETH0_DOWN) */ - dbus_stop(dhdp->bus); - - dhdp->dongle_reset = TRUE; - dhdp->up = FALSE; - - DHD_LINUX_GENERAL_LOCK(dhdp, flags); - dhdp->busstate = DHD_BUS_DOWN; - DHD_LINUX_GENERAL_UNLOCK(dhdp, flags); - wifi_clr_adapter_status(adapter, WIFI_STATUS_FW_READY); - - printf("%s: WLAN OFF DONE\n", __FUNCTION__); - /* App can now remove power from device */ - } else - bcmerror = BCME_ERROR; - } else { - /* App must have restored power to device before calling */ - printf("\n\n%s: == WLAN ON ==\n", __FUNCTION__); - if (dhdp->dongle_reset) { - /* Turn on WLAN */ - DHD_MUTEX_UNLOCK(); - wait_event_interruptible_timeout(adapter->status_event, - wifi_get_adapter_status(adapter, WIFI_STATUS_FW_READY), - msecs_to_jiffies(DHD_FW_READY_TIMEOUT)); - DHD_MUTEX_LOCK(); - bcmerror = dbus_up(dhdp->bus); - if (bcmerror == BCME_OK) { - dhdp->dongle_reset = FALSE; - dhdp->up = TRUE; -#if !defined(IGNORE_ETH0_DOWN) - /* Restore flow control */ - dhd_txflowcontrol(dhdp, ALL_INTERFACES, OFF); -#endif - dhd_os_wd_timer(dhdp, dhd_watchdog_ms); - - DBUSTRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); - } else { - DBUSERR(("%s: failed to dbus_up with code %d\n", __FUNCTION__, bcmerror)); - } - } - } - -#ifdef PKT_STATICS - memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t)); -#endif - return bcmerror; -} - -void -dhd_set_path_params(struct dhd_bus *bus) -{ - /* External conf takes precedence if specified */ - dhd_conf_preinit(bus->dhd); - - if (bus->dhd->conf_path[0] == '\0') { - dhd_conf_set_path(bus->dhd, "config.txt", bus->dhd->conf_path, bus->nv_path); - } - if (bus->dhd->reg_path[0] == '\0') { - dhd_conf_set_path(bus->dhd, "reg.txt", bus->dhd->reg_path, bus->nv_path); - } - if (bus->dhd->clm_path[0] == '\0') { - dhd_conf_set_path(bus->dhd, "clm.blob", bus->dhd->clm_path, bus->fw_path); - } -#ifdef CONFIG_PATH_AUTO_SELECT - dhd_conf_set_conf_name_by_chip(bus->dhd, bus->dhd->conf_path); - dhd_conf_set_reg_name_by_chip(bus->dhd, bus->dhd->reg_path); -#endif - - dhd_conf_read_config(bus->dhd, bus->dhd->conf_path); - dhd_conf_read_reg(bus->dhd, bus->dhd->reg_path); - - dhd_conf_set_fw_name_by_chip(bus->dhd, bus->fw_path); - dhd_conf_set_nv_name_by_chip(bus->dhd, bus->nv_path); - dhd_conf_set_clm_name_by_chip(bus->dhd, bus->dhd->clm_path); - - printf("Final fw_path=%s\n", bus->fw_path); - printf("Final nv_path=%s\n", bus->nv_path); - printf("Final clm_path=%s\n", bus->dhd->clm_path); - printf("Final conf_path=%s\n", bus->dhd->conf_path); - printf("Final reg_path=%s\n", bus->dhd->reg_path); -} - -void -dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, - char *pnv_path, char *pclm_path, char *pconf_path, char *preg_path) -{ - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (bus == NULL) { - DBUSERR(("%s: bus is NULL\n", __FUNCTION__)); - return; - } - - bus->fw_path = pfw_path; - bus->nv_path = pnv_path; - bus->dhd->clm_path = pclm_path; - bus->dhd->conf_path = pconf_path; - bus->dhd->reg_path = preg_path; - - dhd_set_path_params(bus); - -} - -/* - * hdrlen is space to reserve in pkt headroom for DBUS - */ -void * -dhd_dbus_probe_cb(void *arg, const char *desc, uint32 bustype, - uint16 bus_no, uint16 slot, uint32 hdrlen) -{ - osl_t *osh = NULL; - dhd_bus_t *bus = NULL; - dhd_pub_t *pub = NULL; - uint rxsz; - int dlneeded = 0; - wifi_adapter_info_t *adapter = NULL; - - DBUSTRACE(("%s: Enter\n", __FUNCTION__)); - - adapter = dhd_wifi_platform_get_adapter(bustype, bus_no, slot); - - if (!g_pub) { - /* Ask the OS interface part for an OSL handle */ - if (!(osh = osl_attach(NULL, bustype, TRUE))) { - DBUSERR(("%s: OSL attach failed\n", __FUNCTION__)); - goto fail; - } - - /* Attach to the dhd/OS interface */ - if (!(pub = dhd_attach(osh, bus, hdrlen, adapter))) { - DBUSERR(("%s: dhd_attach failed\n", __FUNCTION__)); - goto fail; - } - } else { - pub = g_pub; - } - - if (pub->bus) { - DBUSERR(("%s: wrong probe\n", __FUNCTION__)); - goto fail; - } - - rxsz = dhd_get_rxsz(pub); - bus = dbus_attach(osh, rxsz, DBUS_NRXQ, DBUS_NTXQ, pub, &dhd_dbus_cbs, NULL, NULL); - if (bus) { - pub->bus = bus; - bus->dhd = pub; - - dlneeded = dbus_dlneeded(bus); - if (dlneeded >= 0) { - if (!g_pub) { - dhd_conf_reset(pub); - dhd_conf_set_chiprev(pub, bus->pub.attrib.devid, bus->pub.attrib.chiprev); - dhd_conf_preinit(pub); - } - } - - if (g_pub || dhd_download_fw_on_driverload) { - if (dlneeded == 0) { - wifi_set_adapter_status(adapter, WIFI_STATUS_FW_READY); -#ifdef BCM_REQUEST_FW - } else if (dlneeded > 0) { - dhd_set_path(bus->dhd); - if (dbus_download_firmware(bus, bus->fw_path, bus->nv_path) != DBUS_OK) - goto fail; -#endif - } - } - } else { - DBUSERR(("%s: dbus_attach failed\n", __FUNCTION__)); - } - - if (!g_pub) { - /* Ok, finish the attach to the OS network interface */ - if (dhd_register_if(pub, 0, TRUE) != 0) { - DBUSERR(("%s: dhd_register_if failed\n", __FUNCTION__)); - goto fail; - } - pub->hang_report = TRUE; -#if defined(MULTIPLE_SUPPLICANT) - wl_android_post_init(); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe -#endif - g_pub = pub; - } - - DBUSTRACE(("%s: Exit\n", __FUNCTION__)); - wifi_clr_adapter_status(adapter, WIFI_STATUS_DETTACH); - wifi_set_adapter_status(adapter, WIFI_STATUS_ATTACH); - wake_up_interruptible(&adapter->status_event); - /* This is passed to dhd_dbus_disconnect_cb */ - return bus; - -fail: - if (pub && pub->bus) { - dbus_detach(pub->bus); - pub->bus = NULL; - } - /* Release resources in reverse order */ - if (!g_pub) { - if (pub) { - dhd_detach(pub); - dhd_free(pub); - } - if (osh) { - osl_detach(osh); - } - } - - printf("%s: Failed\n", __FUNCTION__); - return NULL; -} - -void -dhd_dbus_disconnect_cb(void *arg) -{ - dhd_bus_t *bus = (dhd_bus_t *)arg; - dhd_pub_t *pub = g_pub; - osl_t *osh; - wifi_adapter_info_t *adapter = NULL; - - adapter = (wifi_adapter_info_t *)pub->adapter; - - if (pub && !pub->dhd_remove && bus == NULL) { - DBUSERR(("%s: bus is NULL\n", __FUNCTION__)); - return; - } - if (!adapter) { - DBUSERR(("%s: adapter is NULL\n", __FUNCTION__)); - return; - } - - printf("%s: Enter dhd_remove=%d on %s\n", __FUNCTION__, - pub->dhd_remove, adapter->name); - if (!pub->dhd_remove) { - /* Advertise bus remove during rmmod */ - dhd_dbus_advertise_bus_remove(bus->dhd); - dbus_detach(pub->bus); - pub->bus = NULL; - wifi_clr_adapter_status(adapter, WIFI_STATUS_ATTACH); - wifi_set_adapter_status(adapter, WIFI_STATUS_DETTACH); - wake_up_interruptible(&adapter->status_event); - } else { - osh = pub->osh; - dhd_detach(pub); - if (pub->bus) { - dbus_detach(pub->bus); - pub->bus = NULL; - } - dhd_free(pub); - g_pub = NULL; - if (MALLOCED(osh)) { - DBUSERR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh))); - } - osl_detach(osh); - } - - DBUSTRACE(("%s: Exit\n", __FUNCTION__)); -} - -#ifdef LINUX_EXTERNAL_MODULE_DBUS - -static int __init -bcm_dbus_module_init(void) -{ - printf("Inserting bcm_dbus module \n"); - return 0; -} - -static void __exit -bcm_dbus_module_exit(void) -{ - printf("Removing bcm_dbus module \n"); - return; -} - -EXPORT_SYMBOL(dbus_pnp_sleep); -EXPORT_SYMBOL(dbus_get_devinfo); -EXPORT_SYMBOL(dbus_detach); -EXPORT_SYMBOL(dbus_get_attrib); -EXPORT_SYMBOL(dbus_down); -EXPORT_SYMBOL(dbus_pnp_resume); -EXPORT_SYMBOL(dbus_set_config); -EXPORT_SYMBOL(dbus_flowctrl_rx); -EXPORT_SYMBOL(dbus_up); -EXPORT_SYMBOL(dbus_get_device_speed); -EXPORT_SYMBOL(dbus_send_pkt); -EXPORT_SYMBOL(dbus_recv_ctl); -EXPORT_SYMBOL(dbus_attach); - -MODULE_LICENSE("GPL"); - -module_init(bcm_dbus_module_init); -module_exit(bcm_dbus_module_exit); - -#endif /* #ifdef LINUX_EXTERNAL_MODULE_DBUS */
diff --git a/bcmdhd.1.579.77.41.x/dbus_usb.c b/bcmdhd.1.579.77.41.x/dbus_usb.c deleted file mode 100644 index 8a496dd..0000000 --- a/bcmdhd.1.579.77.41.x/dbus_usb.c +++ /dev/null
@@ -1,1172 +0,0 @@ -/* - * Dongle BUS interface for USB, OS independent - * - * Copyright (C) 1999-2016, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dbus_usb.c 565557 2015-06-22 19:29:44Z $ - */ - -/** - * @file @brief - * This file contains DBUS code that is USB, but not OS specific. DBUS is a Broadcom proprietary - * host specific abstraction layer. - */ - -#include <osl.h> -#include <bcmdefs.h> -#include <bcmutils.h> -#include <dbus.h> -#include <usbrdl.h> -#include <bcmdevs.h> -#include <bcmendian.h> - -uint dbus_msglevel = DBUS_ERROR_VAL; -module_param(dbus_msglevel, int, 0); - - -#define USB_DLIMAGE_RETRY_TIMEOUT 3000 /* retry Timeout */ -#define USB_SFLASH_DLIMAGE_SPINWAIT 150 /* in unit of ms */ -#define USB_SFLASH_DLIMAGE_LIMIT 2000 /* spinwait limit (ms) */ -#define POSTBOOT_ID 0xA123 /* ID to detect if dongle has boot up */ -#define USB_RESETCFG_SPINWAIT 1 /* wait after resetcfg (ms) */ -#define USB_DEV_ISBAD(u) (u->pub->attrib.devid == 0xDEAD) -#define USB_DLGO_SPINWAIT 100 /* wait after DL_GO (ms) */ -#define TEST_CHIP 0x4328 - -typedef struct { - dbus_pub_t *pub; - - void *cbarg; - dbus_intf_callbacks_t *cbs; /** callbacks into higher DBUS level (dbus.c) */ - dbus_intf_t *drvintf; - void *usbosl_info; - uint32 rdlram_base_addr; - uint32 rdlram_size; -} usb_info_t; - -/* - * Callbacks common to all USB - */ -static void dbus_usb_disconnect(void *handle); -static void dbus_usb_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb); -static void dbus_usb_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status); -static void dbus_usb_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status); -static void dbus_usb_errhandler(void *handle, int err); -static void dbus_usb_ctl_complete(void *handle, int type, int status); -static void dbus_usb_state_change(void *handle, int state); -static struct dbus_irb* dbus_usb_getirb(void *handle, bool send); -static void dbus_usb_rxerr_indicate(void *handle, bool on); -#if !defined(BCM_REQUEST_FW) -static int dbus_usb_resetcfg(usb_info_t *usbinfo); -#endif -static int dbus_usb_iovar_op(void *bus, const char *name, - void *params, int plen, void *arg, int len, bool set); -static int dbus_iovar_process(usb_info_t* usbinfo, const char *name, - void *params, int plen, void *arg, int len, bool set); -static int dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid, - const char *name, void *params, int plen, void *arg, int len, int val_size); -static int dhdusb_downloadvars(usb_info_t *bus, void *arg, int len); - -static int dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen); -static int dbus_usb_dlstart(void *bus, uint8 *fw, int len); -static int dbus_usb_dlneeded(void *bus); -static int dbus_usb_dlrun(void *bus); -static int dbus_usb_rdl_dwnld_state(usb_info_t *usbinfo); - - -/* OS specific */ -extern bool dbus_usbos_dl_cmd(void *info, uint8 cmd, void *buffer, int buflen); -extern int dbus_usbos_wait(void *info, uint16 ms); -extern int dbus_write_membytes(usb_info_t *usbinfo, bool set, uint32 address, - uint8 *data, uint size); -extern bool dbus_usbos_dl_send_bulk(void *info, void *buffer, int len); -extern int dbus_usbos_loopback_tx(void *usbos_info_ptr, int cnt, int size); - -/** - * These functions are called by the lower DBUS level (dbus_usb_os.c) to notify this DBUS level - * (dbus_usb.c) of an event. - */ -static dbus_intf_callbacks_t dbus_usb_intf_cbs = { - dbus_usb_send_irb_timeout, - dbus_usb_send_irb_complete, - dbus_usb_recv_irb_complete, - dbus_usb_errhandler, - dbus_usb_ctl_complete, - dbus_usb_state_change, - NULL, /* isr */ - NULL, /* dpc */ - NULL, /* watchdog */ - NULL, /* dbus_if_pktget */ - NULL, /* dbus_if_pktfree */ - dbus_usb_getirb, - dbus_usb_rxerr_indicate -}; - -/* IOVar table */ -enum { - IOV_SET_DOWNLOAD_STATE = 1, - IOV_DBUS_MSGLEVEL, - IOV_MEMBYTES, - IOV_VARS, - IOV_LOOPBACK_TX -}; - -const bcm_iovar_t dhdusb_iovars[] = { - {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, - {"dbus_msglevel", IOV_DBUS_MSGLEVEL, 0, IOVT_UINT32, 0 }, - {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 }, - {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, - {"usb_lb_txfer", IOV_LOOPBACK_TX, 0, IOVT_BUFFER, 2 * sizeof(int) }, - {NULL, 0, 0, 0, 0 } -}; - -/* - * Need global for probe() and disconnect() since - * attach() is not called at probe and detach() - * can be called inside disconnect() - */ -static probe_cb_t probe_cb = NULL; -static disconnect_cb_t disconnect_cb = NULL; -static void *probe_arg = NULL; -static void *disc_arg = NULL; -static dbus_intf_t *g_dbusintf = NULL; -static dbus_intf_t dbus_usb_intf; /** functions called by higher layer DBUS into lower layer */ - -/* - * dbus_intf_t common to all USB - * These functions override dbus_usb_<os>.c. - */ -static void *dbus_usb_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs); -static void dbus_usb_detach(dbus_pub_t *pub, void *info); -static void * dbus_usb_probe(void *arg, const char *desc, uint32 bustype, - uint16 bus_no, uint16 slot, uint32 hdrlen); - -/* functions */ - -/** - * As part of DBUS initialization/registration, the higher level DBUS (dbus.c) needs to know what - * lower level DBUS functions to call (in both dbus_usb.c and dbus_usb_os.c). - */ -static void * -dbus_usb_probe(void *arg, const char *desc, uint32 bustype, uint16 bus_no, - uint16 slot, uint32 hdrlen) -{ - DBUSTRACE(("%s(): \n", __FUNCTION__)); - if (probe_cb) { - - if (g_dbusintf != NULL) { - /* First, initialize all lower-level functions as default - * so that dbus.c simply calls directly to dbus_usb_os.c. - */ - bcopy(g_dbusintf, &dbus_usb_intf, sizeof(dbus_intf_t)); - - /* Second, selectively override functions we need, if any. */ - dbus_usb_intf.attach = dbus_usb_attach; - dbus_usb_intf.detach = dbus_usb_detach; - dbus_usb_intf.iovar_op = dbus_usb_iovar_op; - dbus_usb_intf.dlstart = dbus_usb_dlstart; - dbus_usb_intf.dlneeded = dbus_usb_dlneeded; - dbus_usb_intf.dlrun = dbus_usb_dlrun; - } - - disc_arg = probe_cb(probe_arg, "DBUS USB", USB_BUS, bus_no, slot, hdrlen); - return disc_arg; - } - - return NULL; -} - -/** - * On return, *intf contains this or lower-level DBUS functions to be called by higher - * level (dbus.c) - */ -int -dbus_bus_register(int vid, int pid, probe_cb_t prcb, - disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2) -{ - int err; - - DBUSTRACE(("%s(): \n", __FUNCTION__)); - probe_cb = prcb; - disconnect_cb = discb; - probe_arg = prarg; - - *intf = &dbus_usb_intf; - - err = dbus_bus_osl_register(vid, pid, dbus_usb_probe, - dbus_usb_disconnect, NULL, &g_dbusintf, param1, param2); - - ASSERT(g_dbusintf); - return err; -} - -int -dbus_bus_deregister() -{ - DBUSTRACE(("%s(): \n", __FUNCTION__)); - return dbus_bus_osl_deregister(); -} - -/** initialization consists of registration followed by 'attach'. */ -void * -dbus_usb_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs) -{ - usb_info_t *usb_info; - - DBUSTRACE(("%s(): \n", __FUNCTION__)); - - if ((g_dbusintf == NULL) || (g_dbusintf->attach == NULL)) - return NULL; - - /* Sanity check for BUS_INFO() */ - ASSERT(OFFSETOF(usb_info_t, pub) == 0); - - usb_info = MALLOC(pub->osh, sizeof(usb_info_t)); - if (usb_info == NULL) - return NULL; - - bzero(usb_info, sizeof(usb_info_t)); - - usb_info->pub = pub; - usb_info->cbarg = cbarg; - usb_info->cbs = cbs; - - usb_info->usbosl_info = (dbus_pub_t *)g_dbusintf->attach(pub, - usb_info, &dbus_usb_intf_cbs); - if (usb_info->usbosl_info == NULL) { - MFREE(pub->osh, usb_info, sizeof(usb_info_t)); - return NULL; - } - - /* Save USB OS-specific driver entry points */ - usb_info->drvintf = g_dbusintf; - - pub->bus = usb_info; -#if !defined(BCM_REQUEST_FW) - if (!dbus_usb_resetcfg(usb_info)) { - usb_info->pub->busstate = DBUS_STATE_DL_DONE; - } -#endif - /* Return Lower layer info */ - return (void *) usb_info->usbosl_info; -} - -void -dbus_usb_detach(dbus_pub_t *pub, void *info) -{ - usb_info_t *usb_info = (usb_info_t *) pub->bus; - osl_t *osh = pub->osh; - - if (usb_info == NULL) - return; - - if (usb_info->drvintf && usb_info->drvintf->detach) - usb_info->drvintf->detach(pub, usb_info->usbosl_info); - - MFREE(osh, usb_info, sizeof(usb_info_t)); -} - -void -dbus_usb_disconnect(void *handle) -{ - DBUSTRACE(("%s(): \n", __FUNCTION__)); - if (disconnect_cb) - disconnect_cb(disc_arg); -} - -/** - * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be - * notified. - */ -static void -dbus_usb_send_irb_timeout(void *handle, dbus_irb_tx_t *txirb) -{ - usb_info_t *usb_info = (usb_info_t *) handle; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (usb_info == NULL) - return; - - if (usb_info->cbs && usb_info->cbs->send_irb_timeout) - usb_info->cbs->send_irb_timeout(usb_info->cbarg, txirb); -} - -/** - * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be - * notified. - */ -static void -dbus_usb_send_irb_complete(void *handle, dbus_irb_tx_t *txirb, int status) -{ - usb_info_t *usb_info = (usb_info_t *) handle; - - if (usb_info == NULL) - return; - - if (usb_info->cbs && usb_info->cbs->send_irb_complete) - usb_info->cbs->send_irb_complete(usb_info->cbarg, txirb, status); -} - -/** - * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be - * notified. - */ -static void -dbus_usb_recv_irb_complete(void *handle, dbus_irb_rx_t *rxirb, int status) -{ - usb_info_t *usb_info = (usb_info_t *) handle; - - if (usb_info == NULL) - return; - - if (usb_info->cbs && usb_info->cbs->recv_irb_complete) - usb_info->cbs->recv_irb_complete(usb_info->cbarg, rxirb, status); -} - -/** Lower DBUS level (dbus_usb_os.c) requests a free IRB. Pass this on to the higher DBUS level. */ -static struct dbus_irb* -dbus_usb_getirb(void *handle, bool send) -{ - usb_info_t *usb_info = (usb_info_t *) handle; - - if (usb_info == NULL) - return NULL; - - if (usb_info->cbs && usb_info->cbs->getirb) - return usb_info->cbs->getirb(usb_info->cbarg, send); - - return NULL; -} - -/** - * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be - * notified. - */ -static void -dbus_usb_rxerr_indicate(void *handle, bool on) -{ - usb_info_t *usb_info = (usb_info_t *) handle; - - if (usb_info == NULL) - return; - - if (usb_info->cbs && usb_info->cbs->rxerr_indicate) - usb_info->cbs->rxerr_indicate(usb_info->cbarg, on); -} - -/** - * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be - * notified. - */ -static void -dbus_usb_errhandler(void *handle, int err) -{ - usb_info_t *usb_info = (usb_info_t *) handle; - - if (usb_info == NULL) - return; - - if (usb_info->cbs && usb_info->cbs->errhandler) - usb_info->cbs->errhandler(usb_info->cbarg, err); -} - -/** - * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be - * notified. - */ -static void -dbus_usb_ctl_complete(void *handle, int type, int status) -{ - usb_info_t *usb_info = (usb_info_t *) handle; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (usb_info == NULL) { - DBUSERR(("%s: usb_info is NULL\n", __FUNCTION__)); - return; - } - - if (usb_info->cbs && usb_info->cbs->ctl_complete) - usb_info->cbs->ctl_complete(usb_info->cbarg, type, status); -} - -/** - * When the lower DBUS level (dbus_usb_os.c) signals this event, the higher DBUS level has to be - * notified. - */ -static void -dbus_usb_state_change(void *handle, int state) -{ - usb_info_t *usb_info = (usb_info_t *) handle; - - if (usb_info == NULL) - return; - - if (usb_info->cbs && usb_info->cbs->state_change) - usb_info->cbs->state_change(usb_info->cbarg, state); -} - -/** called by higher DBUS level (dbus.c) */ -static int -dbus_usb_iovar_op(void *bus, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - int err = DBUS_OK; - - err = dbus_iovar_process((usb_info_t*)bus, name, params, plen, arg, len, set); - return err; -} - -/** process iovar request from higher DBUS level */ -static int -dbus_iovar_process(usb_info_t* usbinfo, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - const bcm_iovar_t *vi = NULL; - int bcmerror = 0; - int val_size; - uint32 actionid; - - DBUSTRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(name); - ASSERT(len >= 0); - - /* Get MUST have return space */ - ASSERT(set || (arg && len)); - - /* Set does NOT take qualifiers */ - ASSERT(!set || (!params && !plen)); - - /* Look up var locally; if not found pass to host driver */ - if ((vi = bcm_iovar_lookup(dhdusb_iovars, name)) == NULL) { - /* Not Supported */ - bcmerror = BCME_UNSUPPORTED; - DBUSTRACE(("%s: IOVAR %s is not supported\n", name, __FUNCTION__)); - goto exit; - - } - - DBUSTRACE(("%s: %s %s, len %d plen %d\n", __FUNCTION__, - name, (set ? "set" : "get"), len, plen)); - - /* set up 'params' pointer in case this is a set command so that - * the convenience int and bool code can be common to set and get - */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - /* all other types are integer sized */ - val_size = sizeof(int); - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - bcmerror = dbus_usb_doiovar(usbinfo, vi, actionid, - name, params, plen, arg, len, val_size); - -exit: - return bcmerror; -} /* dbus_iovar_process */ - -static int -dbus_usb_doiovar(usb_info_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, - void *params, int plen, void *arg, int len, int val_size) -{ - int bcmerror = 0; - int32 int_val = 0; - int32 int_val2 = 0; - bool bool_val = 0; - - DBUSTRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", - __FUNCTION__, actionid, name, params, plen, arg, len, val_size)); - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) - goto exit; - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - if (plen >= (int)sizeof(int_val) * 2) - bcopy((void*)((uintptr)params + sizeof(int_val)), &int_val2, sizeof(int_val2)); - - bool_val = (int_val != 0) ? TRUE : FALSE; - - switch (actionid) { - - case IOV_SVAL(IOV_MEMBYTES): - case IOV_GVAL(IOV_MEMBYTES): - { - uint32 address; - uint size, dsize; - uint8 *data; - - bool set = (actionid == IOV_SVAL(IOV_MEMBYTES)); - - ASSERT(plen >= 2*sizeof(int)); - - address = (uint32)int_val; - BCM_REFERENCE(address); - bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val)); - size = (uint)int_val; - - /* Do some validation */ - dsize = set ? plen - (2 * sizeof(int)) : len; - if (dsize < size) { - DBUSTRACE(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n", - __FUNCTION__, (set ? "set" : "get"), address, size, dsize)); - bcmerror = BCME_BADARG; - break; - } - DBUSTRACE(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__, - (set ? "write" : "read"), size, address)); - - /* Generate the actual data pointer */ - data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg; - - /* Call to do the transfer */ - bcmerror = dbus_usb_dl_writeimage(BUS_INFO(bus, usb_info_t), data, size); - } - break; - - - case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): - - if (bool_val == TRUE) { - bcmerror = dbus_usb_dlneeded(bus); - dbus_usb_rdl_dwnld_state(BUS_INFO(bus, usb_info_t)); - } else { - usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); - bcmerror = dbus_usb_dlrun(bus); - usbinfo->pub->busstate = DBUS_STATE_DL_DONE; - } - break; - - case IOV_SVAL(IOV_VARS): - bcmerror = dhdusb_downloadvars(BUS_INFO(bus, usb_info_t), arg, len); - break; - - case IOV_GVAL(IOV_DBUS_MSGLEVEL): - int_val = (int32)dbus_msglevel; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DBUS_MSGLEVEL): - dbus_msglevel = int_val; - break; - -#ifdef DBUS_USB_LOOPBACK - case IOV_SVAL(IOV_LOOPBACK_TX): - bcmerror = dbus_usbos_loopback_tx(BUS_INFO(bus, usb_info_t), int_val, - int_val2); - break; -#endif - default: - bcmerror = BCME_UNSUPPORTED; - break; - } - -exit: - return bcmerror; -} /* dbus_usb_doiovar */ - -/** higher DBUS level (dbus.c) wants to set NVRAM variables in dongle */ -static int -dhdusb_downloadvars(usb_info_t *bus, void *arg, int len) -{ - int bcmerror = 0; - uint32 varsize; - uint32 varaddr; - uint32 varsizew; - - if (!len) { - bcmerror = BCME_BUFTOOSHORT; - goto err; - } - - /* RAM size is not set. Set it at dbus_usb_dlneeded */ - if (!bus->rdlram_size) - bcmerror = BCME_ERROR; - - /* Even if there are no vars are to be written, we still need to set the ramsize. */ - varsize = len ? ROUNDUP(len, 4) : 0; - varaddr = (bus->rdlram_size - 4) - varsize; - - /* Write the vars list */ - DBUSTRACE(("WriteVars: @%x varsize=%d\n", varaddr, varsize)); - bcmerror = dbus_write_membytes(bus->usbosl_info, TRUE, (varaddr + bus->rdlram_base_addr), - arg, varsize); - - /* adjust to the user specified RAM */ - DBUSTRACE(("Usable memory size: %d\n", bus->rdlram_size)); - DBUSTRACE(("Vars are at %d, orig varsize is %d\n", varaddr, varsize)); - - varsize = ((bus->rdlram_size - 4) - varaddr); - - /* - * Determine the length token: - * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits. - */ - if (bcmerror) { - varsizew = 0; - } else { - varsizew = varsize / 4; - varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); - varsizew = htol32(varsizew); - } - - DBUSTRACE(("New varsize is %d, length token=0x%08x\n", varsize, varsizew)); - - /* Write the length token to the last word */ - bcmerror = dbus_write_membytes(bus->usbosl_info, TRUE, ((bus->rdlram_size - 4) + - bus->rdlram_base_addr), (uint8*)&varsizew, 4); -err: - return bcmerror; -} /* dbus_usb_doiovar */ - -#if !defined(BCM_REQUEST_FW) -/** - * After downloading firmware into dongle and starting it, we need to know if the firmware is - * indeed up and running. - */ -static int -dbus_usb_resetcfg(usb_info_t *usbinfo) -{ - void *osinfo; - bootrom_id_t id; - uint16 waittime = 0; - - uint32 starttime = 0; - uint32 endtime = 0; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (usbinfo == NULL) - return DBUS_ERR; - - osinfo = usbinfo->usbosl_info; - ASSERT(osinfo); - - /* Give dongle chance to boot */ - dbus_usbos_wait(osinfo, USB_SFLASH_DLIMAGE_SPINWAIT); - waittime = USB_SFLASH_DLIMAGE_SPINWAIT; - while (waittime < USB_DLIMAGE_RETRY_TIMEOUT) { - - starttime = OSL_SYSUPTIME(); - - id.chip = 0xDEAD; /* Get the ID */ - dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t)); - id.chip = ltoh32(id.chip); - - endtime = OSL_SYSUPTIME(); - waittime += (endtime - starttime); - - if (id.chip == POSTBOOT_ID) - break; - } - - if (id.chip == POSTBOOT_ID) { - DBUSERR(("%s: download done. Bootup time = %d ms postboot chip 0x%x/rev 0x%x\n", - __FUNCTION__, waittime, id.chip, id.chiprev)); - - dbus_usbos_dl_cmd(osinfo, DL_RESETCFG, &id, sizeof(bootrom_id_t)); - - dbus_usbos_wait(osinfo, USB_RESETCFG_SPINWAIT); - return DBUS_OK; - } else { - DBUSERR(("%s: Cannot talk to Dongle. Wait time = %d ms. Firmware is not UP \n", - __FUNCTION__, waittime)); - return DBUS_ERR; - } - - return DBUS_OK; -} -#endif - -/** before firmware download, the dongle has to be prepared to receive the fw image */ -static int -dbus_usb_rdl_dwnld_state(usb_info_t *usbinfo) -{ - void *osinfo = usbinfo->usbosl_info; - rdl_state_t state; - int err = DBUS_OK; - - /* 1) Prepare USB boot loader for runtime image */ - dbus_usbos_dl_cmd(osinfo, DL_START, &state, sizeof(rdl_state_t)); - - state.state = ltoh32(state.state); - state.bytes = ltoh32(state.bytes); - - /* 2) Check we are in the Waiting state */ - if (state.state != DL_WAITING) { - DBUSERR(("%s: Failed to DL_START\n", __FUNCTION__)); - err = DBUS_ERR; - goto fail; - } - -fail: - return err; -} - -/** - * Dongle contains bootcode in ROM but firmware is (partially) contained in dongle RAM. Therefore, - * firmware has to be downloaded into dongle RAM. - */ -static int -dbus_usb_dl_writeimage(usb_info_t *usbinfo, uint8 *fw, int fwlen) -{ - osl_t *osh = usbinfo->pub->osh; - void *osinfo = usbinfo->usbosl_info; - unsigned int sendlen, sent, dllen; - char *bulkchunk = NULL, *dlpos; - rdl_state_t state; - int err = DBUS_OK; - bootrom_id_t id; - uint16 wait, wait_time; - uint32 dl_trunk_size = RDL_CHUNK; - - if (BCM4350_CHIP(usbinfo->pub->attrib.devid)) - dl_trunk_size = RDL_CHUNK_MAX; - - while (!bulkchunk) { - bulkchunk = MALLOC(osh, dl_trunk_size); - if (dl_trunk_size == RDL_CHUNK) - break; - if (!bulkchunk) { - dl_trunk_size /= 2; - if (dl_trunk_size < RDL_CHUNK) - dl_trunk_size = RDL_CHUNK; - } - } - - if (bulkchunk == NULL) { - err = DBUS_ERR; - goto fail; - } - - sent = 0; - dlpos = fw; - dllen = fwlen; - - /* Get chip id and rev */ - id.chip = usbinfo->pub->attrib.devid; - id.chiprev = usbinfo->pub->attrib.chiprev; - - DBUSTRACE(("enter %s: fwlen=%d\n", __FUNCTION__, fwlen)); - - dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t)); - - /* 3) Load the image */ - while ((sent < dllen)) { - /* Wait until the usb device reports it received all the bytes we sent */ - - if (sent < dllen) { - if ((dllen-sent) < dl_trunk_size) - sendlen = dllen-sent; - else - sendlen = dl_trunk_size; - - /* simply avoid having to send a ZLP by ensuring we never have an even - * multiple of 64 - */ - if (!(sendlen % 64)) - sendlen -= 4; - - /* send data */ - memcpy(bulkchunk, dlpos, sendlen); - if (!dbus_usbos_dl_send_bulk(osinfo, bulkchunk, sendlen)) { - err = DBUS_ERR; - goto fail; - } - - dlpos += sendlen; - sent += sendlen; - DBUSTRACE(("%s: sendlen %d\n", __FUNCTION__, sendlen)); - } - - wait = 0; - wait_time = USB_SFLASH_DLIMAGE_SPINWAIT; - while (!dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, - sizeof(rdl_state_t))) { - if ((id.chip == 43236) && (id.chiprev == 0)) { - DBUSERR(("%s: 43236a0 SFlash delay, waiting for dongle crc check " - "completion!!!\n", __FUNCTION__)); - dbus_usbos_wait(osinfo, wait_time); - wait += wait_time; - if (wait >= USB_SFLASH_DLIMAGE_LIMIT) { - DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__)); - err = DBUS_ERR; - goto fail; - break; - } - } else { - DBUSERR(("%s: DL_GETSTATE Failed xxxx\n", __FUNCTION__)); - err = DBUS_ERR; - goto fail; - } - } - - state.state = ltoh32(state.state); - state.bytes = ltoh32(state.bytes); - - /* restart if an error is reported */ - if ((state.state == DL_BAD_HDR) || (state.state == DL_BAD_CRC)) { - DBUSERR(("%s: Bad Hdr or Bad CRC\n", __FUNCTION__)); - err = DBUS_ERR; - goto fail; - } - - } -fail: - if (bulkchunk) - MFREE(osh, bulkchunk, dl_trunk_size); - - return err; -} /* dbus_usb_dl_writeimage */ - -/** Higher level DBUS layer (dbus.c) requests this layer to download image into dongle */ -static int -dbus_usb_dlstart(void *bus, uint8 *fw, int len) -{ - usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); - int err; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (usbinfo == NULL) - return DBUS_ERR; - - if (USB_DEV_ISBAD(usbinfo)) - return DBUS_ERR; - - err = dbus_usb_rdl_dwnld_state(usbinfo); - - if (DBUS_OK == err) { - err = dbus_usb_dl_writeimage(usbinfo, fw, len); - if (err == DBUS_OK) - usbinfo->pub->busstate = DBUS_STATE_DL_DONE; - else - usbinfo->pub->busstate = DBUS_STATE_DL_PENDING; - } else - usbinfo->pub->busstate = DBUS_STATE_DL_PENDING; - - return err; -} - -static bool -dbus_usb_update_chipinfo(usb_info_t *usbinfo, uint32 chip) -{ - bool retval = TRUE; - /* based on the CHIP Id, store the ram size which is needed for NVRAM download. */ - switch (chip) { - - case 0x4319: - usbinfo->rdlram_size = RDL_RAM_SIZE_4319; - usbinfo->rdlram_base_addr = RDL_RAM_BASE_4319; - break; - - case 0x4329: - usbinfo->rdlram_size = RDL_RAM_SIZE_4329; - usbinfo->rdlram_base_addr = RDL_RAM_BASE_4329; - break; - - case 43234: - case 43235: - case 43236: - usbinfo->rdlram_size = RDL_RAM_SIZE_43236; - usbinfo->rdlram_base_addr = RDL_RAM_BASE_43236; - break; - - case 0x4328: - usbinfo->rdlram_size = RDL_RAM_SIZE_4328; - usbinfo->rdlram_base_addr = RDL_RAM_BASE_4328; - break; - - case 0x4322: - usbinfo->rdlram_size = RDL_RAM_SIZE_4322; - usbinfo->rdlram_base_addr = RDL_RAM_BASE_4322; - break; - - case 0x4360: - case 0xAA06: - usbinfo->rdlram_size = RDL_RAM_SIZE_4360; - usbinfo->rdlram_base_addr = RDL_RAM_BASE_4360; - break; - - case 43242: - case 43243: - usbinfo->rdlram_size = RDL_RAM_SIZE_43242; - usbinfo->rdlram_base_addr = RDL_RAM_BASE_43242; - break; - - case 43143: - usbinfo->rdlram_size = RDL_RAM_SIZE_43143; - usbinfo->rdlram_base_addr = RDL_RAM_BASE_43143; - break; - - case 0x4350: - case 43556: - case 43558: - case 43569: - usbinfo->rdlram_size = RDL_RAM_SIZE_4350; - usbinfo->rdlram_base_addr = RDL_RAM_BASE_4350; - break; - - case POSTBOOT_ID: - break; - - default: - DBUSERR(("%s: Chip 0x%x Ram size is not known\n", __FUNCTION__, chip)); - retval = FALSE; - break; - - } - - return retval; -} /* dbus_usb_update_chipinfo */ - -/** higher DBUS level (dbus.c) wants to know if firmware download is required. */ -static int -dbus_usb_dlneeded(void *bus) -{ - usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); - void *osinfo; - bootrom_id_t id; - int dl_needed = 1; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (usbinfo == NULL) - return DBUS_ERR; - - osinfo = usbinfo->usbosl_info; - ASSERT(osinfo); - - /* Check if firmware downloaded already by querying runtime ID */ - id.chip = 0xDEAD; - dbus_usbos_dl_cmd(osinfo, DL_GETVER, &id, sizeof(bootrom_id_t)); - - id.chip = ltoh32(id.chip); - id.chiprev = ltoh32(id.chiprev); - - if (FALSE == dbus_usb_update_chipinfo(usbinfo, id.chip)) { - dl_needed = DBUS_ERR; - goto exit; - } - - DBUSERR(("%s: chip 0x%x rev 0x%x\n", __FUNCTION__, id.chip, id.chiprev)); - if (id.chip == POSTBOOT_ID) { - /* This code is needed to support two enumerations on USB1.1 scenario */ - DBUSERR(("%s: Firmware already downloaded\n", __FUNCTION__)); - - dbus_usbos_dl_cmd(osinfo, DL_RESETCFG, &id, sizeof(bootrom_id_t)); - dl_needed = DBUS_OK; - if (usbinfo->pub->busstate == DBUS_STATE_DL_PENDING) - usbinfo->pub->busstate = DBUS_STATE_DL_DONE; - } else { - usbinfo->pub->attrib.devid = id.chip; - usbinfo->pub->attrib.chiprev = id.chiprev; - } - -exit: - return dl_needed; -} - -/** After issuing firmware download, higher DBUS level (dbus.c) wants to start the firmware. */ -static int -dbus_usb_dlrun(void *bus) -{ - usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); - void *osinfo; - rdl_state_t state; - int err = DBUS_OK; - - DBUSTRACE(("%s\n", __FUNCTION__)); - - if (usbinfo == NULL) - return DBUS_ERR; - - if (USB_DEV_ISBAD(usbinfo)) - return DBUS_ERR; - - osinfo = usbinfo->usbosl_info; - ASSERT(osinfo); - - /* Check we are runnable */ - dbus_usbos_dl_cmd(osinfo, DL_GETSTATE, &state, sizeof(rdl_state_t)); - - state.state = ltoh32(state.state); - state.bytes = ltoh32(state.bytes); - - /* Start the image */ - if (state.state == DL_RUNNABLE) { - DBUSTRACE(("%s: Issue DL_GO\n", __FUNCTION__)); - dbus_usbos_dl_cmd(osinfo, DL_GO, &state, sizeof(rdl_state_t)); - - if (usbinfo->pub->attrib.devid == TEST_CHIP) - dbus_usbos_wait(osinfo, USB_DLGO_SPINWAIT); - -// dbus_usb_resetcfg(usbinfo); - /* The Donlge may go for re-enumeration. */ - } else { - DBUSERR(("%s: Dongle not runnable\n", __FUNCTION__)); - err = DBUS_ERR; - } - - return err; -} - -/** - * As preparation for firmware download, higher DBUS level (dbus.c) requests the firmware image - * to be used for the type of dongle detected. Directly called by dbus.c (so not via a callback - * construction) - */ -void -dbus_bus_fw_get(void *bus, uint8 **fw, int *fwlen, int *decomp) -{ - usb_info_t *usbinfo = BUS_INFO(bus, usb_info_t); - unsigned int devid; - unsigned int crev; - - devid = usbinfo->pub->attrib.devid; - crev = usbinfo->pub->attrib.chiprev; - - *fw = NULL; - *fwlen = 0; - - switch (devid) { - case BCM43236_CHIP_ID: - case BCM43235_CHIP_ID: - case BCM43234_CHIP_ID: - case BCM43238_CHIP_ID: { - if (crev == 3 || crev == 2 || crev == 1) { -#ifdef EMBED_IMAGE_43236b - *fw = (uint8 *)dlarray_43236b; - *fwlen = sizeof(dlarray_43236b); - -#endif - } - } break; - case BCM4360_CHIP_ID: - case BCM4352_CHIP_ID: - case BCM43526_CHIP_ID: -#ifdef EMBED_IMAGE_43526a - if (crev <= 2) { - *fw = (uint8 *)dlarray_43526a; - *fwlen = sizeof(dlarray_43526a); - } -#endif -#ifdef EMBED_IMAGE_43526b - if (crev > 2) { - *fw = (uint8 *)dlarray_43526b; - *fwlen = sizeof(dlarray_43526b); - } -#endif - break; - - case BCM43242_CHIP_ID: -#ifdef EMBED_IMAGE_43242a0 - *fw = (uint8 *)dlarray_43242a0; - *fwlen = sizeof(dlarray_43242a0); -#endif - break; - - case BCM43143_CHIP_ID: -#ifdef EMBED_IMAGE_43143a0 - *fw = (uint8 *)dlarray_43143a0; - *fwlen = sizeof(dlarray_43143a0); -#endif -#ifdef EMBED_IMAGE_43143b0 - *fw = (uint8 *)dlarray_43143b0; - *fwlen = sizeof(dlarray_43143b0); -#endif - break; - - case BCM4350_CHIP_ID: - case BCM4354_CHIP_ID: - case BCM43556_CHIP_ID: - case BCM43558_CHIP_ID: - case BCM43566_CHIP_ID: - case BCM43568_CHIP_ID: - case BCM43570_CHIP_ID: - case BCM4358_CHIP_ID: -#ifdef EMBED_IMAGE_4350a0 - if (crev == 0) { - *fw = (uint8 *)dlarray_4350a0; - *fwlen = sizeof(dlarray_4350a0); - } -#endif -#ifdef EMBED_IMAGE_4350b0 - if (crev == 1) { - *fw = (uint8 *)dlarray_4350b0; - *fwlen = sizeof(dlarray_4350b0); - } -#endif -#ifdef EMBED_IMAGE_4350b1 - if (crev == 2) { - *fw = (uint8 *)dlarray_4350b1; - *fwlen = sizeof(dlarray_4350b1); - } -#endif -#ifdef EMBED_IMAGE_43556b1 - if (crev == 2) { - *fw = (uint8 *)dlarray_43556b1; - *fwlen = sizeof(dlarray_43556b1); - } -#endif -#ifdef EMBED_IMAGE_4350c0 - if (crev == 3) { - *fw = (uint8 *)dlarray_4350c0; - *fwlen = sizeof(dlarray_4350c0); - } -#endif /* EMBED_IMAGE_4350c0 */ -#ifdef EMBED_IMAGE_4350c1 - if (crev == 4) { - *fw = (uint8 *)dlarray_4350c1; - *fwlen = sizeof(dlarray_4350c1); - } -#endif /* EMBED_IMAGE_4350c1 */ - break; - case BCM43569_CHIP_ID: -#ifdef EMBED_IMAGE_43569a0 - if (crev == 0) { - *fw = (uint8 *)dlarray_43569a0; - *fwlen = sizeof(dlarray_43569a0); - } -#endif /* EMBED_IMAGE_43569a0 */ - break; - default: -#ifdef EMBED_IMAGE_GENERIC - *fw = (uint8 *)dlarray; - *fwlen = sizeof(dlarray); -#endif - break; - } -} /* dbus_bus_fw_get */
diff --git a/bcmdhd.1.579.77.41.x/dbus_usb_linux.c b/bcmdhd.1.579.77.41.x/dbus_usb_linux.c deleted file mode 100644 index 10927d8..0000000 --- a/bcmdhd.1.579.77.41.x/dbus_usb_linux.c +++ /dev/null
@@ -1,3403 +0,0 @@ -/* - * Dongle BUS interface - * USB Linux Implementation - * - * Copyright (C) 1999-2016, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dbus_usb_linux.c 564663 2015-06-18 02:34:42Z $ - */ - -/** - * @file @brief - * This file contains DBUS code that is USB *and* OS (Linux) specific. DBUS is a Broadcom - * proprietary host specific abstraction layer. - */ - -#include <typedefs.h> -#include <osl.h> - -/** - * DBUS_LINUX_RXDPC is created for router platform performance tuning. A separate thread is created - * to handle USB RX and avoid the call chain getting too long and enhance cache hit rate. - * - * DBUS_LINUX_RXDPC setting is in wlconfig file. - */ - -/* - * If DBUS_LINUX_RXDPC is off, spin_lock_bh() for CTFPOOL in - * linux_osl.c has to be changed to spin_lock_irqsave() because - * PKTGET/PKTFREE are no longer in bottom half. - * - * Right now we have another queue rpcq in wl_linux.c. Maybe we - * can eliminate that one to reduce the overhead. - * - * Enabling 2nd EP and DBUS_LINUX_RXDPC causing traffic from - * both EP's to be queued in the same rx queue. If we want - * RXDPC to work with 2nd EP. The EP for RPC call return - * should bypass the dpc and go directly up. - */ - -/* #define DBUS_LINUX_RXDPC */ - -/* Dbus histogram for ntxq, nrxq, dpc parameter tuning */ -/* #define DBUS_LINUX_HIST */ - -#include <usbrdl.h> -#include <bcmendian.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/usb.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/random.h> -#include <linux/spinlock.h> -#include <linux/list.h> -#include <asm/uaccess.h> -#include <asm/unaligned.h> -#include <dbus.h> -#include <bcmutils.h> -#include <bcmdevs.h> -#include <linux/usb.h> -#include <usbrdl.h> -#include <linux/firmware.h> -#include <dngl_stats.h> -#include <dhd.h> - -#if defined(USBOS_THREAD) || defined(USBOS_TX_THREAD) - -/** - * The usb-thread is designed to provide currency on multiprocessors and SMP linux kernels. On the - * dual cores platform, the WLAN driver, without threads, executed only on CPU0. The driver consumed - * almost of 100% on CPU0, while CPU1 remained idle. The behavior was observed on Broadcom's STB. - * - * The WLAN driver consumed most of CPU0 and not CPU1 because tasklets/queues, software irq, and - * hardware irq are executing from CPU0, only. CPU0 became the system's bottle-neck. TPUT is lower - * and system's responsiveness is slower. - * - * To improve system responsiveness and TPUT usb-thread was implemented. The system's threads could - * be scheduled to run on any core. One core could be processing data in the usb-layer and the other - * core could be processing data in the wl-layer. - * - * For further info see [WlThreadAndUsbThread] Twiki. - */ - -#include <linux/kthread.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <asm/hardirq.h> -#include <linux/list.h> -#include <linux_osl.h> -#endif /* USBOS_THREAD || USBOS_TX_THREAD */ - - - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define KERNEL26 -#endif - -/** - * Starting with the 3.10 kernel release, dynamic PM support for USB is present whenever - * the kernel was built with CONFIG_PM_RUNTIME enabled. The CONFIG_USB_SUSPEND option has - * been eliminated. - */ -#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)) && defined(CONFIG_USB_SUSPEND)) \ - || ((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) && defined(CONFIG_PM_RUNTIME)) -/* For USB power management support, see Linux kernel: Documentation/usb/power-management.txt */ -#define USB_SUSPEND_AVAILABLE -#endif - -/* Define alternate fw/nvram paths used in Android */ -#ifdef OEM_ANDROID -#define CONFIG_ANDROID_BCMDHD_FW_PATH "broadcom/dhd/firmware/fw.bin.trx" -#define CONFIG_ANDROID_BCMDHD_NVRAM_PATH "broadcom/dhd/nvrams/nvm.txt" -#endif /* OEM_ANDROID */ - -static inline int usb_submit_urb_linux(struct urb *urb) -{ - -#ifdef BCM_MAX_URB_LEN - if (urb && (urb->transfer_buffer_length > BCM_MAX_URB_LEN)) { - DBUSERR(("URB transfer length=%d exceeded %d ra=%p\n", urb->transfer_buffer_length, - BCM_MAX_URB_LEN, __builtin_return_address(0))); - return DBUS_ERR; - } -#endif - -#ifdef KERNEL26 - return usb_submit_urb(urb, GFP_ATOMIC); -#else - return usb_submit_urb(urb); -#endif - -} - -#define USB_SUBMIT_URB(urb) usb_submit_urb_linux(urb) - -#ifdef KERNEL26 - -#define USB_ALLOC_URB() usb_alloc_urb(0, GFP_ATOMIC) -#define USB_UNLINK_URB(urb) (usb_kill_urb(urb)) -#define USB_FREE_URB(urb) (usb_free_urb(urb)) -#define USB_REGISTER() usb_register(&dbus_usbdev) -#define USB_DEREGISTER() usb_deregister(&dbus_usbdev) - -#ifdef USB_SUSPEND_AVAILABLE - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) -#define USB_AUTOPM_SET_INTERFACE(intf) usb_autopm_set_interface(intf) -#else -#define USB_ENABLE_AUTOSUSPEND(udev) usb_enable_autosuspend(udev) -#define USB_DISABLE_AUTOSUSPEND(udev) usb_disable_autosuspend(udev) -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */ - -#define USB_AUTOPM_GET_INTERFACE(intf) usb_autopm_get_interface(intf) -#define USB_AUTOPM_PUT_INTERFACE(intf) usb_autopm_put_interface(intf) -#define USB_AUTOPM_GET_INTERFACE_ASYNC(intf) usb_autopm_get_interface_async(intf) -#define USB_AUTOPM_PUT_INTERFACE_ASYNC(intf) usb_autopm_put_interface_async(intf) -#define USB_MARK_LAST_BUSY(dev) usb_mark_last_busy(dev) - -#else /* USB_SUSPEND_AVAILABLE */ - -#define USB_AUTOPM_GET_INTERFACE(intf) do {} while (0) -#define USB_AUTOPM_PUT_INTERFACE(intf) do {} while (0) -#define USB_AUTOPM_GET_INTERFACE_ASYNC(intf) do {} while (0) -#define USB_AUTOPM_PUT_INTERFACE_ASYNC(intf) do {} while (0) -#define USB_MARK_LAST_BUSY(dev) do {} while (0) -#endif /* USB_SUSPEND_AVAILABLE */ - -#define USB_CONTROL_MSG(dev, pipe, request, requesttype, value, index, data, size, timeout) \ - usb_control_msg((dev), (pipe), (request), (requesttype), (value), (index), \ - (data), (size), (timeout)) -#define USB_BULK_MSG(dev, pipe, data, len, actual_length, timeout) \ - usb_bulk_msg((dev), (pipe), (data), (len), (actual_length), (timeout)) -#define USB_BUFFER_ALLOC(dev, size, mem, dma) usb_buffer_alloc(dev, size, mem, dma) -#define USB_BUFFER_FREE(dev, size, data, dma) usb_buffer_free(dev, size, data, dma) - -#ifdef WL_URB_ZPKT -#define URB_QUEUE_BULK URB_ZERO_PACKET -#else -#define URB_QUEUE_BULK 0 -#endif /* WL_URB_ZPKT */ - -#define CALLBACK_ARGS struct urb *urb, struct pt_regs *regs -#define CALLBACK_ARGS_DATA urb, regs -#define CONFIGDESC(usb) (&((usb)->actconfig)->desc) -#define IFPTR(usb, idx) ((usb)->actconfig->interface[idx]) -#define IFALTS(usb, idx) (IFPTR((usb), (idx))->altsetting[0]) -#define IFDESC(usb, idx) IFALTS((usb), (idx)).desc -#define IFEPDESC(usb, idx, ep) (IFALTS((usb), (idx)).endpoint[ep]).desc - -#else /* KERNEL26 */ - -#define USB_ALLOC_URB() usb_alloc_urb(0) -#define USB_UNLINK_URB(urb) usb_unlink_urb(urb) -#define USB_FREE_URB(urb) (usb_free_urb(urb)) -#define USB_REGISTER() usb_register(&dbus_usbdev) -#define USB_DEREGISTER() usb_deregister(&dbus_usbdev) -#define USB_AUTOPM_GET_INTERFACE(intf) do {} while (0) -#define USB_AUTOPM_GET_INTERFACE_ASYNC(intf) do {} while (0) -#define USB_AUTOPM_PUT_INTERFACE_ASYNC(intf) do {} while (0) -#define USB_MARK_LAST_BUSY(dev) do {} while (0) - -#define USB_CONTROL_MSG(dev, pipe, request, requesttype, value, index, data, size, timeout) \ - usb_control_msg((dev), (pipe), (request), (requesttype), (value), (index), \ - (data), (size), (timeout)) -#define USB_BUFFER_ALLOC(dev, size, mem, dma) kmalloc(size, mem) -#define USB_BUFFER_FREE(dev, size, data, dma) kfree(data) - -#ifdef WL_URB_ZPKT -#define URB_QUEUE_BULK USB_QUEUE_BULK|URB_ZERO_PACKET -#else -#define URB_QUEUE_BULK 0 -#endif /* WL_URB_ZPKT */ - -#define CALLBACK_ARGS struct urb *urb -#define CALLBACK_ARGS_DATA urb -#define CONFIGDESC(usb) ((usb)->actconfig) -#define IFPTR(usb, idx) (&(usb)->actconfig->interface[idx]) -#define IFALTS(usb, idx) ((usb)->actconfig->interface[idx].altsetting[0]) -#define IFDESC(usb, idx) IFALTS((usb), (idx)) -#define IFEPDESC(usb, idx, ep) (IFALTS((usb), (idx)).endpoint[ep]) - - -#endif /* KERNEL26 */ - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) -#define USB_SPEED_SUPER 5 -#endif /* #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) */ - -#define CONTROL_IF 0 -#define BULK_IF 0 - -#ifdef BCMUSBDEV_COMPOSITE -#define USB_COMPIF_MAX 4 - -#define USB_CLASS_WIRELESS 0xe0 -#define USB_CLASS_MISC 0xef -#define USB_SUBCLASS_COMMON 0x02 -#define USB_PROTO_IAD 0x01 -#define USB_PROTO_VENDOR 0xff - -#define USB_QUIRK_NO_SET_INTF 0x04 /* device does not support set_interface */ -#endif /* BCMUSBDEV_COMPOSITE */ - -#define USB_SYNC_WAIT_TIMEOUT 300 /* ms */ - -/* Private data kept in skb */ -#define SKB_PRIV(skb, idx) (&((void **)skb->cb)[idx]) -#define SKB_PRIV_URB(skb) (*(struct urb **)SKB_PRIV(skb, 0)) - -#ifndef DBUS_USB_RXQUEUE_BATCH_ADD -/* items to add each time within limit */ -#define DBUS_USB_RXQUEUE_BATCH_ADD 8 -#endif - -#ifndef DBUS_USB_RXQUEUE_LOWER_WATERMARK -/* add a new batch req to rx queue when waiting item count reduce to this number */ -#define DBUS_USB_RXQUEUE_LOWER_WATERMARK 4 -#endif - -enum usbos_suspend_state { - USBOS_SUSPEND_STATE_DEVICE_ACTIVE = 0, /* Device is busy, won't allow suspend */ - USBOS_SUSPEND_STATE_SUSPEND_PENDING, /* Device is idle, can be suspended */ - /* Wating PM to suspend */ - USBOS_SUSPEND_STATE_SUSPENDED /* Device suspended */ -}; - -enum usbos_request_state { - USBOS_REQUEST_STATE_UNSCHEDULED = 0, /* USB TX request not scheduled */ - USBOS_REQUEST_STATE_SCHEDULED, /* USB TX request given to TX thread */ - USBOS_REQUEST_STATE_SUBMITTED /* USB TX request submitted */ -}; - -typedef struct { - uint32 notification; - uint32 reserved; -} intr_t; - -typedef struct { - dbus_pub_t *pub; - - void *cbarg; - dbus_intf_callbacks_t *cbs; - - /* Imported */ - struct usb_device *usb; /* USB device pointer from OS */ - struct urb *intr_urb; /* URB for interrupt endpoint */ - struct list_head req_rxfreeq; - struct list_head req_txfreeq; - struct list_head req_rxpostedq; /* Posted down to USB driver for RX */ - struct list_head req_txpostedq; /* Posted down to USB driver for TX */ - spinlock_t rxfree_lock; /* Lock for rx free list */ - spinlock_t txfree_lock; /* Lock for tx free list */ - spinlock_t rxposted_lock; /* Lock for rx posted list */ - spinlock_t txposted_lock; /* Lock for tx posted list */ - uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2; /* Pipe numbers for USB I/O */ - uint rxbuf_len; - - struct list_head req_rxpendingq; /* RXDPC: Pending for dpc to send up */ - spinlock_t rxpending_lock; /* RXDPC: Lock for rx pending list */ - long dpc_pid; - struct semaphore dpc_sem; - struct completion dpc_exited; - int rxpending; - - struct urb *ctl_urb; - int ctl_in_pipe, ctl_out_pipe; - struct usb_ctrlrequest ctl_write; - struct usb_ctrlrequest ctl_read; - struct semaphore ctl_lock; /* Lock for CTRL transfers via tx_thread */ -#ifdef USBOS_TX_THREAD - enum usbos_request_state ctl_state; -#endif /* USBOS_TX_THREAD */ - - spinlock_t rxlock; /* Lock for rxq management */ - spinlock_t txlock; /* Lock for txq management */ - - int intr_size; /* Size of interrupt message */ - int interval; /* Interrupt polling interval */ - intr_t intr; /* Data buffer for interrupt endpoint */ - - int maxps; - atomic_t txposted; - atomic_t rxposted; - atomic_t txallocated; - atomic_t rxallocated; - bool rxctl_deferrespok; /* Get a response for setup from dongle */ - - wait_queue_head_t wait; - bool waitdone; - int sync_urb_status; - - struct urb *blk_urb; /* Used for downloading embedded image */ - -#ifdef USBOS_THREAD - spinlock_t ctrl_lock; - spinlock_t usbos_list_lock; - struct list_head usbos_list; - struct list_head usbos_free_list; - atomic_t usbos_list_cnt; - wait_queue_head_t usbos_queue_head; - struct task_struct *usbos_kt; -#endif /* USBOS_THREAD */ - -#ifdef USBOS_TX_THREAD - spinlock_t usbos_tx_list_lock; - struct list_head usbos_tx_list; - wait_queue_head_t usbos_tx_queue_head; - struct task_struct *usbos_tx_kt; -#endif /* USBOS_TX_THREAD */ - - struct dma_pool *qtd_pool; /* QTD pool for USB optimization only */ - int tx_ep, rx_ep, rx2_ep; /* EPs for USB optimization */ - struct usb_device *usb_device; /* USB device for optimization */ -} usbos_info_t; - -typedef struct urb_req { - void *pkt; - int buf_len; - struct urb *urb; - void *arg; - usbos_info_t *usbinfo; - struct list_head urb_list; -} urb_req_t; - -#ifdef USBOS_THREAD -typedef struct usbos_list_entry { - struct list_head list; /* must be first */ - void *urb_context; - int urb_length; - int urb_status; -} usbos_list_entry_t; - -static void* dbus_usbos_thread_init(usbos_info_t *usbos_info); -static void dbus_usbos_thread_deinit(usbos_info_t *usbos_info); -static void dbus_usbos_dispatch_schedule(CALLBACK_ARGS); -static int dbus_usbos_thread_func(void *data); -#endif /* USBOS_THREAD */ - -#ifdef USBOS_TX_THREAD -void* dbus_usbos_tx_thread_init(usbos_info_t *usbos_info); -void dbus_usbos_tx_thread_deinit(usbos_info_t *usbos_info); -int dbus_usbos_tx_thread_func(void *data); -#endif /* USBOS_TX_THREAD */ - -/* Shared Function prototypes */ -bool dbus_usbos_dl_cmd(usbos_info_t *usbinfo, uint8 cmd, void *buffer, int buflen); -int dbus_usbos_wait(usbos_info_t *usbinfo, uint16 ms); -bool dbus_usbos_dl_send_bulk(usbos_info_t *usbinfo, void *buffer, int len); -int dbus_write_membytes(usbos_info_t *usbinfo, bool set, uint32 address, uint8 *data, uint size); - -/* Local function prototypes */ -static void dbus_usbos_send_complete(CALLBACK_ARGS); -static void dbus_usbos_recv_complete(CALLBACK_ARGS); -static int dbus_usbos_errhandler(void *bus, int err); -static int dbus_usbos_state_change(void *bus, int state); -static void dbusos_stop(usbos_info_t *usbos_info); - -#ifdef KERNEL26 -static int dbus_usbos_probe(struct usb_interface *intf, const struct usb_device_id *id); -static void dbus_usbos_disconnect(struct usb_interface *intf); -#if defined(USB_SUSPEND_AVAILABLE) -static int dbus_usbos_resume(struct usb_interface *intf); -static int dbus_usbos_suspend(struct usb_interface *intf, pm_message_t message); -/* at the moment, used for full dongle host driver only */ -static int dbus_usbos_reset_resume(struct usb_interface *intf); -#endif /* USB_SUSPEND_AVAILABLE */ -#else /* KERNEL26 */ -static void *dbus_usbos_probe(struct usb_device *usb, unsigned int ifnum, - const struct usb_device_id *id); -static void dbus_usbos_disconnect(struct usb_device *usb, void *ptr); -#endif /* KERNEL26 */ - - -/** - * have to disable missing-field-initializers warning as last element {} triggers it - * and different versions of kernel have different number of members so it is impossible - * to specify the initializer. BTW issuing the warning here is bug og GCC as universal - * zero {0} specified in C99 standard as correct way of initialization of struct to all zeros - */ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ - 4 && __GNUC_MINOR__ >= 6)) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#endif - -static struct usb_device_id devid_table[] = { - { USB_DEVICE(BCM_DNGL_VID, 0x0000) }, /* Configurable via register() */ -#if defined(BCM_REQUEST_FW) - { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4328) }, - { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4322) }, - { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4319) }, - { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43236) }, - { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43143) }, - { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43242) }, - { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4360) }, - { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_4350) }, - { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BL_PID_43569) }, -#endif -#ifdef EXTENDED_VID_PID - EXTENDED_VID_PID, -#endif /* EXTENDED_VID_PID */ - { USB_DEVICE(BCM_DNGL_VID, BCM_DNGL_BDC_PID) }, /* Default BDC */ - { } -}; - -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == \ - 4 && __GNUC_MINOR__ >= 6)) -#pragma GCC diagnostic pop -#endif - -MODULE_DEVICE_TABLE(usb, devid_table); - -/** functions called by the Linux kernel USB subsystem */ -static struct usb_driver dbus_usbdev = { - name: "dbus_usbdev", - probe: dbus_usbos_probe, - disconnect: dbus_usbos_disconnect, - id_table: devid_table, -#if defined(USB_SUSPEND_AVAILABLE) - suspend: dbus_usbos_suspend, - resume: dbus_usbos_resume, - reset_resume: dbus_usbos_reset_resume, - /* Linux USB core will allow autosuspend for devices bound to this driver */ - supports_autosuspend: 1 -#endif /* USB_SUSPEND_AVAILABLE */ -}; - -/** - * This stores USB info during Linux probe callback since attach() is not called yet at this point - */ -typedef struct { - void *usbos_info; - struct usb_device *usb; /* USB device pointer from OS */ - uint rx_pipe; /* Pipe numbers for USB I/O */ - uint tx_pipe; /* Pipe numbers for USB I/O */ - uint intr_pipe; /* Pipe numbers for USB I/O */ - uint rx_pipe2; /* Pipe numbers for USB I/O */ - int intr_size; /* Size of interrupt message */ - int interval; /* Interrupt polling interval */ - bool dldone; - int vid; - int pid; - bool dereged; - bool disc_cb_done; - DEVICE_SPEED device_speed; - enum usbos_suspend_state suspend_state; - struct usb_interface *intf; -} probe_info_t; - -/* - * USB Linux dbus_intf_t - */ -static void *dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs); -static void dbus_usbos_intf_detach(dbus_pub_t *pub, void *info); -static int dbus_usbos_intf_send_irb(void *bus, dbus_irb_tx_t *txirb); -static int dbus_usbos_intf_recv_irb(void *bus, dbus_irb_rx_t *rxirb); -static int dbus_usbos_intf_recv_irb_from_ep(void *bus, dbus_irb_rx_t *rxirb, uint32 ep_idx); -static int dbus_usbos_intf_cancel_irb(void *bus, dbus_irb_tx_t *txirb); -static int dbus_usbos_intf_send_ctl(void *bus, uint8 *buf, int len); -static int dbus_usbos_intf_recv_ctl(void *bus, uint8 *buf, int len); -static int dbus_usbos_intf_get_attrib(void *bus, dbus_attrib_t *attrib); -static int dbus_usbos_intf_up(void *bus); -static int dbus_usbos_intf_down(void *bus); -static int dbus_usbos_intf_stop(void *bus); -static int dbus_usbos_readreg(void *bus, uint32 regaddr, int datalen, uint32 *value); -extern int dbus_usbos_loopback_tx(void *usbos_info_ptr, int cnt, int size); -int dbus_usbos_writereg(void *bus, uint32 regaddr, int datalen, uint32 data); -static int dbus_usbos_intf_set_config(void *bus, dbus_config_t *config); -static bool dbus_usbos_intf_recv_needed(void *bus); -static void *dbus_usbos_intf_exec_rxlock(void *bus, exec_cb_t cb, struct exec_parms *args); -static void *dbus_usbos_intf_exec_txlock(void *bus, exec_cb_t cb, struct exec_parms *args); -#ifdef BCMUSBDEV_COMPOSITE -static int dbus_usbos_intf_wlan(struct usb_device *usb); -#endif /* BCMUSBDEV_COMPOSITE */ - -/** functions called by dbus_usb.c */ -static dbus_intf_t dbus_usbos_intf = { - .attach = dbus_usbos_intf_attach, - .detach = dbus_usbos_intf_detach, - .up = dbus_usbos_intf_up, - .down = dbus_usbos_intf_down, - .send_irb = dbus_usbos_intf_send_irb, - .recv_irb = dbus_usbos_intf_recv_irb, - .cancel_irb = dbus_usbos_intf_cancel_irb, - .send_ctl = dbus_usbos_intf_send_ctl, - .recv_ctl = dbus_usbos_intf_recv_ctl, - .get_stats = NULL, - .get_attrib = dbus_usbos_intf_get_attrib, - .remove = NULL, - .resume = NULL, - .suspend = NULL, - .stop = dbus_usbos_intf_stop, - .reset = NULL, - .pktget = NULL, - .pktfree = NULL, - .iovar_op = NULL, - .dump = NULL, - .set_config = dbus_usbos_intf_set_config, - .get_config = NULL, - .device_exists = NULL, - .dlneeded = NULL, - .dlstart = NULL, - .dlrun = NULL, - .recv_needed = dbus_usbos_intf_recv_needed, - .exec_rxlock = dbus_usbos_intf_exec_rxlock, - .exec_txlock = dbus_usbos_intf_exec_txlock, - - .tx_timer_init = NULL, - .tx_timer_start = NULL, - .tx_timer_stop = NULL, - - .sched_dpc = NULL, - .lock = NULL, - .unlock = NULL, - .sched_probe_cb = NULL, - - .shutdown = NULL, - - .recv_stop = NULL, - .recv_resume = NULL, - - .recv_irb_from_ep = dbus_usbos_intf_recv_irb_from_ep, - .readreg = dbus_usbos_readreg -}; - -static probe_info_t g_probe_info; -static probe_cb_t probe_cb = NULL; -static disconnect_cb_t disconnect_cb = NULL; -static void *probe_arg = NULL; -static void *disc_arg = NULL; - - - -static volatile int loopback_rx_cnt, loopback_tx_cnt; -int loopback_size; -bool is_loopback_pkt(void *buf); -int matches_loopback_pkt(void *buf); - -/** - * multiple code paths in this file dequeue a URB request, this function makes sure that it happens - * in a concurrency save manner. Don't call this from a sleepable process context. - */ -static urb_req_t * BCMFASTPATH -dbus_usbos_qdeq(struct list_head *urbreq_q, spinlock_t *lock) -{ - unsigned long flags; - urb_req_t *req; - - ASSERT(urbreq_q != NULL); - - spin_lock_irqsave(lock, flags); - - if (list_empty(urbreq_q)) { - req = NULL; - } else { - ASSERT(urbreq_q->next != NULL); - ASSERT(urbreq_q->next != urbreq_q); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - req = list_entry(urbreq_q->next, urb_req_t, urb_list); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - list_del_init(&req->urb_list); - } - - spin_unlock_irqrestore(lock, flags); - - return req; -} - -static void BCMFASTPATH -dbus_usbos_qenq(struct list_head *urbreq_q, urb_req_t *req, spinlock_t *lock) -{ - unsigned long flags; - - spin_lock_irqsave(lock, flags); - - list_add_tail(&req->urb_list, urbreq_q); - - spin_unlock_irqrestore(lock, flags); -} - -/** - * multiple code paths in this file remove a URB request from a list, this function makes sure that - * it happens in a concurrency save manner. Don't call this from a sleepable process context. - * Is quite similar to dbus_usbos_qdeq(), I wonder why this function is needed. - */ -static void -dbus_usbos_req_del(urb_req_t *req, spinlock_t *lock) -{ - unsigned long flags; - - spin_lock_irqsave(lock, flags); - - list_del_init(&req->urb_list); - - spin_unlock_irqrestore(lock, flags); -} - - -/** - * Driver requires a pool of URBs to operate. This function is called during - * initialization (attach phase), allocates a number of URBs, and puts them - * on the free (req_rxfreeq and req_txfreeq) queue - */ -static int -dbus_usbos_urbreqs_alloc(usbos_info_t *usbos_info, uint32 count, bool is_rx) -{ - int i; - int allocated = 0; - int err = DBUS_OK; - - for (i = 0; i < count; i++) { - urb_req_t *req; - - req = MALLOC(usbos_info->pub->osh, sizeof(urb_req_t)); - if (req == NULL) { - DBUSERR(("%s: MALLOC req failed\n", __FUNCTION__)); - err = DBUS_ERR_NOMEM; - goto fail; - } - bzero(req, sizeof(urb_req_t)); - - req->urb = USB_ALLOC_URB(); - if (req->urb == NULL) { - DBUSERR(("%s: USB_ALLOC_URB req->urb failed\n", __FUNCTION__)); - err = DBUS_ERR_NOMEM; - goto fail; - } - - INIT_LIST_HEAD(&req->urb_list); - - if (is_rx) { -#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) - /* don't allocate now. Do it on demand */ - req->pkt = NULL; -#else - /* pre-allocate buffers never to be released */ - req->pkt = MALLOC(usbos_info->pub->osh, usbos_info->rxbuf_len); - if (req->pkt == NULL) { - DBUSERR(("%s: MALLOC req->pkt failed\n", __FUNCTION__)); - err = DBUS_ERR_NOMEM; - goto fail; - } -#endif - req->buf_len = usbos_info->rxbuf_len; - dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock); - } else { - req->buf_len = 0; - dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock); - } - allocated++; - continue; - -fail: - if (req) { - if (is_rx && req->pkt) { -#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) - /* req->pkt is NULL in "NOCOPY" mode */ -#else - MFREE(usbos_info->pub->osh, req->pkt, req->buf_len); -#endif - } - if (req->urb) { - USB_FREE_URB(req->urb); - } - MFREE(usbos_info->pub->osh, req, sizeof(urb_req_t)); - } - break; - } - - atomic_add(allocated, is_rx ? &usbos_info->rxallocated : &usbos_info->txallocated); - - if (is_rx) { - DBUSTRACE(("%s: add %d (total %d) rx buf, each has %d bytes\n", __FUNCTION__, - allocated, atomic_read(&usbos_info->rxallocated), usbos_info->rxbuf_len)); - } else { - DBUSTRACE(("%s: add %d (total %d) tx req\n", __FUNCTION__, - allocated, atomic_read(&usbos_info->txallocated))); - } - - return err; -} /* dbus_usbos_urbreqs_alloc */ - -/** Typically called during detach or when attach failed. Don't call until all URBs unlinked */ -static int -dbus_usbos_urbreqs_free(usbos_info_t *usbos_info, bool is_rx) -{ - int rtn = 0; - urb_req_t *req; - struct list_head *req_q; - spinlock_t *lock; - - if (is_rx) { - req_q = &usbos_info->req_rxfreeq; - lock = &usbos_info->rxfree_lock; - } else { - req_q = &usbos_info->req_txfreeq; - lock = &usbos_info->txfree_lock; - } - while ((req = dbus_usbos_qdeq(req_q, lock)) != NULL) { - - if (is_rx) { - if (req->pkt) { - /* We do MFREE instead of PKTFREE because the pkt has been - * converted to native already - */ - MFREE(usbos_info->pub->osh, req->pkt, req->buf_len); - req->pkt = NULL; - req->buf_len = 0; - } - } else { - /* sending req should not be assigned pkt buffer */ - ASSERT(req->pkt == NULL); - } - - if (req->urb) { - USB_FREE_URB(req->urb); - req->urb = NULL; - } - MFREE(usbos_info->pub->osh, req, sizeof(urb_req_t)); - - rtn++; - } - return rtn; -} /* dbus_usbos_urbreqs_free */ - -/** - * called by Linux kernel on URB completion. Upper DBUS layer (dbus_usb.c) has to be notified of - * send completion. - */ -void -dbus_usbos_send_complete(CALLBACK_ARGS) -{ - urb_req_t *req = urb->context; - dbus_irb_tx_t *txirb = req->arg; - usbos_info_t *usbos_info = req->usbinfo; - unsigned long flags; - int status = DBUS_OK; - int txposted; - - USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); - - spin_lock_irqsave(&usbos_info->txlock, flags); - - dbus_usbos_req_del(req, &usbos_info->txposted_lock); - txposted = atomic_dec_return(&usbos_info->txposted); - if (unlikely (txposted < 0)) { - DBUSERR(("%s ERROR: txposted is negative (%d)!!\n", __FUNCTION__, txposted)); - } - spin_unlock_irqrestore(&usbos_info->txlock, flags); - - if (unlikely (urb->status)) { - status = DBUS_ERR_TXFAIL; - DBUSTRACE(("txfail status %d\n", urb->status)); - } - -#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) - /* sending req should not be assigned pkt buffer */ - ASSERT(req->pkt == NULL); -#endif - /* txirb should always be set, except for ZLP. ZLP is reusing this callback function. */ - if (txirb != NULL) { - if (txirb->send_buf != NULL) { - MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len); - txirb->send_buf = NULL; - req->buf_len = 0; - } - if (likely (usbos_info->cbarg && usbos_info->cbs)) { - if (likely (usbos_info->cbs->send_irb_complete != NULL)) - usbos_info->cbs->send_irb_complete(usbos_info->cbarg, txirb, status); - } - } - - dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock); -} /* dbus_usbos_send_complete */ - -/** - * In order to receive USB traffic from the dongle, we need to supply the Linux kernel with a free - * URB that is going to contain received data. - */ -static int BCMFASTPATH -dbus_usbos_recv_urb_submit(usbos_info_t *usbos_info, dbus_irb_rx_t *rxirb, uint32 ep_idx) -{ - urb_req_t *req; - int ret = DBUS_OK; - unsigned long flags; - void *p; - uint rx_pipe; - int rxposted; - - BCM_REFERENCE(rxposted); - - if (!(req = dbus_usbos_qdeq(&usbos_info->req_rxfreeq, &usbos_info->rxfree_lock))) { - DBUSTRACE(("%s No free URB!\n", __FUNCTION__)); - return DBUS_ERR_RXDROP; - } - - spin_lock_irqsave(&usbos_info->rxlock, flags); - -#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) - req->pkt = rxirb->pkt = PKTGET(usbos_info->pub->osh, req->buf_len, FALSE); - if (!rxirb->pkt) { - DBUSERR(("%s: PKTGET failed\n", __FUNCTION__)); - dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock); - ret = DBUS_ERR_RXDROP; - goto fail; - } - /* consider the packet "native" so we don't count it as MALLOCED in the osl */ - PKTTONATIVE(usbos_info->pub->osh, req->pkt); - rxirb->buf = NULL; - p = PKTDATA(usbos_info->pub->osh, req->pkt); -#else - if (req->buf_len != usbos_info->rxbuf_len) { - ASSERT(req->pkt); - MFREE(usbos_info->pub->osh, req->pkt, req->buf_len); - DBUSTRACE(("%s: replace rx buff: old len %d, new len %d\n", __FUNCTION__, - req->buf_len, usbos_info->rxbuf_len)); - req->buf_len = 0; - req->pkt = MALLOC(usbos_info->pub->osh, usbos_info->rxbuf_len); - if (req->pkt == NULL) { - DBUSERR(("%s: MALLOC req->pkt failed\n", __FUNCTION__)); - ret = DBUS_ERR_NOMEM; - goto fail; - } - req->buf_len = usbos_info->rxbuf_len; - } - rxirb->buf = req->pkt; - p = rxirb->buf; -#endif /* defined(BCM_RPC_NOCOPY) */ - rxirb->buf_len = req->buf_len; - req->usbinfo = usbos_info; - req->arg = rxirb; - if (ep_idx == 0) { - rx_pipe = usbos_info->rx_pipe; - } else { - rx_pipe = usbos_info->rx_pipe2; - ASSERT(usbos_info->rx_pipe2); - } - /* Prepare the URB */ - usb_fill_bulk_urb(req->urb, usbos_info->usb, rx_pipe, - p, - rxirb->buf_len, - (usb_complete_t)dbus_usbos_recv_complete, req); - req->urb->transfer_flags |= URB_QUEUE_BULK; - - if ((ret = USB_SUBMIT_URB(req->urb))) { - DBUSERR(("%s USB_SUBMIT_URB failed. status %d\n", __FUNCTION__, ret)); - dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock); - ret = DBUS_ERR_RXFAIL; - goto fail; - } - rxposted = atomic_inc_return(&usbos_info->rxposted); - - dbus_usbos_qenq(&usbos_info->req_rxpostedq, req, &usbos_info->rxposted_lock); -fail: - spin_unlock_irqrestore(&usbos_info->rxlock, flags); - return ret; -} /* dbus_usbos_recv_urb_submit */ - - -/** - * Called by worked thread when a 'receive URB' completed or Linux kernel when it returns a URB to - * this driver. - */ -static void BCMFASTPATH -dbus_usbos_recv_complete_handle(urb_req_t *req, int len, int status) -{ - dbus_irb_rx_t *rxirb = req->arg; - usbos_info_t *usbos_info = req->usbinfo; - unsigned long flags; - int rxallocated, rxposted; - int dbus_status = DBUS_OK; - bool killed = (g_probe_info.suspend_state == USBOS_SUSPEND_STATE_SUSPEND_PENDING) ? 1 : 0; - - spin_lock_irqsave(&usbos_info->rxlock, flags); - dbus_usbos_req_del(req, &usbos_info->rxposted_lock); - rxposted = atomic_dec_return(&usbos_info->rxposted); - rxallocated = atomic_read(&usbos_info->rxallocated); - spin_unlock_irqrestore(&usbos_info->rxlock, flags); - - if ((rxallocated < usbos_info->pub->nrxq) && (!status) && - (rxposted == DBUS_USB_RXQUEUE_LOWER_WATERMARK)) { - DBUSTRACE(("%s: need more rx buf: rxallocated %d rxposted %d!\n", - __FUNCTION__, rxallocated, rxposted)); - dbus_usbos_urbreqs_alloc(usbos_info, - MIN(DBUS_USB_RXQUEUE_BATCH_ADD, - usbos_info->pub->nrxq - rxallocated), TRUE); - } - - /* Handle errors */ - if (status) { - /* - * Linux 2.4 disconnect: -ENOENT or -EILSEQ for CRC error; rmmod: -ENOENT - * Linux 2.6 disconnect: -EPROTO, rmmod: -ESHUTDOWN - */ - if ((status == -ENOENT && (!killed))|| status == -ESHUTDOWN) { - /* NOTE: unlink() can not be called from URB callback(). - * Do not call dbusos_stop() here. - */ - DBUSTRACE(("%s rx error %d\n", __FUNCTION__, status)); - dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN); - } else if (status == -EPROTO) { - DBUSTRACE(("%s rx error %d\n", __FUNCTION__, status)); - } else if (killed && (status == -EHOSTUNREACH || status == -ENOENT)) { - /* Device is suspended */ - } else { - DBUSTRACE(("%s rx error %d\n", __FUNCTION__, status)); - dbus_usbos_errhandler(usbos_info, DBUS_ERR_RXFAIL); - } - - /* On error, don't submit more URBs yet */ - rxirb->buf = NULL; - rxirb->actual_len = 0; - dbus_status = DBUS_ERR_RXFAIL; - goto fail; - } - - /* Make the skb represent the received urb */ - rxirb->actual_len = len; - - if (rxirb->actual_len < sizeof(uint32)) { - DBUSTRACE(("small pkt len %d, process as ZLP\n", rxirb->actual_len)); - dbus_status = DBUS_ERR_RXZLP; - } - -fail: -#if defined(BCM_RPC_NOCOPY) || defined(BCM_RPC_RXNOCOPY) - /* detach the packet from the queue */ - req->pkt = NULL; -#endif /* BCM_RPC_NOCOPY || BCM_RPC_RXNOCOPY */ - - if (usbos_info->cbarg && usbos_info->cbs) { - if (usbos_info->cbs->recv_irb_complete) { - usbos_info->cbs->recv_irb_complete(usbos_info->cbarg, rxirb, dbus_status); - } - } - - dbus_usbos_qenq(&usbos_info->req_rxfreeq, req, &usbos_info->rxfree_lock); - - /* Mark the interface as busy to reset USB autosuspend timer */ - USB_MARK_LAST_BUSY(usbos_info->usb); -} /* dbus_usbos_recv_complete_handle */ - -/** called by Linux kernel when it returns a URB to this driver */ -static void -dbus_usbos_recv_complete(CALLBACK_ARGS) -{ -#ifdef USBOS_THREAD - dbus_usbos_dispatch_schedule(CALLBACK_ARGS_DATA); -#else /* !USBOS_THREAD */ - dbus_usbos_recv_complete_handle(urb->context, urb->actual_length, urb->status); -#endif /* USBOS_THREAD */ -} - - -/** - * If Linux notifies our driver that a control read or write URB has completed, we should notify - * the DBUS layer above us (dbus_usb.c in this case). - */ -static void -dbus_usbos_ctl_complete(usbos_info_t *usbos_info, int type, int urbstatus) -{ - int status = DBUS_ERR; - - if (usbos_info == NULL) - return; - - switch (urbstatus) { - case 0: - status = DBUS_OK; - break; - case -EINPROGRESS: - case -ENOENT: - default: -#ifdef INTR_EP_ENABLE - DBUSERR(("%s:%d fail status %d bus:%d susp:%d intr:%d ctli:%d ctlo:%d\n", - __FUNCTION__, type, urbstatus, - usbos_info->pub->busstate, g_probe_info.suspend_state, - usbos_info->intr_urb_submitted, usbos_info->ctlin_urb_submitted, - usbos_info->ctlout_urb_submitted)); -#else - DBUSERR(("%s: failed with status %d\n", __FUNCTION__, urbstatus)); - status = DBUS_ERR; - break; -#endif /* INTR_EP_ENABLE */ - } - - if (usbos_info->cbarg && usbos_info->cbs) { - if (usbos_info->cbs->ctl_complete) - usbos_info->cbs->ctl_complete(usbos_info->cbarg, type, status); - } -} - -/** called by Linux */ -static void -dbus_usbos_ctlread_complete(CALLBACK_ARGS) -{ - usbos_info_t *usbos_info = (usbos_info_t *)urb->context; - - ASSERT(urb); - usbos_info = (usbos_info_t *)urb->context; - - dbus_usbos_ctl_complete(usbos_info, DBUS_CBCTL_READ, urb->status); - -#ifdef USBOS_THREAD - if (usbos_info->rxctl_deferrespok) { - usbos_info->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | - USB_RECIP_INTERFACE; - usbos_info->ctl_read.bRequest = 1; - } -#endif - - up(&usbos_info->ctl_lock); - - USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); -} - -/** called by Linux */ -static void -dbus_usbos_ctlwrite_complete(CALLBACK_ARGS) -{ - usbos_info_t *usbos_info = (usbos_info_t *)urb->context; - - ASSERT(urb); - usbos_info = (usbos_info_t *)urb->context; - - dbus_usbos_ctl_complete(usbos_info, DBUS_CBCTL_WRITE, urb->status); - -#ifdef USBOS_TX_THREAD - usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED; -#endif /* USBOS_TX_THREAD */ - - up(&usbos_info->ctl_lock); - - USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); -} - -#ifdef INTR_EP_ENABLE -/** called by Linux */ -static void -dbus_usbos_intr_complete(CALLBACK_ARGS) -{ - usbos_info_t *usbos_info = (usbos_info_t *)urb->context; - bool killed = (g_probe_info.suspend_state == USBOS_SUSPEND_STATE_SUSPEND_PENDING) ? 1 : 0; - - if (usbos_info == NULL || usbos_info->pub == NULL) - return; - if ((urb->status == -ENOENT && (!killed)) || urb->status == -ESHUTDOWN || - urb->status == -ENODEV) { - dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN); - } - - if (usbos_info->pub->busstate == DBUS_STATE_DOWN) { - DBUSERR(("%s: intr cb when DBUS down, ignoring\n", __FUNCTION__)); - return; - } - dbus_usbos_ctl_complete(usbos_info, DBUS_CBINTR_POLL, urb->status); -} -#endif /* INTR_EP_ENABLE */ - -/** - * when the bus is going to sleep or halt, the Linux kernel requires us to take ownership of our - * URBs again. Multiple code paths in this file require a list of URBs to be cancelled in a - * concurrency save manner. - */ -static void -dbus_usbos_unlink(struct list_head *urbreq_q, spinlock_t *lock) -{ - urb_req_t *req; - - /* dbus_usbos_recv_complete() adds req back to req_freeq */ - while ((req = dbus_usbos_qdeq(urbreq_q, lock)) != NULL) { - ASSERT(req->urb != NULL); - USB_UNLINK_URB(req->urb); - } -} - -/** multiple code paths in this file require the bus to stop */ -static void -dbus_usbos_cancel_all_urbs(usbos_info_t *usbos_info) -{ - int rxposted, txposted; - - DBUSTRACE(("%s: unlink all URBs\n", __FUNCTION__)); - -#ifdef USBOS_TX_THREAD - usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED; - - /* Yield the CPU to TX thread so all pending requests are submitted */ - while (!list_empty(&usbos_info->usbos_tx_list)) { - wake_up_interruptible(&usbos_info->usbos_tx_queue_head); - OSL_SLEEP(10); - } -#endif /* USBOS_TX_THREAD */ - - /* tell Linux kernel to cancel a single intr, ctl and blk URB */ - if (usbos_info->intr_urb) - USB_UNLINK_URB(usbos_info->intr_urb); - if (usbos_info->ctl_urb) - USB_UNLINK_URB(usbos_info->ctl_urb); - if (usbos_info->blk_urb) - USB_UNLINK_URB(usbos_info->blk_urb); - - dbus_usbos_unlink(&usbos_info->req_txpostedq, &usbos_info->txposted_lock); - dbus_usbos_unlink(&usbos_info->req_rxpostedq, &usbos_info->rxposted_lock); - - /* Wait until the callbacks for all submitted URBs have been called, because the - * handler needs to know is an USB suspend is in progress. - */ - SPINWAIT((atomic_read(&usbos_info->txposted) != 0 || - atomic_read(&usbos_info->rxposted) != 0), 10000); - - txposted = atomic_read(&usbos_info->txposted); - rxposted = atomic_read(&usbos_info->rxposted); - if (txposted != 0 || rxposted != 0) { - DBUSERR(("%s ERROR: REQs posted, rx=%d tx=%d!\n", - __FUNCTION__, rxposted, txposted)); - } -} /* dbus_usbos_cancel_all_urbs */ - -/** multiple code paths require the bus to stop */ -static void -dbusos_stop(usbos_info_t *usbos_info) -{ - urb_req_t *req; - int rxposted; - req = NULL; - BCM_REFERENCE(req); - - ASSERT(usbos_info); - - dbus_usbos_state_change(usbos_info, DBUS_STATE_DOWN); - - dbus_usbos_cancel_all_urbs(usbos_info); - -#ifdef USBOS_THREAD - /* yield the CPU to rx packet thread */ - while (1) { - if (atomic_read(&usbos_info->usbos_list_cnt) <= 0) break; - wake_up_interruptible(&usbos_info->usbos_queue_head); - OSL_SLEEP(3); - } -#endif /* USBOS_THREAD */ - - rxposted = atomic_read(&usbos_info->rxposted); - if (rxposted > 0) { - DBUSERR(("%s ERROR: rx REQs posted=%d in stop!\n", __FUNCTION__, - rxposted)); - } - - ASSERT(atomic_read(&usbos_info->txposted) == 0 && rxposted == 0); - -} /* dbusos_stop */ - -#if defined(USB_SUSPEND_AVAILABLE) - -/** - * Linux kernel sports a 'USB auto suspend' feature. See: http://lwn.net/Articles/373550/ - * The suspend method is called by the Linux kernel to warn the driver that the device is going to - * be suspended. If the driver returns a negative error code, the suspend will be aborted. If the - * driver returns 0, it must cancel all outstanding URBs (usb_kill_urb()) and not submit any more. - */ -static int -dbus_usbos_suspend(struct usb_interface *intf, - pm_message_t message) -{ - DBUSERR(("%s suspend state: %d\n", __FUNCTION__, g_probe_info.suspend_state)); - /* DHD for full dongle model */ - g_probe_info.suspend_state = USBOS_SUSPEND_STATE_SUSPEND_PENDING; - dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_SLEEP); - dbus_usbos_cancel_all_urbs((usbos_info_t*)g_probe_info.usbos_info); - g_probe_info.suspend_state = USBOS_SUSPEND_STATE_SUSPENDED; - - return 0; -} - -/** - * The resume method is called to tell the driver that the device has been resumed and the driver - * can return to normal operation. URBs may once more be submitted. - */ -static int dbus_usbos_resume(struct usb_interface *intf) -{ - DBUSERR(("%s Device resumed\n", __FUNCTION__)); - - dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_UP); - g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; - return 0; -} - -/** -* This function is directly called by the Linux kernel, when the suspended device has been reset -* instead of being resumed -*/ -static int dbus_usbos_reset_resume(struct usb_interface *intf) -{ - DBUSERR(("%s Device reset resumed\n", __FUNCTION__)); - - /* The device may have lost power, so a firmware download may be required */ - dbus_usbos_state_change((usbos_info_t*)g_probe_info.usbos_info, DBUS_STATE_DL_NEEDED); - g_probe_info.suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE; - return 0; -} - -#endif /* USB_SUSPEND_AVAILABLE */ - -/** - * Called by Linux kernel at initialization time, kernel wants to know if our driver will accept the - * caller supplied USB interface. Note that USB drivers are bound to interfaces, and not to USB - * devices. - */ -#ifdef KERNEL26 -#define DBUS_USBOS_PROBE() static int dbus_usbos_probe(struct usb_interface *intf, const struct usb_device_id *id) -#define DBUS_USBOS_DISCONNECT() static void dbus_usbos_disconnect(struct usb_interface *intf) -#else -#define DBUS_USBOS_PROBE() static void * dbus_usbos_probe(struct usb_device *usb, unsigned int ifnum, const struct usb_device_id *id) -#define DBUS_USBOS_DISCONNECT() static void dbus_usbos_disconnect(struct usb_device *usb, void *ptr) -#endif /* KERNEL26 */ - -DBUS_USBOS_PROBE() -{ - int ep; - struct usb_endpoint_descriptor *endpoint; - int ret = 0; -#ifdef KERNEL26 - struct usb_device *usb = interface_to_usbdev(intf); -#else - int claimed = 0; -#endif - int num_of_eps; -#ifdef BCMUSBDEV_COMPOSITE - int wlan_if = -1; - bool intr_ep = FALSE; -#endif /* BCMUSBDEV_COMPOSITE */ - wifi_adapter_info_t *adapter; - - DHD_MUTEX_LOCK(); - - DBUSERR(("%s: bus num(busnum)=%d, slot num (portnum)=%d\n", __FUNCTION__, - usb->bus->busnum, usb->portnum)); - adapter = dhd_wifi_platform_attach_adapter(USB_BUS, usb->bus->busnum, - usb->portnum, WIFI_STATUS_POWER_ON); - if (adapter == NULL) { - DBUSERR(("%s: can't find adapter info for this chip\n", __FUNCTION__)); - goto fail; - } - -#ifdef BCMUSBDEV_COMPOSITE - wlan_if = dbus_usbos_intf_wlan(usb); -#ifdef KERNEL26 - if ((wlan_if >= 0) && (IFPTR(usb, wlan_if) == intf)) -#else - if (wlan_if == ifnum) -#endif /* KERNEL26 */ - { -#endif /* BCMUSBDEV_COMPOSITE */ - g_probe_info.usb = usb; - g_probe_info.dldone = TRUE; -#ifdef BCMUSBDEV_COMPOSITE - } else { - DBUSTRACE(("dbus_usbos_probe: skip probe for non WLAN interface\n")); - ret = BCME_UNSUPPORTED; - goto fail; - } -#endif /* BCMUSBDEV_COMPOSITE */ - -#ifdef KERNEL26 - g_probe_info.intf = intf; -#endif /* KERNEL26 */ - -#ifdef BCMUSBDEV_COMPOSITE - if (IFDESC(usb, wlan_if).bInterfaceNumber > USB_COMPIF_MAX) -#else - if (IFDESC(usb, CONTROL_IF).bInterfaceNumber) -#endif /* BCMUSBDEV_COMPOSITE */ - { - ret = -1; - goto fail; - } - if (id != NULL) { - g_probe_info.vid = id->idVendor; - g_probe_info.pid = id->idProduct; - } - -#ifdef KERNEL26 - usb_set_intfdata(intf, &g_probe_info); -#endif - - /* Check that the device supports only one configuration */ - if (usb->descriptor.bNumConfigurations != 1) { - ret = -1; - goto fail; - } - - if (usb->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) { -#ifdef BCMUSBDEV_COMPOSITE - if ((usb->descriptor.bDeviceClass != USB_CLASS_MISC) && - (usb->descriptor.bDeviceClass != USB_CLASS_WIRELESS)) { -#endif /* BCMUSBDEV_COMPOSITE */ - ret = -1; - goto fail; -#ifdef BCMUSBDEV_COMPOSITE - } -#endif /* BCMUSBDEV_COMPOSITE */ - } - - /* - * Only the BDC interface configuration is supported: - * Device class: USB_CLASS_VENDOR_SPEC - * if0 class: USB_CLASS_VENDOR_SPEC - * if0/ep0: control - * if0/ep1: bulk in - * if0/ep2: bulk out (ok if swapped with bulk in) - */ - if (CONFIGDESC(usb)->bNumInterfaces != 1) { -#ifdef BCMUSBDEV_COMPOSITE - if (CONFIGDESC(usb)->bNumInterfaces > USB_COMPIF_MAX) { -#endif /* BCMUSBDEV_COMPOSITE */ - ret = -1; - goto fail; -#ifdef BCMUSBDEV_COMPOSITE - } -#endif /* BCMUSBDEV_COMPOSITE */ - } - - /* Check interface */ -#ifndef KERNEL26 -#ifdef BCMUSBDEV_COMPOSITE - if (usb_interface_claimed(IFPTR(usb, wlan_if))) -#else - if (usb_interface_claimed(IFPTR(usb, CONTROL_IF))) -#endif /* BCMUSBDEV_COMPOSITE */ - { - ret = -1; - goto fail; - } -#endif /* !KERNEL26 */ - -#ifdef BCMUSBDEV_COMPOSITE - if ((IFDESC(usb, wlan_if).bInterfaceClass != USB_CLASS_VENDOR_SPEC || - IFDESC(usb, wlan_if).bInterfaceSubClass != 2 || - IFDESC(usb, wlan_if).bInterfaceProtocol != 0xff) && - (IFDESC(usb, wlan_if).bInterfaceClass != USB_CLASS_MISC || - IFDESC(usb, wlan_if).bInterfaceSubClass != USB_SUBCLASS_COMMON || - IFDESC(usb, wlan_if).bInterfaceProtocol != USB_PROTO_IAD)) -#else - if (IFDESC(usb, CONTROL_IF).bInterfaceClass != USB_CLASS_VENDOR_SPEC || - IFDESC(usb, CONTROL_IF).bInterfaceSubClass != 2 || - IFDESC(usb, CONTROL_IF).bInterfaceProtocol != 0xff) -#endif /* BCMUSBDEV_COMPOSITE */ - { -#ifdef BCMUSBDEV_COMPOSITE - DBUSERR(("%s: invalid control interface: class %d, subclass %d, proto %d\n", - __FUNCTION__, - IFDESC(usb, wlan_if).bInterfaceClass, - IFDESC(usb, wlan_if).bInterfaceSubClass, - IFDESC(usb, wlan_if).bInterfaceProtocol)); -#else - DBUSERR(("%s: invalid control interface: class %d, subclass %d, proto %d\n", - __FUNCTION__, - IFDESC(usb, CONTROL_IF).bInterfaceClass, - IFDESC(usb, CONTROL_IF).bInterfaceSubClass, - IFDESC(usb, CONTROL_IF).bInterfaceProtocol)); -#endif /* BCMUSBDEV_COMPOSITE */ - ret = -1; - goto fail; - } - - /* Check control endpoint */ -#ifdef BCMUSBDEV_COMPOSITE - endpoint = &IFEPDESC(usb, wlan_if, 0); -#else - endpoint = &IFEPDESC(usb, CONTROL_IF, 0); -#endif /* BCMUSBDEV_COMPOSITE */ - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) { -#ifdef BCMUSBDEV_COMPOSITE - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != - USB_ENDPOINT_XFER_BULK) { -#endif /* BCMUSBDEV_COMPOSITE */ - DBUSERR(("%s: invalid control endpoint %d\n", - __FUNCTION__, endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)); - ret = -1; - goto fail; -#ifdef BCMUSBDEV_COMPOSITE - } -#endif /* BCMUSBDEV_COMPOSITE */ - } - -#ifdef BCMUSBDEV_COMPOSITE - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) { -#endif /* BCMUSBDEV_COMPOSITE */ - g_probe_info.intr_pipe = - usb_rcvintpipe(usb, endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); -#ifdef BCMUSBDEV_COMPOSITE - intr_ep = TRUE; - } -#endif /* BCMUSBDEV_COMPOSITE */ - -#ifndef KERNEL26 - /* Claim interface */ -#ifdef BCMUSBDEV_COMPOSITE - usb_driver_claim_interface(&dbus_usbdev, IFPTR(usb, wlan_if), &g_probe_info); -#else - usb_driver_claim_interface(&dbus_usbdev, IFPTR(usb, CONTROL_IF), &g_probe_info); -#endif /* BCMUSBDEV_COMPOSITE */ - claimed = 1; -#endif /* !KERNEL26 */ - g_probe_info.rx_pipe = 0; - g_probe_info.rx_pipe2 = 0; - g_probe_info.tx_pipe = 0; -#ifdef BCMUSBDEV_COMPOSITE - if (intr_ep) - ep = 1; - else - ep = 0; - num_of_eps = IFDESC(usb, wlan_if).bNumEndpoints - 1; -#else - num_of_eps = IFDESC(usb, BULK_IF).bNumEndpoints - 1; -#endif /* BCMUSBDEV_COMPOSITE */ - - if ((num_of_eps != 2) && (num_of_eps != 3)) { -#ifdef BCMUSBDEV_COMPOSITE - if (num_of_eps > 7) -#endif /* BCMUSBDEV_COMPOSITE */ - ASSERT(0); - } - /* Check data endpoints and get pipes */ -#ifdef BCMUSBDEV_COMPOSITE - for (; ep <= num_of_eps; ep++) -#else - for (ep = 1; ep <= num_of_eps; ep++) -#endif /* BCMUSBDEV_COMPOSITE */ - { -#ifdef BCMUSBDEV_COMPOSITE - endpoint = &IFEPDESC(usb, wlan_if, ep); -#else - endpoint = &IFEPDESC(usb, BULK_IF, ep); -#endif /* BCMUSBDEV_COMPOSITE */ - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != - USB_ENDPOINT_XFER_BULK) { - DBUSERR(("%s: invalid data endpoint %d\n", - __FUNCTION__, ep)); - ret = -1; - goto fail; - } - - if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { - /* direction: dongle->host */ - if (!g_probe_info.rx_pipe) { - g_probe_info.rx_pipe = usb_rcvbulkpipe(usb, - (endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)); - } else { - g_probe_info.rx_pipe2 = usb_rcvbulkpipe(usb, - (endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)); - } - - } else - g_probe_info.tx_pipe = usb_sndbulkpipe(usb, (endpoint->bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK)); - } - - /* Allocate interrupt URB and data buffer */ - /* RNDIS says 8-byte intr, our old drivers used 4-byte */ -#ifdef BCMUSBDEV_COMPOSITE - g_probe_info.intr_size = (IFEPDESC(usb, wlan_if, 0).wMaxPacketSize == 16) ? 8 : 4; - g_probe_info.interval = IFEPDESC(usb, wlan_if, 0).bInterval; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)) - usb->quirks |= USB_QUIRK_NO_SET_INTF; -#endif -#else - g_probe_info.intr_size = (IFEPDESC(usb, CONTROL_IF, 0).wMaxPacketSize == 16) ? 8 : 4; - g_probe_info.interval = IFEPDESC(usb, CONTROL_IF, 0).bInterval; -#endif /* BCMUSBDEV_COMPOSITE */ - -#ifndef KERNEL26 - /* usb_fill_int_urb does the interval decoding in 2.6 */ - if (usb->speed == USB_SPEED_HIGH) - g_probe_info.interval = 1 << (g_probe_info.interval - 1); -#endif - if (usb->speed == USB_SPEED_SUPER) { - g_probe_info.device_speed = SUPER_SPEED; - DBUSERR(("super speed device detected\n")); - } else if (usb->speed == USB_SPEED_HIGH) { - g_probe_info.device_speed = HIGH_SPEED; - DBUSERR(("high speed device detected\n")); - } else { - g_probe_info.device_speed = FULL_SPEED; - DBUSERR(("full speed device detected\n")); - } - if (g_probe_info.dereged == FALSE && probe_cb) { - disc_arg = probe_cb(probe_arg, "", USB_BUS, usb->bus->busnum, usb->portnum, 0); - } - - g_probe_info.disc_cb_done = FALSE; - -#ifdef KERNEL26 - intf->needs_remote_wakeup = 1; -#endif /* KERNEL26 */ - DHD_MUTEX_UNLOCK(); - - /* Success */ -#ifdef KERNEL26 - return DBUS_OK; -#else - usb_inc_dev_use(usb); - return &g_probe_info; -#endif - -fail: - printf("%s: Exit ret=%d\n", __FUNCTION__, ret); -#ifdef BCMUSBDEV_COMPOSITE - if (ret != BCME_UNSUPPORTED) -#endif /* BCMUSBDEV_COMPOSITE */ - DBUSERR(("%s: failed with errno %d\n", __FUNCTION__, ret)); -#ifndef KERNEL26 - if (claimed) -#ifdef BCMUSBDEV_COMPOSITE - usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, wlan_if)); -#else - usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, CONTROL_IF)); -#endif /* BCMUSBDEV_COMPOSITE */ -#endif /* !KERNEL26 */ - - DHD_MUTEX_UNLOCK(); -#ifdef KERNEL26 - usb_set_intfdata(intf, NULL); - return ret; -#else - return NULL; -#endif -} /* dbus_usbos_probe */ - -/** Called by Linux kernel, is the counter part of dbus_usbos_probe() */ -DBUS_USBOS_DISCONNECT() -{ -#ifdef KERNEL26 - struct usb_device *usb = interface_to_usbdev(intf); - probe_info_t *probe_usb_init_data = usb_get_intfdata(intf); -#else - probe_info_t *probe_usb_init_data = (probe_info_t *) ptr; -#endif - usbos_info_t *usbos_info; - - DHD_MUTEX_LOCK(); - - DBUSERR(("%s: bus num(busnum)=%d, slot num (portnum)=%d\n", __FUNCTION__, - usb->bus->busnum, usb->portnum)); - - if (probe_usb_init_data) { - usbos_info = (usbos_info_t *) probe_usb_init_data->usbos_info; - if (usbos_info) { - if ((probe_usb_init_data->dereged == FALSE) && disconnect_cb && disc_arg) { - disconnect_cb(disc_arg); - disc_arg = NULL; - probe_usb_init_data->disc_cb_done = TRUE; - } - } - } - - if (usb) { -#ifndef KERNEL26 -#ifdef BCMUSBDEV_COMPOSITE - usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, wlan_if)); -#else - usb_driver_release_interface(&dbus_usbdev, IFPTR(usb, CONTROL_IF)); -#endif /* BCMUSBDEV_COMPOSITE */ - usb_dec_dev_use(usb); -#endif /* !KERNEL26 */ - } - DHD_MUTEX_UNLOCK(); -} /* dbus_usbos_disconnect */ - -#define LOOPBACK_PKT_START 0xBABE1234 - -bool is_loopback_pkt(void *buf) -{ - - uint32 *buf_ptr = (uint32 *) buf; - - if (*buf_ptr == LOOPBACK_PKT_START) - return TRUE; - return FALSE; - -} - -int matches_loopback_pkt(void *buf) -{ - int i, j; - unsigned char *cbuf = (unsigned char *) buf; - - for (i = 4; i < loopback_size; i++) { - if (cbuf[i] != (i % 256)) { - printf("%s: mismatch at i=%d %d : ", __FUNCTION__, i, cbuf[i]); - for (j = i; ((j < i+ 16) && (j < loopback_size)); j++) { - printf("%d ", cbuf[j]); - } - printf("\n"); - return 0; - } - } - loopback_rx_cnt++; - return 1; -} - -int dbus_usbos_loopback_tx(void *usbos_info_ptr, int cnt, int size) -{ - usbos_info_t *usbos_info = (usbos_info_t *) usbos_info_ptr; - unsigned char *buf; - int j; - void* p = NULL; - int rc, last_rx_cnt; - int tx_failed_cnt; - int max_size = 1650; - int usb_packet_size = 512; - int min_packet_size = 10; - - if (size % usb_packet_size == 0) { - size = size - 1; - DBUSERR(("%s: overriding size=%d \n", __FUNCTION__, size)); - } - - if (size < min_packet_size) { - size = min_packet_size; - DBUSERR(("%s: overriding size=%d\n", __FUNCTION__, min_packet_size)); - } - if (size > max_size) { - size = max_size; - DBUSERR(("%s: overriding size=%d\n", __FUNCTION__, max_size)); - } - - loopback_tx_cnt = 0; - loopback_rx_cnt = 0; - tx_failed_cnt = 0; - loopback_size = size; - - while (loopback_tx_cnt < cnt) { - uint32 *x; - int pkt_size = loopback_size; - - p = PKTGET(usbos_info->pub->osh, pkt_size, TRUE); - if (p == NULL) { - DBUSERR(("%s:%d Failed to allocate packet sz=%d\n", - __FUNCTION__, __LINE__, pkt_size)); - return BCME_ERROR; - } - x = (uint32*) PKTDATA(usbos_info->pub->osh, p); - *x = LOOPBACK_PKT_START; - buf = (unsigned char*) x; - for (j = 4; j < pkt_size; j++) { - buf[j] = j % 256; - } - rc = dbus_send_buf(usbos_info->pub, buf, pkt_size, p); - if (rc != BCME_OK) { - DBUSERR(("%s:%d Freeing packet \n", __FUNCTION__, __LINE__)); - PKTFREE(usbos_info->pub->osh, p, TRUE); - dbus_usbos_wait(usbos_info, 1); - tx_failed_cnt++; - } else { - loopback_tx_cnt++; - tx_failed_cnt = 0; - } - if (tx_failed_cnt == 5) { - DBUSERR(("%s : Failed to send loopback packets cnt=%d loopback_tx_cnt=%d\n", - __FUNCTION__, cnt, loopback_tx_cnt)); - break; - } - } - printf("Transmitted %d loopback packets of size %d\n", loopback_tx_cnt, loopback_size); - - last_rx_cnt = loopback_rx_cnt; - while (loopback_rx_cnt < loopback_tx_cnt) { - dbus_usbos_wait(usbos_info, 1); - if (loopback_rx_cnt <= last_rx_cnt) { - DBUSERR(("%s: Matched rx cnt stuck at %d \n", __FUNCTION__, last_rx_cnt)); - return BCME_ERROR; - } - last_rx_cnt = loopback_rx_cnt; - } - printf("Received %d loopback packets of size %d\n", loopback_tx_cnt, loopback_size); - - return BCME_OK; -} /* dbus_usbos_loopback_tx */ - -/** - * Higher layer (dbus_usb.c) wants to transmit an I/O Request Block - * @param[in] txirb txirb->pkt, if non-zero, contains a single or a chain of packets - */ -static int -dbus_usbos_intf_send_irb(void *bus, dbus_irb_tx_t *txirb) -{ - usbos_info_t *usbos_info = (usbos_info_t *) bus; - urb_req_t *req, *req_zlp = NULL; - int ret = DBUS_OK; - unsigned long flags; - void *pkt; - uint32 buffer_length; - uint8 *buf; - - if ((usbos_info == NULL) || !usbos_info->tx_pipe) { - return DBUS_ERR; - } - - if (txirb->pkt != NULL) { - buffer_length = pkttotlen(usbos_info->pub->osh, txirb->pkt); - /* In case of multiple packets the values below may be overwritten */ - txirb->send_buf = NULL; - buf = PKTDATA(usbos_info->pub->osh, txirb->pkt); - } else { /* txirb->buf != NULL */ - ASSERT(txirb->buf != NULL); - ASSERT(txirb->send_buf == NULL); - buffer_length = txirb->len; - buf = txirb->buf; - } - - if (!(req = dbus_usbos_qdeq(&usbos_info->req_txfreeq, &usbos_info->txfree_lock))) { - DBUSERR(("%s No free URB!\n", __FUNCTION__)); - return DBUS_ERR_TXDROP; - } - - /* If not using standard Linux kernel functionality for handling Zero Length Packet(ZLP), - * the dbus needs to generate ZLP when length is multiple of MaxPacketSize. - */ -#ifndef WL_URB_ZPKT - if (!(buffer_length % usbos_info->maxps)) { - if (!(req_zlp = - dbus_usbos_qdeq(&usbos_info->req_txfreeq, &usbos_info->txfree_lock))) { - DBUSERR(("%s No free URB for ZLP!\n", __FUNCTION__)); - dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock); - return DBUS_ERR_TXDROP; - } - - /* No txirb, so that dbus_usbos_send_complete can differentiate between - * DATA and ZLP. - */ - req_zlp->arg = NULL; - req_zlp->usbinfo = usbos_info; - req_zlp->buf_len = 0; - - usb_fill_bulk_urb(req_zlp->urb, usbos_info->usb, usbos_info->tx_pipe, NULL, - 0, (usb_complete_t)dbus_usbos_send_complete, req_zlp); - - req_zlp->urb->transfer_flags |= URB_QUEUE_BULK; - } -#endif /* !WL_URB_ZPKT */ - -#ifndef USBOS_TX_THREAD - /* Disable USB autosuspend until this request completes, request USB resume if needed. - * Because this call runs asynchronously, there is no guarantee the bus is resumed before - * the URB is submitted, and the URB might be dropped. Use USBOS_TX_THREAD to avoid - * this. - */ - USB_AUTOPM_GET_INTERFACE_ASYNC(g_probe_info.intf); -#endif /* !USBOS_TX_THREAD */ - - spin_lock_irqsave(&usbos_info->txlock, flags); - - req->arg = txirb; - req->usbinfo = usbos_info; - req->buf_len = 0; - - /* Prepare the URB */ - if (txirb->pkt != NULL) { - uint32 pktlen; - uint8 *transfer_buf; - - /* For multiple packets, allocate contiguous buffer and copy packet data to it */ - if (PKTNEXT(usbos_info->pub->osh, txirb->pkt)) { - transfer_buf = MALLOC(usbos_info->pub->osh, buffer_length); - if (!transfer_buf) { - ret = DBUS_ERR_TXDROP; - DBUSERR(("fail to alloc to usb buffer\n")); - goto fail; - } - - pkt = txirb->pkt; - txirb->send_buf = transfer_buf; - req->buf_len = buffer_length; - - while (pkt) { - pktlen = PKTLEN(usbos_info->pub->osh, pkt); - bcopy(PKTDATA(usbos_info->pub->osh, pkt), transfer_buf, pktlen); - transfer_buf += pktlen; - pkt = PKTNEXT(usbos_info->pub->osh, pkt); - } - - ASSERT(((uint8 *) txirb->send_buf + buffer_length) == transfer_buf); - - /* Overwrite buf pointer with pointer to allocated contiguous transfer_buf - */ - buf = txirb->send_buf; - } - } - - usb_fill_bulk_urb(req->urb, usbos_info->usb, usbos_info->tx_pipe, buf, - buffer_length, (usb_complete_t)dbus_usbos_send_complete, req); - - req->urb->transfer_flags |= URB_QUEUE_BULK; - -#ifdef USBOS_TX_THREAD - /* Enqueue TX request, the TX thread will resume the bus if needed and submit - * it asynchronously - */ - dbus_usbos_qenq(&usbos_info->usbos_tx_list, req, &usbos_info->usbos_tx_list_lock); - if (req_zlp != NULL) { - dbus_usbos_qenq(&usbos_info->usbos_tx_list, req_zlp, - &usbos_info->usbos_tx_list_lock); - } - spin_unlock_irqrestore(&usbos_info->txlock, flags); - - wake_up_interruptible(&usbos_info->usbos_tx_queue_head); - return DBUS_OK; -#else - if ((ret = USB_SUBMIT_URB(req->urb))) { - ret = DBUS_ERR_TXDROP; - goto fail; - } - - dbus_usbos_qenq(&usbos_info->req_txpostedq, req, &usbos_info->txposted_lock); - atomic_inc(&usbos_info->txposted); - - if (req_zlp != NULL) { - if ((ret = USB_SUBMIT_URB(req_zlp->urb))) { - DBUSERR(("failed to submit ZLP URB!\n")); - ASSERT(0); - ret = DBUS_ERR_TXDROP; - goto fail2; - } - - dbus_usbos_qenq(&usbos_info->req_txpostedq, req_zlp, &usbos_info->txposted_lock); - /* Also increment txposted for zlp packet, as it will be decremented in - * dbus_usbos_send_complete() - */ - atomic_inc(&usbos_info->txposted); - } - - spin_unlock_irqrestore(&usbos_info->txlock, flags); - return DBUS_OK; -#endif /* USBOS_TX_THREAD */ - -fail: - if (txirb->send_buf != NULL) { - MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len); - txirb->send_buf = NULL; - req->buf_len = 0; - } - dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock); -#ifndef USBOS_TX_THREAD -fail2: -#endif - if (req_zlp != NULL) { - dbus_usbos_qenq(&usbos_info->req_txfreeq, req_zlp, &usbos_info->txfree_lock); - } - - spin_unlock_irqrestore(&usbos_info->txlock, flags); - -#ifndef USBOS_TX_THREAD - USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); -#endif /* !USBOS_TX_THREAD */ - - return ret; -} /* dbus_usbos_intf_send_irb */ - -/** Higher layer (dbus_usb.c) recycles a received (and used) packet. */ -static int -dbus_usbos_intf_recv_irb(void *bus, dbus_irb_rx_t *rxirb) -{ - usbos_info_t *usbos_info = (usbos_info_t *) bus; - int ret = DBUS_OK; - - if (usbos_info == NULL) - return DBUS_ERR; - - ret = dbus_usbos_recv_urb_submit(usbos_info, rxirb, 0); - return ret; -} - -static int -dbus_usbos_intf_recv_irb_from_ep(void *bus, dbus_irb_rx_t *rxirb, uint32 ep_idx) -{ - usbos_info_t *usbos_info = (usbos_info_t *) bus; - int ret = DBUS_OK; - - if (usbos_info == NULL) - return DBUS_ERR; - -#ifdef INTR_EP_ENABLE - /* By specifying the ep_idx value of 0xff, the cdc layer is asking to - * submit an interrupt URB - */ - if (rxirb == NULL && ep_idx == 0xff) { - /* submit intr URB */ - if ((ret = USB_SUBMIT_URB(usbos_info->intr_urb)) < 0) { - DBUSERR(("%s intr USB_SUBMIT_URB failed, status %d\n", - __FUNCTION__, ret)); - } - return ret; - } -#else - if (rxirb == NULL) { - return DBUS_ERR; - } -#endif /* INTR_EP_ENABLE */ - - ret = dbus_usbos_recv_urb_submit(usbos_info, rxirb, ep_idx); - return ret; -} - -/** Higher layer (dbus_usb.c) want to cancel an IRB */ -static int -dbus_usbos_intf_cancel_irb(void *bus, dbus_irb_tx_t *txirb) -{ - usbos_info_t *usbos_info = (usbos_info_t *) bus; - - if (usbos_info == NULL) - return DBUS_ERR; - - return DBUS_ERR; -} - -/** Only one CTL transfer can be pending at any time. This function may block. */ -static int -dbus_usbos_intf_send_ctl(void *bus, uint8 *buf, int len) -{ - usbos_info_t *usbos_info = (usbos_info_t *) bus; - uint16 size; -#ifndef USBOS_TX_THREAD - int status; -#endif /* USBOS_TX_THREAD */ - - if ((usbos_info == NULL) || (buf == NULL) || (len == 0)) - return DBUS_ERR; - - if (usbos_info->ctl_urb == NULL) - return DBUS_ERR; - - /* Block until a pending CTL transfer has completed */ - if (down_interruptible(&usbos_info->ctl_lock) != 0) { - return DBUS_ERR_TXCTLFAIL; - } - -#ifdef USBOS_TX_THREAD - ASSERT(usbos_info->ctl_state == USBOS_REQUEST_STATE_UNSCHEDULED); -#else - /* Disable USB autosuspend until this request completes, request USB resume if needed. - * Because this call runs asynchronously, there is no guarantee the bus is resumed before - * the URB is submitted, and the URB might be dropped. Use USBOS_TX_THREAD to avoid - * this. - */ - USB_AUTOPM_GET_INTERFACE_ASYNC(g_probe_info.intf); -#endif /* USBOS_TX_THREAD */ - - size = len; - usbos_info->ctl_write.wLength = cpu_to_le16p(&size); - usbos_info->ctl_urb->transfer_buffer_length = size; - - usb_fill_control_urb(usbos_info->ctl_urb, - usbos_info->usb, - usb_sndctrlpipe(usbos_info->usb, 0), - (unsigned char *) &usbos_info->ctl_write, - buf, size, (usb_complete_t)dbus_usbos_ctlwrite_complete, usbos_info); - -#ifdef USBOS_TX_THREAD - /* Enqueue CTRL request for transmission by the TX thread. The - * USB bus will first be resumed if needed. - */ - usbos_info->ctl_state = USBOS_REQUEST_STATE_SCHEDULED; - wake_up_interruptible(&usbos_info->usbos_tx_queue_head); -#else - status = USB_SUBMIT_URB(usbos_info->ctl_urb); - if (status < 0) { - DBUSERR(("%s: usb_submit_urb failed %d\n", __FUNCTION__, status)); - up(&usbos_info->ctl_lock); - - USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); - - return DBUS_ERR_TXCTLFAIL; - } -#endif /* USBOS_TX_THREAD */ - - return DBUS_OK; -} /* dbus_usbos_intf_send_ctl */ - -/** This function does not seem to be called by anyone, including dbus_usb.c */ -static int -dbus_usbos_intf_recv_ctl(void *bus, uint8 *buf, int len) -{ - usbos_info_t *usbos_info = (usbos_info_t *) bus; - int status; - uint16 size; - - if ((usbos_info == NULL) || (buf == NULL) || (len == 0)) - return DBUS_ERR; - - if (usbos_info->ctl_urb == NULL) - return DBUS_ERR; - - /* Block until a pending CTRL transfer has completed */ - if (down_interruptible(&usbos_info->ctl_lock) != 0) { - return DBUS_ERR_TXCTLFAIL; - } - - /* Disable USB autosuspend until this request completes, request USB resume if needed. */ - USB_AUTOPM_GET_INTERFACE_ASYNC(g_probe_info.intf); - - size = len; - usbos_info->ctl_read.wLength = cpu_to_le16p(&size); - usbos_info->ctl_urb->transfer_buffer_length = size; - - if (usbos_info->rxctl_deferrespok) { - /* BMAC model */ - usbos_info->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_VENDOR | - USB_RECIP_INTERFACE; - usbos_info->ctl_read.bRequest = DL_DEFER_RESP_OK; - } else { - /* full dongle model */ - usbos_info->ctl_read.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | - USB_RECIP_INTERFACE; - usbos_info->ctl_read.bRequest = 1; - } - - usb_fill_control_urb(usbos_info->ctl_urb, - usbos_info->usb, - usb_rcvctrlpipe(usbos_info->usb, 0), - (unsigned char *) &usbos_info->ctl_read, - buf, size, (usb_complete_t)dbus_usbos_ctlread_complete, usbos_info); - - status = USB_SUBMIT_URB(usbos_info->ctl_urb); - if (status < 0) { - DBUSERR(("%s: usb_submit_urb failed %d\n", __FUNCTION__, status)); - up(&usbos_info->ctl_lock); - - USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); - - return DBUS_ERR_RXCTLFAIL; - } - - return DBUS_OK; -} - -static int -dbus_usbos_intf_get_attrib(void *bus, dbus_attrib_t *attrib) -{ - usbos_info_t *usbos_info = (usbos_info_t *) bus; - - if ((usbos_info == NULL) || (attrib == NULL)) - return DBUS_ERR; - - attrib->bustype = DBUS_USB; - attrib->vid = g_probe_info.vid; - attrib->pid = g_probe_info.pid; - attrib->devid = 0x4322; - - attrib->nchan = 1; - - /* MaxPacketSize for USB hi-speed bulk out is 512 bytes - * and 64-bytes for full-speed. - * When sending pkt > MaxPacketSize, Host SW breaks it - * up into multiple packets. - */ - attrib->mtu = usbos_info->maxps; - - return DBUS_OK; -} - -/** Called by higher layer (dbus_usb.c) when it wants to 'up' the USB interface to the dongle */ -static int -dbus_usbos_intf_up(void *bus) -{ - usbos_info_t *usbos_info = (usbos_info_t *) bus; - uint16 ifnum; -#ifdef BCMUSBDEV_COMPOSITE - int wlan_if = 0; -#endif - if (usbos_info == NULL) - return DBUS_ERR; - - if (usbos_info->usb == NULL) - return DBUS_ERR; - -#if defined(INTR_EP_ENABLE) - /* full dongle use intr EP, bmac doesn't use it */ - if (usbos_info->intr_urb) { - int ret; - - usb_fill_int_urb(usbos_info->intr_urb, usbos_info->usb, - usbos_info->intr_pipe, &usbos_info->intr, - usbos_info->intr_size, (usb_complete_t)dbus_usbos_intr_complete, - usbos_info, usbos_info->interval); - - if ((ret = USB_SUBMIT_URB(usbos_info->intr_urb))) { - DBUSERR(("%s USB_SUBMIT_URB failed with status %d\n", __FUNCTION__, ret)); - return DBUS_ERR; - } - } -#endif - - if (usbos_info->ctl_urb) { - usbos_info->ctl_in_pipe = usb_rcvctrlpipe(usbos_info->usb, 0); - usbos_info->ctl_out_pipe = usb_sndctrlpipe(usbos_info->usb, 0); - -#ifdef BCMUSBDEV_COMPOSITE - wlan_if = dbus_usbos_intf_wlan(usbos_info->usb); - ifnum = cpu_to_le16(IFDESC(usbos_info->usb, wlan_if).bInterfaceNumber); -#else - ifnum = cpu_to_le16(IFDESC(usbos_info->usb, CONTROL_IF).bInterfaceNumber); -#endif /* BCMUSBDEV_COMPOSITE */ - /* CTL Write */ - usbos_info->ctl_write.bRequestType = - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE; - usbos_info->ctl_write.bRequest = 0; - usbos_info->ctl_write.wValue = cpu_to_le16(0); - usbos_info->ctl_write.wIndex = cpu_to_le16p(&ifnum); - - /* CTL Read */ - usbos_info->ctl_read.bRequestType = - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; - usbos_info->ctl_read.bRequest = 1; - usbos_info->ctl_read.wValue = cpu_to_le16(0); - usbos_info->ctl_read.wIndex = cpu_to_le16p(&ifnum); - } - - /* Success, indicate usbos_info is fully up */ - dbus_usbos_state_change(usbos_info, DBUS_STATE_UP); - - return DBUS_OK; -} /* dbus_usbos_intf_up */ - -static int -dbus_usbos_intf_down(void *bus) -{ - usbos_info_t *usbos_info = (usbos_info_t *) bus; - - if (usbos_info == NULL) - return DBUS_ERR; - - dbusos_stop(usbos_info); - return DBUS_OK; -} - -static int -dbus_usbos_intf_stop(void *bus) -{ - usbos_info_t *usbos_info = (usbos_info_t *) bus; - - if (usbos_info == NULL) - return DBUS_ERR; - - dbusos_stop(usbos_info); - return DBUS_OK; -} - - -/** Called by higher layer (dbus_usb.c) */ -static int -dbus_usbos_intf_set_config(void *bus, dbus_config_t *config) -{ - int err = DBUS_ERR; - usbos_info_t* usbos_info = bus; - - if (config->config_id == DBUS_CONFIG_ID_RXCTL_DEFERRES) { - usbos_info->rxctl_deferrespok = config->rxctl_deferrespok; - err = DBUS_OK; - } else if (config->config_id == DBUS_CONFIG_ID_AGGR_LIMIT) { - /* DBUS_CONFIG_ID_AGGR_LIMIT shouldn't be called after probe stage */ - ASSERT(disc_arg == NULL); - ASSERT(config->aggr_param.maxrxsf > 0); - ASSERT(config->aggr_param.maxrxsize > 0); - if (config->aggr_param.maxrxsize > usbos_info->rxbuf_len) { - int state = usbos_info->pub->busstate; - dbus_usbos_unlink(&usbos_info->req_rxpostedq, &usbos_info->rxposted_lock); - while (atomic_read(&usbos_info->rxposted)) { - DBUSTRACE(("%s rxposted is %d, delay 1 ms\n", __FUNCTION__, - atomic_read(&usbos_info->rxposted))); - dbus_usbos_wait(usbos_info, 1); - } - usbos_info->rxbuf_len = config->aggr_param.maxrxsize; - dbus_usbos_state_change(usbos_info, state); - } - err = DBUS_OK; - } - - return err; -} - - -/** Called by dbus_usb.c when it wants to download firmware into the dongle */ -bool -dbus_usbos_dl_cmd(usbos_info_t *usbinfo, uint8 cmd, void *buffer, int buflen) -{ - int transferred; - int index = 0; - char *tmpbuf; - - if ((usbinfo == NULL) || (buffer == NULL) || (buflen == 0)) - return FALSE; - - tmpbuf = (char *) MALLOC(usbinfo->pub->osh, buflen); - if (!tmpbuf) { - DBUSERR(("%s: Unable to allocate memory \n", __FUNCTION__)); - return FALSE; - } - -#ifdef BCM_REQUEST_FW - if (cmd == DL_GO) { - index = 1; - } -#endif - - /* Disable USB autosuspend until this request completes, request USB resume if needed. */ - USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); - - transferred = USB_CONTROL_MSG(usbinfo->usb, usb_rcvctrlpipe(usbinfo->usb, 0), - cmd, (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE), - 0, index, - (void*) tmpbuf, buflen, USB_CTRL_EP_TIMEOUT); - if (transferred == buflen) { - memcpy(buffer, tmpbuf, buflen); - } else { - DBUSERR(("%s: usb_control_msg failed %d\n", __FUNCTION__, transferred)); - } - - USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); - - MFREE(usbinfo->pub->osh, tmpbuf, buflen); - return (transferred == buflen); -} - -/** - * Called by dbus_usb.c when it wants to download a buffer into the dongle (e.g. as part of the - * download process, when writing nvram variables). - */ -int -dbus_write_membytes(usbos_info_t* usbinfo, bool set, uint32 address, uint8 *data, uint size) -{ - hwacc_t hwacc; - int write_bytes = 4; - int status; - int retval = 0; - - DBUSTRACE(("Enter:%s\n", __FUNCTION__)); - - /* Read is not supported */ - if (set == 0) { - DBUSERR(("Currently read is not supported!!\n")); - return -1; - } - - USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); - - hwacc.cmd = DL_CMD_WRHW; - hwacc.addr = address; - - DBUSTRACE(("Address:%x size:%d", hwacc.addr, size)); - do { - if (size >= 4) { - write_bytes = 4; - } else if (size >= 2) { - write_bytes = 2; - } else { - write_bytes = 1; - } - - hwacc.len = write_bytes; - - while (size >= write_bytes) { - hwacc.data = *((unsigned int*)data); - - status = USB_CONTROL_MSG(usbinfo->usb, usb_sndctrlpipe(usbinfo->usb, 0), - DL_WRHW, (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE), - 1, 0, (char *)&hwacc, sizeof(hwacc_t), USB_CTRL_EP_TIMEOUT); - - if (status < 0) { - retval = -1; - DBUSERR((" Ctrl write hwacc failed w/status %d @ address:%x \n", - status, hwacc.addr)); - goto err; - } - - hwacc.addr += write_bytes; - data += write_bytes; - size -= write_bytes; - } - } while (size > 0); - -err: - USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); - - return retval; -} - -int -dbus_usbos_readreg(void *bus, uint32 regaddr, int datalen, uint32 *value) -{ - usbos_info_t *usbinfo = (usbos_info_t *) bus; - int ret = DBUS_OK; - int transferred; - uint32 cmd; - hwacc_t hwacc; - - if (usbinfo == NULL) - return DBUS_ERR; - - if (datalen == 1) - cmd = DL_RDHW8; - else if (datalen == 2) - cmd = DL_RDHW16; - else - cmd = DL_RDHW32; - - USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); - - transferred = USB_CONTROL_MSG(usbinfo->usb, usb_rcvctrlpipe(usbinfo->usb, 0), - cmd, (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE), - (uint16)(regaddr), (uint16)(regaddr >> 16), - (void *) &hwacc, sizeof(hwacc_t), USB_CTRL_EP_TIMEOUT); - - if (transferred >= sizeof(hwacc_t)) { - *value = hwacc.data; - } else { - DBUSERR(("%s: usb_control_msg failed %d\n", __FUNCTION__, transferred)); - ret = DBUS_ERR; - } - - USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); - - return ret; -} - -int -dbus_usbos_writereg(void *bus, uint32 regaddr, int datalen, uint32 data) -{ - usbos_info_t *usbinfo = (usbos_info_t *) bus; - int ret = DBUS_OK; - int transferred; - uint32 cmd = DL_WRHW; - hwacc_t hwacc; - - if (usbinfo == NULL) - return DBUS_ERR; - - USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); - - hwacc.cmd = DL_WRHW; - hwacc.addr = regaddr; - hwacc.data = data; - hwacc.len = datalen; - - transferred = USB_CONTROL_MSG(usbinfo->usb, usb_sndctrlpipe(usbinfo->usb, 0), - cmd, (USB_DIR_OUT| USB_TYPE_VENDOR | USB_RECIP_INTERFACE), - 1, 0, - (void *) &hwacc, sizeof(hwacc_t), USB_CTRL_EP_TIMEOUT); - - if (transferred != sizeof(hwacc_t)) { - DBUSERR(("%s: usb_control_msg failed %d\n", __FUNCTION__, transferred)); - ret = DBUS_ERR; - } - - USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); - - return ret; -} - -int -dbus_usbos_wait(usbos_info_t *usbinfo, uint16 ms) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - if (in_interrupt()) - mdelay(ms); - else - msleep_interruptible(ms); -#else - wait_ms(ms); -#endif - return DBUS_OK; -} - -/** Called by dbus_usb.c as part of the firmware download process */ -bool -dbus_usbos_dl_send_bulk(usbos_info_t *usbinfo, void *buffer, int len) -{ - bool ret = TRUE; - int status; - int transferred = 0; - - if (usbinfo == NULL) - return DBUS_ERR; - - USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); - - status = USB_BULK_MSG(usbinfo->usb, usbinfo->tx_pipe, - buffer, len, - &transferred, USB_BULK_EP_TIMEOUT); - - if (status < 0) { - DBUSERR(("%s: usb_bulk_msg failed %d\n", __FUNCTION__, status)); - ret = FALSE; - } - - USB_AUTOPM_PUT_INTERFACE(g_probe_info.intf); - - return ret; -} - -static bool -dbus_usbos_intf_recv_needed(void *bus) -{ - return FALSE; -} - -/** - * Higher layer (dbus_usb.c) wants to execute a function on the condition that the rx spin lock has - * been acquired. - */ -static void* -dbus_usbos_intf_exec_rxlock(void *bus, exec_cb_t cb, struct exec_parms *args) -{ - usbos_info_t *usbos_info = (usbos_info_t *) bus; - void *ret; - unsigned long flags; - - if (usbos_info == NULL) - return NULL; - - spin_lock_irqsave(&usbos_info->rxlock, flags); - ret = cb(args); - spin_unlock_irqrestore(&usbos_info->rxlock, flags); - - return ret; -} - -static void* -dbus_usbos_intf_exec_txlock(void *bus, exec_cb_t cb, struct exec_parms *args) -{ - usbos_info_t *usbos_info = (usbos_info_t *) bus; - void *ret; - unsigned long flags; - - if (usbos_info == NULL) - return NULL; - - spin_lock_irqsave(&usbos_info->txlock, flags); - ret = cb(args); - spin_unlock_irqrestore(&usbos_info->txlock, flags); - - return ret; -} - -/** - * if an error condition was detected in this module, the higher DBUS layer (dbus_usb.c) has to - * be notified. - */ -int -dbus_usbos_errhandler(void *bus, int err) -{ - usbos_info_t *usbos_info = (usbos_info_t *) bus; - - if (usbos_info == NULL) - return DBUS_ERR; - - if (usbos_info->cbarg && usbos_info->cbs) { - if (usbos_info->cbs->errhandler) - usbos_info->cbs->errhandler(usbos_info->cbarg, err); - } - - return DBUS_OK; -} - -/** - * if a change in bus state was detected in this module, the higher DBUS layer (dbus_usb.c) has to - * be notified. - */ -int -dbus_usbos_state_change(void *bus, int state) -{ - usbos_info_t *usbos_info = (usbos_info_t *) bus; - - if (usbos_info == NULL) - return DBUS_ERR; - - if (usbos_info->cbarg && usbos_info->cbs) { - if (usbos_info->cbs->state_change) - usbos_info->cbs->state_change(usbos_info->cbarg, state); - } - - usbos_info->pub->busstate = state; - return DBUS_OK; -} - -int -dbus_bus_osl_register(int vid, int pid, probe_cb_t prcb, - disconnect_cb_t discb, void *prarg, dbus_intf_t **intf, void *param1, void *param2) -{ - bzero(&g_probe_info, sizeof(probe_info_t)); - - probe_cb = prcb; - disconnect_cb = discb; - probe_arg = prarg; - - devid_table[0].idVendor = vid; - devid_table[0].idProduct = pid; - - *intf = &dbus_usbos_intf; - - USB_REGISTER(); - - return DBUS_ERR_NODEVICE; -} - -int -dbus_bus_osl_deregister() -{ - g_probe_info.dereged = TRUE; - - DHD_MUTEX_LOCK(); - if (disconnect_cb && disc_arg && (g_probe_info.disc_cb_done == FALSE)) { - disconnect_cb(disc_arg); - disc_arg = NULL; - } - DHD_MUTEX_UNLOCK(); - - USB_DEREGISTER(); - - return DBUS_OK; -} - -void * -dbus_usbos_intf_attach(dbus_pub_t *pub, void *cbarg, dbus_intf_callbacks_t *cbs) -{ - usbos_info_t *usbos_info; - - if (g_probe_info.dldone == FALSE) { - DBUSERR(("%s: err device not downloaded!\n", __FUNCTION__)); - return NULL; - } - - /* Sanity check for BUS_INFO() */ - ASSERT(OFFSETOF(usbos_info_t, pub) == 0); - - usbos_info = MALLOC(pub->osh, sizeof(usbos_info_t)); - if (usbos_info == NULL) - return NULL; - - bzero(usbos_info, sizeof(usbos_info_t)); - - usbos_info->pub = pub; - usbos_info->cbarg = cbarg; - usbos_info->cbs = cbs; - - /* Needed for disconnect() */ - g_probe_info.usbos_info = usbos_info; - - /* Update USB Info */ - usbos_info->usb = g_probe_info.usb; - usbos_info->rx_pipe = g_probe_info.rx_pipe; - usbos_info->rx_pipe2 = g_probe_info.rx_pipe2; - usbos_info->tx_pipe = g_probe_info.tx_pipe; - usbos_info->intr_pipe = g_probe_info.intr_pipe; - usbos_info->intr_size = g_probe_info.intr_size; - usbos_info->interval = g_probe_info.interval; - usbos_info->pub->device_speed = g_probe_info.device_speed; - if (usbos_info->rx_pipe2) { - usbos_info->pub->attrib.has_2nd_bulk_in_ep = 1; - } else { - usbos_info->pub->attrib.has_2nd_bulk_in_ep = 0; - } - - if (usbos_info->tx_pipe) - usbos_info->maxps = usb_maxpacket(usbos_info->usb, - usbos_info->tx_pipe, usb_pipeout(usbos_info->tx_pipe)); - - INIT_LIST_HEAD(&usbos_info->req_rxfreeq); - INIT_LIST_HEAD(&usbos_info->req_txfreeq); - INIT_LIST_HEAD(&usbos_info->req_rxpostedq); - INIT_LIST_HEAD(&usbos_info->req_txpostedq); - spin_lock_init(&usbos_info->rxfree_lock); - spin_lock_init(&usbos_info->txfree_lock); - spin_lock_init(&usbos_info->rxposted_lock); - spin_lock_init(&usbos_info->txposted_lock); - spin_lock_init(&usbos_info->rxlock); - spin_lock_init(&usbos_info->txlock); - - atomic_set(&usbos_info->rxposted, 0); - atomic_set(&usbos_info->txposted, 0); - - -#ifdef USB_DISABLE_INT_EP - usbos_info->intr_urb = NULL; -#else - if (!(usbos_info->intr_urb = USB_ALLOC_URB())) { - DBUSERR(("%s: usb_alloc_urb (tx) failed\n", __FUNCTION__)); - goto fail; - } -#endif - - if (!(usbos_info->ctl_urb = USB_ALLOC_URB())) { - DBUSERR(("%s: usb_alloc_urb (tx) failed\n", __FUNCTION__)); - goto fail; - } - - init_waitqueue_head(&usbos_info->wait); - - if (!(usbos_info->blk_urb = USB_ALLOC_URB())) { /* for embedded image downloading */ - DBUSERR(("%s: usb_alloc_urb (tx) failed\n", __FUNCTION__)); - goto fail; - } - - usbos_info->rxbuf_len = (uint)usbos_info->pub->rxsize; - - - - atomic_set(&usbos_info->txallocated, 0); - if (DBUS_OK != dbus_usbos_urbreqs_alloc(usbos_info, - usbos_info->pub->ntxq, FALSE)) { - goto fail; - } - - atomic_set(&usbos_info->rxallocated, 0); - if (DBUS_OK != dbus_usbos_urbreqs_alloc(usbos_info, - MIN(DBUS_USB_RXQUEUE_BATCH_ADD, usbos_info->pub->nrxq), - TRUE)) { - goto fail; - } - - sema_init(&usbos_info->ctl_lock, 1); - -#ifdef USBOS_THREAD - if (dbus_usbos_thread_init(usbos_info) == NULL) - goto fail; -#endif /* USBOS_THREAD */ - -#ifdef USBOS_TX_THREAD - if (dbus_usbos_tx_thread_init(usbos_info) == NULL) - goto fail; -#endif /* USBOS_TX_THREAD */ - - pub->dev_info = g_probe_info.usb; - - - return (void *) usbos_info; -fail: - if (usbos_info->intr_urb) { - USB_FREE_URB(usbos_info->intr_urb); - usbos_info->intr_urb = NULL; - } - - if (usbos_info->ctl_urb) { - USB_FREE_URB(usbos_info->ctl_urb); - usbos_info->ctl_urb = NULL; - } - -#if defined(BCM_REQUEST_FW) - if (usbos_info->blk_urb) { - USB_FREE_URB(usbos_info->blk_urb); - usbos_info->blk_urb = NULL; - } -#endif - - dbus_usbos_urbreqs_free(usbos_info, TRUE); - atomic_set(&usbos_info->rxallocated, 0); - dbus_usbos_urbreqs_free(usbos_info, FALSE); - atomic_set(&usbos_info->txallocated, 0); - - g_probe_info.usbos_info = NULL; - - MFREE(pub->osh, usbos_info, sizeof(usbos_info_t)); - return NULL; -} /* dbus_usbos_intf_attach */ - -void -dbus_usbos_intf_detach(dbus_pub_t *pub, void *info) -{ - usbos_info_t *usbos_info = (usbos_info_t *) info; - osl_t *osh = pub->osh; - - if (usbos_info == NULL) { - return; - } - -#ifdef USBOS_TX_THREAD - dbus_usbos_tx_thread_deinit(usbos_info); -#endif /* USBOS_TX_THREAD */ - - /* Must unlink all URBs prior to driver unload; - * otherwise an URB callback can occur after driver - * has been de-allocated and rmmod'd - */ - dbusos_stop(usbos_info); - - if (usbos_info->intr_urb) { - USB_FREE_URB(usbos_info->intr_urb); - usbos_info->intr_urb = NULL; - } - - if (usbos_info->ctl_urb) { - USB_FREE_URB(usbos_info->ctl_urb); - usbos_info->ctl_urb = NULL; - } - - if (usbos_info->blk_urb) { - USB_FREE_URB(usbos_info->blk_urb); - usbos_info->blk_urb = NULL; - } - - dbus_usbos_urbreqs_free(usbos_info, TRUE); - atomic_set(&usbos_info->rxallocated, 0); - dbus_usbos_urbreqs_free(usbos_info, FALSE); - atomic_set(&usbos_info->txallocated, 0); - -#ifdef USBOS_THREAD - dbus_usbos_thread_deinit(usbos_info); -#endif /* USBOS_THREAD */ - - g_probe_info.usbos_info = NULL; - MFREE(osh, usbos_info, sizeof(usbos_info_t)); -} /* dbus_usbos_intf_detach */ - - -#ifdef USBOS_TX_THREAD - -void* -dbus_usbos_tx_thread_init(usbos_info_t *usbos_info) -{ - spin_lock_init(&usbos_info->usbos_tx_list_lock); - INIT_LIST_HEAD(&usbos_info->usbos_tx_list); - init_waitqueue_head(&usbos_info->usbos_tx_queue_head); - - usbos_info->usbos_tx_kt = kthread_create(dbus_usbos_tx_thread_func, - usbos_info, "usb-tx-thread"); - - if (IS_ERR(usbos_info->usbos_tx_kt)) { - DBUSERR(("Thread Creation failed\n")); - return (NULL); - } - - usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED; - wake_up_process(usbos_info->usbos_tx_kt); - - return (usbos_info->usbos_tx_kt); -} - -void -dbus_usbos_tx_thread_deinit(usbos_info_t *usbos_info) -{ - urb_req_t *req; - - if (usbos_info->usbos_tx_kt) { - wake_up_interruptible(&usbos_info->usbos_tx_queue_head); - kthread_stop(usbos_info->usbos_tx_kt); - } - - /* Move pending requests to free queue so they can be freed */ - while ((req = dbus_usbos_qdeq( - &usbos_info->usbos_tx_list, &usbos_info->usbos_tx_list_lock)) != NULL) { - dbus_usbos_qenq(&usbos_info->req_txfreeq, req, &usbos_info->txfree_lock); - } -} - -/** - * Allow USB in-band resume to block by submitting CTRL and DATA URBs on a separate thread. - */ -int -dbus_usbos_tx_thread_func(void *data) -{ - usbos_info_t *usbos_info = (usbos_info_t *)data; - urb_req_t *req; - dbus_irb_tx_t *txirb; - int ret; - unsigned long flags; - -#ifdef WL_THREADNICE - set_user_nice(current, WL_THREADNICE); -#endif - - while (1) { - /* Wait until there are URBs to submit */ - wait_event_interruptible_timeout( - usbos_info->usbos_tx_queue_head, - !list_empty(&usbos_info->usbos_tx_list) || - usbos_info->ctl_state == USBOS_REQUEST_STATE_SCHEDULED, - 100); - - if (kthread_should_stop()) - break; - - /* Submit CTRL URB if needed */ - if (usbos_info->ctl_state == USBOS_REQUEST_STATE_SCHEDULED) { - - /* Disable USB autosuspend until this request completes. If the - * interface was suspended, this call blocks until it has been resumed. - */ - USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); - - usbos_info->ctl_state = USBOS_REQUEST_STATE_SUBMITTED; - - ret = USB_SUBMIT_URB(usbos_info->ctl_urb); - if (ret != 0) { - DBUSERR(("%s CTRL USB_SUBMIT_URB failed, status %d\n", - __FUNCTION__, ret)); - - usbos_info->ctl_state = USBOS_REQUEST_STATE_UNSCHEDULED; - up(&usbos_info->ctl_lock); - - USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); - } - } - - /* Submit all available TX URBs */ - while ((req = dbus_usbos_qdeq(&usbos_info->usbos_tx_list, - &usbos_info->usbos_tx_list_lock)) != NULL) { - - /* Disable USB autosuspend until this request completes. If the - * interface was suspended, this call blocks until it has been resumed. - */ - USB_AUTOPM_GET_INTERFACE(g_probe_info.intf); - - spin_lock_irqsave(&usbos_info->txlock, flags); - - ret = USB_SUBMIT_URB(req->urb); - if (ret == 0) { - /* URB submitted successfully */ - dbus_usbos_qenq(&usbos_info->req_txpostedq, req, - &usbos_info->txposted_lock); - atomic_inc(&usbos_info->txposted); - } else { - /* Submitting the URB failed. */ - DBUSERR(("%s TX USB_SUBMIT_URB failed, status %d\n", - __FUNCTION__, ret)); - - USB_AUTOPM_PUT_INTERFACE_ASYNC(g_probe_info.intf); - } - - spin_unlock_irqrestore(&usbos_info->txlock, flags); - - if (ret != 0) { - /* Cleanup and notify higher layers */ - dbus_usbos_qenq(&usbos_info->req_txfreeq, req, - &usbos_info->txfree_lock); - - txirb = req->arg; - if (txirb->send_buf) { - MFREE(usbos_info->pub->osh, txirb->send_buf, req->buf_len); - txirb->send_buf = NULL; - req->buf_len = 0; - } - - if (likely (usbos_info->cbarg && usbos_info->cbs)) { - if (likely (usbos_info->cbs->send_irb_complete != NULL)) - usbos_info->cbs->send_irb_complete( - usbos_info->cbarg, txirb, DBUS_ERR_TXDROP); - } - } - } - } - - return 0; -} /* dbus_usbos_tx_thread_func */ - -#endif /* USBOS_TX_THREAD */ - -#ifdef USBOS_THREAD - -/** - * Increase system performance by creating a USB thread that runs parallel to other system - * activity. - */ -static void* -dbus_usbos_thread_init(usbos_info_t *usbos_info) -{ - usbos_list_entry_t *entry; - unsigned long flags, ii; - - spin_lock_init(&usbos_info->usbos_list_lock); - spin_lock_init(&usbos_info->ctrl_lock); - INIT_LIST_HEAD(&usbos_info->usbos_list); - INIT_LIST_HEAD(&usbos_info->usbos_free_list); - init_waitqueue_head(&usbos_info->usbos_queue_head); - atomic_set(&usbos_info->usbos_list_cnt, 0); - - - for (ii = 0; ii < (usbos_info->pub->nrxq + usbos_info->pub->ntxq); ii++) { - entry = MALLOC(usbos_info->pub->osh, sizeof(usbos_list_entry_t)); - if (entry) { - spin_lock_irqsave(&usbos_info->usbos_list_lock, flags); - list_add_tail((struct list_head*) entry, &usbos_info->usbos_free_list); - spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); - } else { - DBUSERR(("Failed to create list\n")); - } - } - - usbos_info->usbos_kt = kthread_create(dbus_usbos_thread_func, - usbos_info, "usb-thread"); - - if (IS_ERR(usbos_info->usbos_kt)) { - DBUSERR(("Thread Creation failed\n")); - return (NULL); - } - - wake_up_process(usbos_info->usbos_kt); - - return (usbos_info->usbos_kt); -} - -static void -dbus_usbos_thread_deinit(usbos_info_t *usbos_info) -{ - struct list_head *cur, *next; - usbos_list_entry_t *entry; - unsigned long flags; - - if (usbos_info->usbos_kt) { - wake_up_interruptible(&usbos_info->usbos_queue_head); - kthread_stop(usbos_info->usbos_kt); - } -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - list_for_each_safe(cur, next, &usbos_info->usbos_list) - { - entry = list_entry(cur, struct usbos_list_entry, list); - /* detach this entry from the list and then free the entry */ - spin_lock_irqsave(&usbos_info->usbos_list_lock, flags); - list_del(cur); - MFREE(usbos_info->pub->osh, entry, sizeof(usbos_list_entry_t)); - spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); - } - - list_for_each_safe(cur, next, &usbos_info->usbos_free_list) - { - entry = list_entry(cur, struct usbos_list_entry, list); - /* detach this entry from the list and then free the entry */ - spin_lock_irqsave(&usbos_info->usbos_list_lock, flags); - list_del(cur); - MFREE(usbos_info->pub->osh, entry, sizeof(usbos_list_entry_t)); - spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); - } -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif -} - -/** Process completed URBs in a worker thread */ -static int -dbus_usbos_thread_func(void *data) -{ - usbos_info_t *usbos_info = (usbos_info_t *)data; - usbos_list_entry_t *entry; - struct list_head *cur, *next; - unsigned long flags; - -#ifdef WL_THREADNICE - set_user_nice(current, WL_THREADNICE); -#endif - - while (1) { - /* If the list is empty, then go to sleep */ - wait_event_interruptible_timeout - (usbos_info->usbos_queue_head, - atomic_read(&usbos_info->usbos_list_cnt) > 0, - 100); - - if (kthread_should_stop()) - break; - - spin_lock_irqsave(&usbos_info->usbos_list_lock, flags); - - /* For each entry on the list, process it. Remove the entry from - * the list when done. - */ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - list_for_each_safe(cur, next, &usbos_info->usbos_list) - { - urb_req_t *req; - int len; - int stat; - usbos_info_t *usbos_info_local; - - entry = list_entry(cur, struct usbos_list_entry, list); - if (entry == NULL) - break; - - req = entry->urb_context; - len = entry->urb_length; - stat = entry->urb_status; - usbos_info_local = req->usbinfo; - - /* detach this entry from the list and attach it to the free list */ - list_del_init(cur); - spin_unlock_irqrestore(&usbos_info_local->usbos_list_lock, flags); - - dbus_usbos_recv_complete_handle(req, len, stat); - - spin_lock_irqsave(&usbos_info_local->usbos_list_lock, flags); - - list_add_tail(cur, &usbos_info_local->usbos_free_list); - - atomic_dec(&usbos_info_local->usbos_list_cnt); - } - - spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); - - } -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - - return 0; -} /* dbus_usbos_thread_func */ - -/** Called on Linux calling URB callback, see dbus_usbos_recv_complete() */ -static void -dbus_usbos_dispatch_schedule(CALLBACK_ARGS) -{ - urb_req_t *req = urb->context; - usbos_info_t *usbos_info = req->usbinfo; - usbos_list_entry_t *entry; - unsigned long flags; - struct list_head *cur; - - spin_lock_irqsave(&usbos_info->usbos_list_lock, flags); - - cur = usbos_info->usbos_free_list.next; -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - entry = list_entry(cur, struct usbos_list_entry, list); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - - /* detach this entry from the free list and prepare it insert it to use list */ - list_del_init(cur); - - if (entry) { - entry->urb_context = urb->context; - entry->urb_length = urb->actual_length; - entry->urb_status = urb->status; - - atomic_inc(&usbos_info->usbos_list_cnt); - list_add_tail(cur, &usbos_info->usbos_list); - } else { - DBUSERR(("!!!!!!OUT OF MEMORY!!!!!!!\n")); - } - - spin_unlock_irqrestore(&usbos_info->usbos_list_lock, flags); - - /* thread */ - wake_up_interruptible(&usbos_info->usbos_queue_head); -} /* dbus_usbos_dispatch_schedule */ - -#endif /* USBOS_THREAD */ - - - - -#ifdef BCM_REQUEST_FW - -struct request_fw_context { - const struct firmware *firmware; - struct semaphore lock; -}; - -/* - * Callback for dbus_request_firmware(). - */ -static void -dbus_request_firmware_done(const struct firmware *firmware, void *ctx) -{ - struct request_fw_context *context = (struct request_fw_context*)ctx; - - /* Store the received firmware handle in the context and wake requester */ - context->firmware = firmware; - up(&context->lock); -} - -/* - * Send a firmware request and wait for completion. - * - * The use of the asynchronous version of request_firmware() is needed to avoid - * kernel oopses when we just come out of system hibernate. - */ -static int -dbus_request_firmware(const char *name, const struct firmware **firmware) -{ - struct request_fw_context *context; - int ret; - - context = kzalloc(sizeof(*context), GFP_KERNEL); - if (!context) - return -ENOMEM; - - sema_init(&context->lock, 0); - - ret = request_firmware_nowait(THIS_MODULE, true, name, &g_probe_info.usb->dev, - GFP_KERNEL, context, dbus_request_firmware_done); - if (ret) { - kfree(context); - return ret; - } - - /* Wait for completion */ - if (down_interruptible(&context->lock) != 0) { - kfree(context); - return -ERESTARTSYS; - } - - *firmware = context->firmware; - kfree(context); - - return *firmware != NULL ? 0 : -ENOENT; -} - -static void * -dbus_get_fwfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype, uint16 boardrev) -{ - const struct firmware *firmware = NULL; -#ifndef OEM_ANDROID - s8 *device_id = NULL; - s8 *chip_rev = ""; -#endif /* OEM_ANDROID */ - s8 file_name[64]; - int ret; - -#ifndef OEM_ANDROID - switch (devid) { - case BCM4350_CHIP_ID: - case BCM4354_CHIP_ID: - case BCM43556_CHIP_ID: - case BCM43558_CHIP_ID: - case BCM43566_CHIP_ID: - case BCM43568_CHIP_ID: - case BCM43570_CHIP_ID: - case BCM4358_CHIP_ID: - device_id = "4350"; - break; - case BCM43143_CHIP_ID: - device_id = "43143"; - break; - case BCM43234_CHIP_ID: - case BCM43235_CHIP_ID: - case BCM43236_CHIP_ID: - device_id = "43236"; - break; - case BCM43242_CHIP_ID: - device_id = "43242"; - break; - case BCM43238_CHIP_ID: - device_id = "43238"; - break; - case BCM43526_CHIP_ID: - device_id = "43526"; - break; - case BCM43569_CHIP_ID: - device_id = "43569"; - switch (chiprev) { - case 0: - chip_rev = "a0"; - break; - case 2: - chip_rev = "a2"; - break; - default: - break; - } - break; - default: - DBUSERR(("unsupported device %x\n", devid)); - return NULL; - } - - /* Load firmware */ - snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s-firmware.bin", device_id, chip_rev); -#else - snprintf(file_name, sizeof(file_name), "%s", CONFIG_ANDROID_BCMDHD_FW_PATH); -#endif /* OEM_ANDROID */ - - ret = dbus_request_firmware(file_name, &firmware); - if (ret) { - DBUSERR(("fail to request firmware %s\n", file_name)); - return NULL; - } - - *fwlen = firmware->size; - *fw = (uint8 *)firmware->data; - return (void *)firmware; - -} - -static void * -dbus_get_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, uint16 boardtype, uint16 boardrev) -{ - const struct firmware *firmware = NULL; -#ifndef OEM_ANDROID - s8 *device_id = NULL; - s8 *chip_rev = ""; -#endif /* OEM_ANDROID */ - s8 file_name[64]; - int ret; - -#ifndef OEM_ANDROID - switch (devid) { - case BCM4350_CHIP_ID: - case BCM4354_CHIP_ID: - case BCM43556_CHIP_ID: - case BCM43558_CHIP_ID: - case BCM43566_CHIP_ID: - case BCM43568_CHIP_ID: - case BCM43570_CHIP_ID: - case BCM4358_CHIP_ID: - device_id = "4350"; - break; - case BCM43143_CHIP_ID: - device_id = "43143"; - break; - case BCM43234_CHIP_ID: - device_id = "43234"; - break; - case BCM43235_CHIP_ID: - device_id = "43235"; - break; - case BCM43236_CHIP_ID: - device_id = "43236"; - break; - case BCM43238_CHIP_ID: - device_id = "43238"; - break; - case BCM43242_CHIP_ID: - device_id = "43242"; - break; - case BCM43526_CHIP_ID: - device_id = "43526"; - break; - case BCM43569_CHIP_ID: - device_id = "43569"; - switch (chiprev) { - case 0: - chip_rev = "a0"; - break; - case 2: - chip_rev = "a2"; - break; - default: - break; - } - break; - default: - DBUSERR(("unsupported device %x\n", devid)); - return NULL; - } - - /* Load board specific nvram file */ - snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s-%2x-%2x.nvm", - device_id, chip_rev, boardtype, boardrev); -#else - snprintf(file_name, sizeof(file_name), "%s", CONFIG_ANDROID_BCMDHD_NVRAM_PATH); -#endif /* OEM_ANDROID */ - - ret = dbus_request_firmware(file_name, &firmware); - if (ret) { - DBUSERR(("fail to request nvram %s\n", file_name)); - -#ifndef OEM_ANDROID - /* Load generic nvram file */ - snprintf(file_name, sizeof(file_name), "brcm/bcm%s%s.nvm", - device_id, chip_rev); - - ret = dbus_request_firmware(file_name, &firmware); -#endif /* OEM_ANDROID */ - - if (ret) { - DBUSERR(("fail to request nvram %s\n", file_name)); - return NULL; - } - } - - *fwlen = firmware->size; - *fw = (uint8 *)firmware->data; - return (void *)firmware; -} - -void * -dbus_get_fw_nvfile(int devid, int chiprev, uint8 **fw, int *fwlen, int type, uint16 boardtype, - uint16 boardrev) -{ - switch (type) { - case DBUS_FIRMWARE: - return dbus_get_fwfile(devid, chiprev, fw, fwlen, boardtype, boardrev); - case DBUS_NVFILE: - return dbus_get_nvfile(devid, chiprev, fw, fwlen, boardtype, boardrev); - default: - return NULL; - } -} - -void -dbus_release_fw_nvfile(void *firmware) -{ - release_firmware((struct firmware *)firmware); -} -#endif /* BCM_REQUEST_FW */ - -#ifdef BCMUSBDEV_COMPOSITE -/** - * For a composite device the interface order is not guaranteed, scan the device struct for the WLAN - * interface. - */ -static int -dbus_usbos_intf_wlan(struct usb_device *usb) -{ - int i, num_of_eps, ep, intf_wlan = -1; - int num_intf = CONFIGDESC(usb)->bNumInterfaces; - struct usb_endpoint_descriptor *endpoint; - - for (i = 0; i < num_intf; i++) { - if (IFDESC(usb, i).bInterfaceClass != USB_CLASS_VENDOR_SPEC) - continue; - num_of_eps = IFDESC(usb, i).bNumEndpoints; - - for (ep = 0; ep < num_of_eps; ep++) { - endpoint = &IFEPDESC(usb, i, ep); - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_BULK) { - intf_wlan = i; - break; - } - } - if (ep < num_of_eps) - break; - } - - return intf_wlan; -} -#endif /* BCMUSBDEV_COMPOSITE */
diff --git a/bcmdhd.1.579.77.41.x/dhd.h b/bcmdhd.1.579.77.41.x/dhd.h deleted file mode 100644 index 3ec09fb..0000000 --- a/bcmdhd.1.579.77.41.x/dhd.h +++ /dev/null
@@ -1,2942 +0,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-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd.h 711448 2017-07-18 08:27:03Z $ - */ - -/**************** - * Common types * - */ - -#ifndef _dhd_h_ -#define _dhd_h_ - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/random.h> -#include <linux/spinlock.h> -#include <linux/ethtool.h> -#include <asm/uaccess.h> -#include <asm/unaligned.h> -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) -#include <linux/wakelock.h> -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) -#include <linux/sched/types.h> -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) */ -/* The kernel threading is sdio-specific */ -struct task_struct; -struct sched_param; -#if defined(BT_OVER_SDIO) -#include <dhd_bt_interface.h> -#endif /* defined (BT_OVER_SDIO) */ -int setScheduler(struct task_struct *p, int policy, struct sched_param *param); -int get_scheduler_policy(struct task_struct *p); -#define MAX_EVENT 16 - -#define ALL_INTERFACES 0xff - -#include <wlioctl.h> -#include <wlfc_proto.h> -#include <hnd_armtrap.h> -#if defined(DUMP_IOCTL_IOV_LIST) || defined(DHD_DEBUG) -#include <bcmutils.h> -#endif /* DUMP_IOCTL_IOV_LIST || DHD_DEBUG */ -#include <hnd_pktq.h> - -#if defined(BCMWDF) -#include <wdf.h> -#include <WdfMiniport.h> -#endif /* (BCMWDF) */ - -#ifdef BCOL_TCPKA_SYNC -#include <dhd_bcol_tcpka.h> -#endif /* BCOL_TCPKA_SYNC */ - -#ifdef DEBUG_DPC_THREAD_WATCHDOG -#define MAX_RESCHED_CNT 600 -#endif /* DEBUG_DPC_THREAD_WATCHDOG */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) && LINUX_VERSION_CODE < \ - KERNEL_VERSION(3, 18, 0) || defined(CONFIG_BCMDHD_VENDOR_EXT)) -#define WL_VENDOR_EXT_SUPPORT -#endif /* 3.18 > KERNEL_VER >= 3.14 || defined(CONFIG_BCMDHD_VENDOR_EXT) */ - -#if defined(KEEP_ALIVE) -/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ -#define KEEP_ALIVE_PERIOD 55000 -#define NULL_PKT_STR "null_pkt" -#endif /* KEEP_ALIVE */ - -/* Forward decls */ -struct dhd_bus; -struct dhd_prot; -struct dhd_info; -struct dhd_ioctl; -struct dhd_dbg; -struct dhd_ts; - -/* The level of bus communication with the dongle */ -enum dhd_bus_state { - DHD_BUS_DOWN, /* Not ready for frame transfers */ - DHD_BUS_LOAD, /* Download access only (CPU reset) */ - DHD_BUS_DATA, /* Ready for frame transfers */ - DHD_BUS_SUSPEND, /* Bus has been suspended */ - DHD_BUS_DOWN_IN_PROGRESS, /* Bus going Down */ - DHD_BUS_REMOVE, /* Bus has been removed */ -}; - -/* - * Bit fields to Indicate clean up process that wait till they are finished. - * Future synchronizable processes can add their bit filed below and update - * their functionalities accordingly - */ -#define DHD_BUS_BUSY_IN_TX 0x01 -#define DHD_BUS_BUSY_IN_SEND_PKT 0x02 -#define DHD_BUS_BUSY_IN_DPC 0x04 -#define DHD_BUS_BUSY_IN_WD 0x08 -#define DHD_BUS_BUSY_IN_IOVAR 0x10 -#define DHD_BUS_BUSY_IN_DHD_IOVAR 0x20 -#define DHD_BUS_BUSY_SUSPEND_IN_PROGRESS 0x40 -#define DHD_BUS_BUSY_RESUME_IN_PROGRESS 0x80 -#define DHD_BUS_BUSY_RPM_SUSPEND_IN_PROGRESS 0x100 -#define DHD_BUS_BUSY_RPM_SUSPEND_DONE 0x200 -#define DHD_BUS_BUSY_RPM_RESUME_IN_PROGRESS 0x400 -#define DHD_BUS_BUSY_RPM_ALL (DHD_BUS_BUSY_RPM_SUSPEND_DONE | \ - DHD_BUS_BUSY_RPM_SUSPEND_IN_PROGRESS | \ - DHD_BUS_BUSY_RPM_RESUME_IN_PROGRESS) -#define DHD_BUS_BUSY_IN_CHECKDIED 0x800 - -#define DHD_BUS_BUSY_SET_IN_TX(dhdp) \ - (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_TX -#define DHD_BUS_BUSY_SET_IN_SEND_PKT(dhdp) \ - (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_SEND_PKT -#define DHD_BUS_BUSY_SET_IN_DPC(dhdp) \ - (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_DPC -#define DHD_BUS_BUSY_SET_IN_WD(dhdp) \ - (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_WD -#define DHD_BUS_BUSY_SET_IN_IOVAR(dhdp) \ - (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_IOVAR -#define DHD_BUS_BUSY_SET_IN_DHD_IOVAR(dhdp) \ - (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_DHD_IOVAR -#define DHD_BUS_BUSY_SET_SUSPEND_IN_PROGRESS(dhdp) \ - (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_SUSPEND_IN_PROGRESS -#define DHD_BUS_BUSY_SET_RESUME_IN_PROGRESS(dhdp) \ - (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_RESUME_IN_PROGRESS -#define DHD_BUS_BUSY_SET_RPM_SUSPEND_IN_PROGRESS(dhdp) \ - (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_RPM_SUSPEND_IN_PROGRESS -#define DHD_BUS_BUSY_SET_RPM_SUSPEND_DONE(dhdp) \ - (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_RPM_SUSPEND_DONE -#define DHD_BUS_BUSY_SET_RPM_RESUME_IN_PROGRESS(dhdp) \ - (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_RPM_RESUME_IN_PROGRESS -#define DHD_BUS_BUSY_SET_IN_CHECKDIED(dhdp) \ - (dhdp)->dhd_bus_busy_state |= DHD_BUS_BUSY_IN_CHECKDIED - -#define DHD_BUS_BUSY_CLEAR_IN_TX(dhdp) \ - (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_TX -#define DHD_BUS_BUSY_CLEAR_IN_SEND_PKT(dhdp) \ - (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_SEND_PKT -#define DHD_BUS_BUSY_CLEAR_IN_DPC(dhdp) \ - (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_DPC -#define DHD_BUS_BUSY_CLEAR_IN_WD(dhdp) \ - (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_WD -#define DHD_BUS_BUSY_CLEAR_IN_IOVAR(dhdp) \ - (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_IOVAR -#define DHD_BUS_BUSY_CLEAR_IN_DHD_IOVAR(dhdp) \ - (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_DHD_IOVAR -#define DHD_BUS_BUSY_CLEAR_SUSPEND_IN_PROGRESS(dhdp) \ - (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_SUSPEND_IN_PROGRESS -#define DHD_BUS_BUSY_CLEAR_RESUME_IN_PROGRESS(dhdp) \ - (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_RESUME_IN_PROGRESS -#define DHD_BUS_BUSY_CLEAR_RPM_SUSPEND_IN_PROGRESS(dhdp) \ - (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_RPM_SUSPEND_IN_PROGRESS -#define DHD_BUS_BUSY_CLEAR_RPM_SUSPEND_DONE(dhdp) \ - (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_RPM_SUSPEND_DONE -#define DHD_BUS_BUSY_CLEAR_RPM_RESUME_IN_PROGRESS(dhdp) \ - (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_RPM_RESUME_IN_PROGRESS -#define DHD_BUS_BUSY_CLEAR_IN_CHECKDIED(dhdp) \ - (dhdp)->dhd_bus_busy_state &= ~DHD_BUS_BUSY_IN_CHECKDIED - -#define DHD_BUS_BUSY_CHECK_IN_TX(dhdp) \ - ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_TX) -#define DHD_BUS_BUSY_CHECK_IN_SEND_PKT(dhdp) \ - ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_SEND_PKT) -#define DHD_BUS_BUSY_CHECK_IN_DPC(dhdp) \ - ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_DPC) -#define DHD_BUS_BUSY_CHECK_IN_WD(dhdp) \ - ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_WD) -#define DHD_BUS_BUSY_CHECK_IN_IOVAR(dhdp) \ - ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_IOVAR) -#define DHD_BUS_BUSY_CHECK_IN_DHD_IOVAR(dhdp) \ - ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_DHD_IOVAR) -#define DHD_BUS_BUSY_CHECK_SUSPEND_IN_PROGRESS(dhdp) \ - ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_SUSPEND_IN_PROGRESS) -#define DHD_BUS_BUSY_CHECK_RESUME_IN_PROGRESS(dhdp) \ - ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_RESUME_IN_PROGRESS) -#define DHD_BUS_BUSY_CHECK_RPM_SUSPEND_IN_PROGRESS(dhdp) \ - ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_RPM_SUSPEND_IN_PROGRESS) -#define DHD_BUS_BUSY_CHECK_RPM_SUSPEND_DONE(dhdp) \ - ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_RPM_SUSPEND_DONE) -#define DHD_BUS_BUSY_CHECK_RPM_RESUME_IN_PROGRESS(dhdp) \ - ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_RPM_RESUME_IN_PROGRESS) -#define DHD_BUS_BUSY_CHECK_RPM_ALL(dhdp) \ - ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_RPM_ALL) -#define DHD_BUS_BUSY_CHECK_IN_CHECKDIED(dhdp) \ - ((dhdp)->dhd_bus_busy_state & DHD_BUS_BUSY_IN_CHECKDIED) -#define DHD_BUS_BUSY_CHECK_IDLE(dhdp) \ - ((dhdp)->dhd_bus_busy_state == 0) - -#define DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhdp) \ - ((dhdp)->busstate == DHD_BUS_SUSPEND || DHD_BUS_BUSY_CHECK_SUSPEND_IN_PROGRESS(dhdp) || \ - DHD_BUS_BUSY_CHECK_RPM_SUSPEND_IN_PROGRESS(dhdp)) - -#define DHD_BUS_CHECK_ANY_SUSPEND_IN_PROGRESS(dhdp) \ - (DHD_BUS_BUSY_CHECK_SUSPEND_IN_PROGRESS(dhdp) || \ - DHD_BUS_BUSY_CHECK_RPM_SUSPEND_IN_PROGRESS(dhdp)) - -#define DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp) \ - ((dhdp)->busstate == DHD_BUS_DOWN || (dhdp)->busstate == DHD_BUS_DOWN_IN_PROGRESS || \ - (dhdp)->busstate == DHD_BUS_REMOVE) - -#define DHD_BUS_CHECK_REMOVE(dhdp) \ - ((dhdp)->busstate == DHD_BUS_REMOVE) - -/* Macro to print Ethernet Address as String - * expects both arguements as (char *) - */ -#ifdef SIMPLE_MAC_PRINT -#define DHD_MAC_TO_STR(mac, str) (snprintf(str, ETHER_ADDR_STR_LEN, \ - "%02x:XX:XX:XX:%02x:%02x\n", \ - (uchar)mac[0]&0xff, \ - (uchar)mac[4]&0xff, \ - (uchar)mac[5]&0xff)) -#else -#define DHD_MAC_TO_STR(mac, str) (snprintf(str, ETHER_ADDR_STR_LEN, \ - "%02x:%02x:%02x:%02x:%02x:%02x\n", \ - (uchar)mac[0]&0xff, \ - (uchar)mac[1]&0xff, \ - (uchar)mac[2]&0xff, \ - (uchar)mac[3]&0xff, \ - (uchar)mac[4]&0xff, \ - (uchar)mac[5]&0xff)) -#endif /* SIMPLE_MAC_PRINT */ - - -/* Download Types */ -typedef enum download_type { - FW, - NVRAM, - CLM_BLOB -} download_type_t; - - -/* For supporting multiple interfaces */ -#define DHD_MAX_IFS 16 -#define DHD_DEL_IF -0xE -#define DHD_BAD_IF -0xF -#define DHD_EVENT_IF 0xFFFF /* Hack i/f to handle events from INFO Ring */ - -enum dhd_op_flags { -/* Firmware requested operation mode */ - DHD_FLAG_STA_MODE = (1 << (0)), /* STA only */ - DHD_FLAG_HOSTAP_MODE = (1 << (1)), /* SOFTAP only */ - DHD_FLAG_P2P_MODE = (1 << (2)), /* P2P Only */ - /* STA + P2P */ - DHD_FLAG_CONCURR_SINGLE_CHAN_MODE = (DHD_FLAG_STA_MODE | DHD_FLAG_P2P_MODE), - /* STA + SoftAP */ - DHD_FLAG_CONCURR_STA_HOSTAP_MODE = (DHD_FLAG_STA_MODE | DHD_FLAG_HOSTAP_MODE), - DHD_FLAG_CONCURR_MULTI_CHAN_MODE = (1 << (4)), /* STA + P2P */ - /* Current P2P mode for P2P connection */ - DHD_FLAG_P2P_GC_MODE = (1 << (5)), - DHD_FLAG_P2P_GO_MODE = (1 << (6)), - DHD_FLAG_MBSS_MODE = (1 << (7)), /* MBSS in future */ - DHD_FLAG_IBSS_MODE = (1 << (8)), - DHD_FLAG_MFG_MODE = (1 << (9)), - DHD_FLAG_RSDB_MODE = (1 << (10)), - DHD_FLAG_MP2P_MODE = (1 << (11)) -}; - -#define DHD_OPMODE_SUPPORTED(dhd, opmode_flag) \ - (dhd ? ((((dhd_pub_t *)dhd)->op_mode) & opmode_flag) : -1) - -/* Max sequential TX/RX Control timeouts to set HANG event */ -#ifndef MAX_CNTL_TX_TIMEOUT -#define MAX_CNTL_TX_TIMEOUT 2 -#endif /* MAX_CNTL_TX_TIMEOUT */ -#ifndef MAX_CNTL_RX_TIMEOUT -#define MAX_CNTL_RX_TIMEOUT 1 -#endif /* MAX_CNTL_RX_TIMEOUT */ - -#define DHD_SCAN_ASSOC_ACTIVE_TIME 40 /* ms: Embedded default Active setting from DHD */ -#define DHD_SCAN_UNASSOC_ACTIVE_TIME 80 /* ms: Embedded def. Unassoc Active setting from DHD */ -#define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD */ -#define DHD_SCAN_HOME_TIME 45 /* ms: Embedded default Home time setting from DHD */ -#define DHD_SCAN_HOME_AWAY_TIME 100 /* ms: Embedded default Home Away time setting from DHD */ - -#ifndef POWERUP_MAX_RETRY -#define POWERUP_MAX_RETRY 3 /* how many times we retry to power up the chip */ -#endif -#ifndef POWERUP_WAIT_MS -#define POWERUP_WAIT_MS 2000 /* ms: time out in waiting wifi to come up */ -#endif -/* - * MAX_NVRAMBUF_SIZE determines the size of the Buffer in the DHD that holds - * the NVRAM data. That is the size of the buffer pointed by bus->vars - * This also needs to be increased to 16K to support NVRAM size higher than 8K - */ -#define MAX_NVRAMBUF_SIZE (16 * 1024) /* max nvram buf size */ -#define MAX_CLM_BUF_SIZE (48 * 1024) /* max clm blob size */ -#ifdef DHD_DEBUG -#define DHD_JOIN_MAX_TIME_DEFAULT 10000 /* ms: Max time out for joining AP */ -#define DHD_SCAN_DEF_TIMEOUT 10000 /* ms: Max time out for scan in progress */ -#endif - -#ifndef CONFIG_BCMDHD_CLM_PATH -#define CONFIG_BCMDHD_CLM_PATH "/system/etc/wifi/bcmdhd_clm.blob" -#endif /* CONFIG_BCMDHD_CLM_PATH */ -#define WL_CCODE_NULL_COUNTRY "#n" - -#define FW_VER_STR_LEN 128 -#define CLM_VER_STR_LEN 128 -#define BUS_API_REV_STR_LEN 128 -extern char bus_api_revision[]; - -enum dhd_bus_wake_state { - WAKE_LOCK_OFF, - WAKE_LOCK_PRIV, - WAKE_LOCK_DPC, - WAKE_LOCK_IOCTL, - WAKE_LOCK_DOWNLOAD, - WAKE_LOCK_TMOUT, - WAKE_LOCK_WATCHDOG, - WAKE_LOCK_LINK_DOWN_TMOUT, - WAKE_LOCK_PNO_FIND_TMOUT, - WAKE_LOCK_SOFTAP_SET, - WAKE_LOCK_SOFTAP_STOP, - WAKE_LOCK_SOFTAP_START, - WAKE_LOCK_SOFTAP_THREAD -}; - -#ifdef PCIE_INB_DW -enum dhd_bus_ds_state { - DW_DEVICE_DS_INVALID = -1, - DW_DEVICE_DS_DEV_SLEEP = 0, - DW_DEVICE_DS_DEV_SLEEP_PEND, - DW_DEVICE_DS_DISABLED_WAIT, - DW_DEVICE_DS_DEV_WAKE, - DW_DEVICE_DS_ACTIVE, - DW_DEVICE_HOST_SLEEP_WAIT, - DW_DEVICE_HOST_SLEEP, - DW_DEVICE_HOST_WAKE_WAIT, - DW_DEVICE_DS_D3_INFORM_WAIT -}; -#endif /* PCIE_INB_DW */ - -enum dhd_prealloc_index { - DHD_PREALLOC_PROT = 0, - DHD_PREALLOC_RXBUF, - DHD_PREALLOC_DATABUF, - DHD_PREALLOC_OSL_BUF, -#if defined(STATIC_WL_PRIV_STRUCT) - DHD_PREALLOC_WIPHY_ESCAN0 = 5, -#endif /* STATIC_WL_PRIV_STRUCT */ - DHD_PREALLOC_DHD_INFO = 7, - DHD_PREALLOC_DHD_WLFC_INFO = 8, - DHD_PREALLOC_IF_FLOW_LKUP = 9, - /* 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_INFO = 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 -}; - -enum dhd_dongledump_mode { - DUMP_DISABLED = 0, - DUMP_MEMONLY, - DUMP_MEMFILE, - DUMP_MEMFILE_BUGON, - DUMP_MEMFILE_MAX -}; - -enum dhd_dongledump_type { - DUMP_TYPE_RESUMED_ON_TIMEOUT = 1, - DUMP_TYPE_D3_ACK_TIMEOUT, - DUMP_TYPE_DONGLE_TRAP, - DUMP_TYPE_MEMORY_CORRUPTION, - DUMP_TYPE_PKTID_AUDIT_FAILURE, - DUMP_TYPE_PKTID_INVALID, - DUMP_TYPE_SCAN_TIMEOUT, - DUMP_TYPE_JOIN_TIMEOUT, - DUMP_TYPE_SCAN_BUSY, - DUMP_TYPE_BY_SYSDUMP, - DUMP_TYPE_BY_LIVELOCK, - DUMP_TYPE_AP_LINKUP_FAILURE, - DUMP_TYPE_AP_ABNORMAL_ACCESS, - DUMP_TYPE_CFG_VENDOR_TRIGGERED, - DUMP_TYPE_RESUMED_ON_TIMEOUT_TX, - DUMP_TYPE_RESUMED_ON_TIMEOUT_RX, - DUMP_TYPE_RESUMED_ON_INVALID_RING_RDWR, - DUMP_TYPE_DONGLE_HOST_EVENT, - DUMP_TYPE_RESUMED_UNKNOWN, - DUMP_TYPE_TRANS_ID_MISMATCH, - DUMP_TYPE_HANG_ON_IFACE_OP_FAIL, -#ifdef SUPPORT_LINKDOWN_RECOVERY - DUMP_TYPE_READ_SHM_FAIL -#endif /* SUPPORT_LINKDOWN_RECOVERY */ -}; - -enum dhd_hang_reason { - HANG_REASON_MASK = 0x8000, - HANG_REASON_IOCTL_RESP_TIMEOUT = 0x8001, - HANG_REASON_DONGLE_TRAP = 0x8002, - HANG_REASON_D3_ACK_TIMEOUT = 0x8003, - HANG_REASON_BUS_DOWN = 0x8004, - HANG_REASON_MSGBUF_LIVELOCK = 0x8006, - HANG_REASON_IFACE_OP_FAILURE = 0x8007, - HANG_REASON_HT_AVAIL_ERROR = 0x8008, - HANG_REASON_PCIE_RC_LINK_UP_FAIL = 0x8009, - HANG_REASON_PCIE_PKTID_ERROR = 0x800A, - HANG_REASON_PCIE_LINK_DOWN = 0x8805, - HANG_REASON_INVALID_EVENT_OR_DATA = 0x8806, - HANG_REASON_UNKNOWN = 0x8807, - HANG_REASON_MAX = 0x8808 -}; - -enum dhd_rsdb_scan_features { - /* Downgraded scan feature for AP active */ - RSDB_SCAN_DOWNGRADED_AP_SCAN = 0x01, - /* Downgraded scan feature for P2P Discovery */ - RSDB_SCAN_DOWNGRADED_P2P_DISC_SCAN = 0x02, - /* Enable channel pruning for ROAM SCAN */ - RSDB_SCAN_DOWNGRADED_CH_PRUNE_ROAM = 0x10, - /* Enable channel pruning for any SCAN */ - RSDB_SCAN_DOWNGRADED_CH_PRUNE_ALL = 0x20 -}; - -/* Packet alignment for most efficient SDIO (can change based on platform) */ -#ifndef DHD_SDALIGN -#ifdef CUSTOM_SDIO_F2_BLKSIZE -#define DHD_SDALIGN CUSTOM_SDIO_F2_BLKSIZE -#else -#define DHD_SDALIGN 32 -#endif -#endif - -/** - * DMA-able buffer parameters - * - dmaaddr_t is 32bits on a 32bit host. - * dhd_dma_buf::pa may not be used as a sh_addr_t, bcm_addr64_t or uintptr - * - dhd_dma_buf::_alloced is ONLY for freeing a DMA-able buffer. - */ -typedef struct dhd_dma_buf { - void *va; /* virtual address of buffer */ - uint32 len; /* user requested buffer length */ - dmaaddr_t pa; /* physical address of buffer */ - void *dmah; /* dma mapper handle */ - void *secdma; /* secure dma sec_cma_info handle */ - uint32 _alloced; /* actual size of buffer allocated with align and pad */ -} dhd_dma_buf_t; - -/* host reordering packts logic */ -/* followed the structure to hold the reorder buffers (void **p) */ -typedef struct reorder_info { - void **p; - uint8 flow_id; - uint8 cur_idx; - uint8 exp_idx; - uint8 max_idx; - uint8 pend_pkts; -} reorder_info_t; - -#ifdef DHDTCPACK_SUPPRESS - -enum { - /* TCPACK suppress off */ - TCPACK_SUP_OFF, - /* Replace TCPACK in txq when new coming one has higher ACK number. */ - TCPACK_SUP_REPLACE, - /* TCPACK_SUP_REPLACE + delayed TCPACK TX unless ACK to PSH DATA. - * This will give benefits to Half-Duplex bus interface(e.g. SDIO) that - * 1. we are able to read TCP DATA packets first from the bus - * 2. TCPACKs that don't need to hurry delivered remains longer in TXQ so can be suppressed. - */ - TCPACK_SUP_DELAYTX, - TCPACK_SUP_HOLD, - TCPACK_SUP_LAST_MODE -}; - -#ifdef BCMSDIO -#define TCPACK_SUP_DEFAULT TCPACK_SUP_DELAYTX -#elif defined(BCMPCIE) -#define TCPACK_SUP_DEFAULT TCPACK_SUP_HOLD -#else -#define TCPACK_SUP_DEFAULT TCPACK_SUP_OFF -#endif /* BCMSDIO */ -#endif /* DHDTCPACK_SUPPRESS */ - -#if defined(TRAFFIC_MGMT_DWM) -#define DHD_DWM_TBL_SIZE 57 -/* DSCP WMM AC Mapping macros and structures */ -#define DHD_TRF_MGMT_DWM_FILTER_BIT 0x8 -#define DHD_TRF_MGMT_DWM_PRIO_BITS 0x7 -#define DHD_TRF_MGMT_DWM_FAVORED_BIT 0x10 -#define DHD_TRF_MGMT_DWM_PRIO(dwm_tbl_entry) ((dwm_tbl_entry) & DHD_TRF_MGMT_DWM_PRIO_BITS) -#define DHD_TRF_MGMT_DWM_IS_FAVORED_SET(dwm_tbl_entry) \ - ((dwm_tbl_entry) & DHD_TRF_MGMT_DWM_FAVORED_BIT) -#define DHD_TRF_MGMT_DWM_SET_FAVORED(dwm_tbl_entry) \ - ((dwm_tbl_entry) |= DHD_TRF_MGMT_DWM_FAVORED_BIT) -#define DHD_TRF_MGMT_DWM_IS_FILTER_SET(dwm_tbl_entry) \ - ((dwm_tbl_entry) & DHD_TRF_MGMT_DWM_FILTER_BIT) -#define DHD_TRF_MGMT_DWM_SET_FILTER(dwm_tbl_entry) \ - ((dwm_tbl_entry) |= DHD_TRF_MGMT_DWM_FILTER_BIT) - -typedef struct { - uint8 dhd_dwm_enabled; - uint8 dhd_dwm_tbl[DHD_DWM_TBL_SIZE]; -} dhd_trf_mgmt_dwm_tbl_t; -#endif - -#define DHD_NULL_CHK_AND_RET(cond) \ - if (!cond) { \ - DHD_ERROR(("%s " #cond " is NULL\n", __FUNCTION__)); \ - return; \ - } - -#define DHD_NULL_CHK_AND_RET_VAL(cond, value) \ - if (!cond) { \ - DHD_ERROR(("%s " #cond " is NULL\n", __FUNCTION__)); \ - return value; \ - } - -#define DHD_NULL_CHK_AND_GOTO(cond, label) \ - if (!cond) { \ - DHD_ERROR(("%s " #cond " is NULL\n", __FUNCTION__)); \ - goto label; \ - } - -/* - * Accumulating the queue lengths of all flowring queues in a parent object, - * to assert flow control, when the cummulative queue length crosses an upper - * threshold defined on a parent object. Upper threshold may be maintained - * at a station level, at an interface level, or at a dhd instance. - * - * cumm_ctr_t abstraction: - * cumm_ctr_t abstraction may be enhanced to use an object with a hysterisis - * pause on/off threshold callback. - * All macros use the address of the cummulative length in the parent objects. - * - * BCM_GMAC3 builds use a single perimeter lock, as opposed to a per queue lock. - * Cummulative counters in parent objects may be updated without spinlocks. - * - * In non BCM_GMAC3, if a cummulative queue length is desired across all flows - * belonging to either of (a station, or an interface or a dhd instance), then - * an atomic operation is required using an atomic_t cummulative counters or - * using a spinlock. BCM_ROUTER_DHD uses the Linux atomic_t construct. - */ - -/* Cummulative length not supported. */ -typedef uint32 cumm_ctr_t; -#define DHD_CUMM_CTR_PTR(clen) ((cumm_ctr_t*)(clen)) -#define DHD_CUMM_CTR(clen) *(DHD_CUMM_CTR_PTR(clen)) /* accessor */ -#define DHD_CUMM_CTR_READ(clen) DHD_CUMM_CTR(clen) /* read access */ -#define DHD_CUMM_CTR_INIT(clen) \ - ASSERT(DHD_CUMM_CTR_PTR(clen) != DHD_CUMM_CTR_PTR(NULL)); -#define DHD_CUMM_CTR_INCR(clen) \ - ASSERT(DHD_CUMM_CTR_PTR(clen) != DHD_CUMM_CTR_PTR(NULL)); -#define DHD_CUMM_CTR_DECR(clen) \ - ASSERT(DHD_CUMM_CTR_PTR(clen) != DHD_CUMM_CTR_PTR(NULL)); - -#if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) -struct tdls_peer_node { - uint8 addr[ETHER_ADDR_LEN]; - struct tdls_peer_node *next; -}; -typedef struct tdls_peer_node tdls_peer_node_t; -typedef struct { - tdls_peer_node_t *node; - uint8 tdls_peer_count; -} tdls_peer_tbl_t; -#endif /* defined(WLTDLS) && defined(PCIE_FULL_DONGLE) */ - -#ifdef DHD_LOG_DUMP -/* below structure describe ring buffer. */ -struct dhd_log_dump_buf -{ - spinlock_t lock; - unsigned int enable; - unsigned int wraparound; - unsigned long max; - unsigned int remain; - char* present; - char* front; - char* buffer; -}; - -#define DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE 256 -extern void dhd_log_dump_write(int type, const char *fmt, ...); -extern char *dhd_log_dump_get_timestamp(void); -#endif /* DHD_LOG_DUMP */ - -#if defined(CUSTOMER_HW2) -#define DHD_COMMON_DUMP_PATH "/data/misc/wifi/" -#else -#define DHD_COMMON_DUMP_PATH "/installmedia/" -#endif - -#ifdef UART_HB_CONFIG -#define WOWL_ALIVE_HB 0x01 -#define WOWL_ALIVE_UART 0x10 -#endif /* UART_HB_CONFIG */ - -struct cntry_locales_custom { - char iso_abbrev[WLC_CNTRY_BUF_SZ]; /* ISO 3166-1 country abbreviation */ - char custom_locale[WLC_CNTRY_BUF_SZ]; /* Custom firmware locale */ - int32 custom_locale_rev; /* Custom local revisin default -1 */ -}; - -#ifdef REPORT_FATAL_TIMEOUTS -typedef struct timeout_info { - void *scan_timer_lock; - void *join_timer_lock; - void *cmd_timer_lock; - void *bus_timer_lock; - uint32 scan_timeout_val; - uint32 join_timeout_val; - uint32 cmd_timeout_val; - uint32 bus_timeout_val; - bool scan_timer_active; - bool join_timer_active; - bool cmd_timer_active; - bool bus_timer_active; - osl_timer_t *scan_timer; - osl_timer_t *join_timer; - osl_timer_t *cmd_timer; - osl_timer_t *bus_timer; - uint16 cmd_request_id; - uint32 cmd; - uint32 cmd_join_error; -} timeout_info_t; -#endif /* REPORT_FATAL_TIMEOUTS */ - -#ifdef HOFFLOAD_MODULES -/* Metadata structure containing module information */ -struct module_metadata { - void *data; /* module data */ - uint32_t size; /* module size */ - u64 data_addr; /* address of module data in host */ -}; -#endif - -#ifdef DMAMAP_STATS -typedef struct dmamap_stats { - uint64 txdata; - uint64 txdata_sz; - uint64 rxdata; - uint64 rxdata_sz; - uint64 ioctl_rx; - uint64 ioctl_rx_sz; - uint64 event_rx; - uint64 event_rx_sz; - uint64 info_rx; - uint64 info_rx_sz; - uint64 tsbuf_rx; - uint64 tsbuf_rx_sz; -} dma_stats_t; -#endif /* DMAMAP_STATS */ - -#ifdef IDSUP_STATS -typedef enum { - EVT_CONNECTED, - EVT_DISCONNECTED, - EVT_SCAN_STARTED, - EVT_SCAN_RESULTS, - EVT_DISASSOC, - EVT_RESET, - EVT_REGDOM_CHANGE, - EVT_DHCPC, - EVT_ONLINE_CHECK, - EVT_TIMEOUT, - EVT_WAKE_PENDING, - EVT_SLAAC, - EVT_RECOVER -} wifi_event_t; - -typedef enum { - WIFI_WPA_STATE_UNKNOWN, - WIFI_WPA_STATE_DISCONNECTED, - WIFI_WPA_STATE_INTERFACE_DISABLED, - WIFI_WPA_STATE_INACTIVE, - WIFI_WPA_STATE_SCANNING, - WIFI_WPA_STATE_AUTHENTICATING, - WIFI_WPA_STATE_ASSOCIATING, - WIFI_WPA_STATE_ASSOCIATED, - WIFI_WPA_STATE_4WAY_HANDSHAKE, - WIFI_WPA_STATE_GROUP_HANDSHAKE, - WIFI_WPA_STATE_COMPLETED -} wifi_wpa_state_t; - -enum dhd_status { - DHD_STATUS_RECOVERED, - DHD_STATUS_HANGED, -}; -#endif /* IDSUP_STATS */ - -#ifdef WIFI_STATS -#define TCPKA_SESSION_NUM 1 -#define MKEEP_ALIVE_NUM 5 -#define PKT_FILTER_MAX_NUM 5 -#define VS_IE_MAX_NUM 10 -#define AP_INFO_SLOT_MAX 10 - -typedef struct { - uint32 oui; - uint32 type; -} vs_oui_t; - -typedef struct { - char ssid[DOT11_MAX_SSID_LEN]; - uint8 ssid_len; - uint8 flag; /* ap_info_flag: indicate connect/disconnect/both */ - struct ether_addr bssid; - uint16 channel; - int8 rssi_max; - int8 rssi_min; - uint32 wsec; - uint32 wpa_auth; - uint32 bi_us; - uint8 dtim_period; - uint8 disconnect_reason; /* ap_disconnect_reason: */ - bool connect_in_sleep; - bool disconnect_in_sleep; - uint32 brand; - uint32 vendor; -} wifi_stats_ap_info_t; - -typedef struct { - uint32 rx_beacon; /* total beacons on this AP */ - uint32 lost_beacon; /* total lost beacons on this AP */ - uint32 awake_cnt; /* total count when STA was forced awake to trace beacon */ - uint32 duration; /* total time on this AP */ - uint32 connect_time; /* connect epoch time */ - uint32 disconnect_time; /* disconnect epoch time */ -} wifi_stats_ap_info_v2_t; - -typedef struct { - uint8 tx_enable; - uint32 src_ip; - uint32 dst_ip; - uint16 src_port; - uint16 dst_port; -} sleep_cfg_tcpka_t; - -typedef struct { - uint8 id; - uint16 period; - uint16 len; -} sleep_cfg_mkeepalive_t; - -typedef struct { - uint8 pm_mode; - uint8 mpc; - uint16 max_sleep_ms; - uint8 dtim_skip; - uint8 pads1; - uint16 pretbtt; - uint8 is_connected; - uint8 is_tcp_connected; - sleep_cfg_mkeepalive_t mka[MKEEP_ALIVE_NUM]; - uint8 mka_cnt; - uint8 pads2[3]; - sleep_cfg_tcpka_t tcpka[TCPKA_SESSION_NUM]; - uint8 tcpka_cnt; - uint8 pads3[3]; -} wifi_stats_sleep_cfg_t; - -typedef struct { - uint16 id; - uint8 polarity; - uint8 pads1; - uint32 timeout; - uint32 num_pkts_matched; - uint8 timed_out; - uint8 pads2[3]; -} wake_stats_pktfilter_t; - -typedef struct { - uint32 rx_wakes; - uint32 ctrl_wakes; - uint32 sleep_duration; - uint32 pm_duration; - uint32 beacons; - uint32 rx_badplcp; - uint32 rx_badfcs; - wake_stats_pktfilter_t pf[PKT_FILTER_MAX_NUM]; - uint8 pf_cnt; - uint8 wake_reason; - uint8 pads[2]; -} wifi_stats_host_wake_t; - -typedef struct { - uint32 lost_bcn; - uint32 force_awake_duration; - uint32 wake_interval; /* in milliseconds */ -} wifi_stats_host_wake_v2_t; - -#define MAX_ANT 4 -typedef struct { - uint8 antenna_cnt; - uint8 current_idx; - uint8 pads[2]; - uint32 switch_count; - uint32 duration[MAX_ANT]; - uint32 switch_time; -} wifi_stats_antenna_t; - -typedef struct { - uint32 unknown_ap_flag; - uint32 roaming_to_origin_connected_ap; - uint32 disconnect_with_disconnectd_ap; - uint32 disconnect_with_empty_ap_list; - uint32 disconnect_with_mismatched_bssid; -} wifi_stats_err_cnt_t; - -typedef struct { - uint32 id; - wifi_stats_ap_info_t ap_info[AP_INFO_SLOT_MAX]; - uint8 ap_cnt; - uint8 pads[3]; /* alignment */ - wifi_stats_sleep_cfg_t sleep_cfg; - wifi_stats_host_wake_t wake_stats; - vs_oui_t ap_vs_oui[AP_INFO_SLOT_MAX][VS_IE_MAX_NUM]; -} wifi_fw_stats_v1_t; - -typedef struct { - uint32 id; - wifi_stats_ap_info_t ap_info[AP_INFO_SLOT_MAX]; - uint8 ap_cnt; - uint8 pads[3]; /* alignment */ - wifi_stats_sleep_cfg_t sleep_cfg; - wifi_stats_host_wake_t wake_stats; - vs_oui_t ap_vs_oui[AP_INFO_SLOT_MAX][VS_IE_MAX_NUM]; - /* v2 addtional data */ - wifi_stats_ap_info_v2_t ap_info_v2[AP_INFO_SLOT_MAX]; - wifi_stats_host_wake_v2_t wake_stats_v2; - wifi_stats_antenna_t antenna_stats; - uint32 uptime; /* system up time as base for epoch time */ - wifi_stats_err_cnt_t err_cnt; -} wifi_fw_stats_t; - -#endif /* WIFI_STATS */ - -#ifdef SDIO_TRAITS_STATS -#define SDIO_TRAITS_CNT_SHIFT 4 -#define SDIO_TRAITS_CNT_LO_MASK 0x0f -#define SDIO_TRAITS_CNT_HI_MASK 0xf0 -#define SDIO_TRAITS_MAX_CNT 0xf - -typedef struct { - uint8 attach_sdio_fail_cnt; /* 0-3 bit is attach_sdio_fail cnt, 4-7 bit is conn lost cnt */ - uint8 firmware_hang_cnt; - uint8 bus_hang_cnt; /* 0-3 bit is bus hang cnt, 4-7 bit is dhcp fail cnt */ - uint8 fw_reload_phy_reinit_cnt; -} sdio_traits_stats_t; - -typedef enum { - FW_RELOAD_BACKOFF_TYPE_PHY_REINIT = 0, - FW_RELOAD_BACKOFF_TYPE_CONNECTION, - FW_RELOAD_BACKOFF_TYPE_DHCP, - FW_RELOAD_BACKOFF_TYPE_MAX, -} fw_reload_backoff_type; - -extern void dhd_bus_traits_attach_fail_inc(void); -extern void dhd_bus_traits_fw_hang_inc(void); -extern void dhd_bus_traits_bus_hang_inc(void); -extern void dhd_bus_traits_fw_reload_phy_reinit_inc(void); -extern void dhd_bus_traits_fw_reload_conn_stuck_inc(void); -extern void dhd_bus_traits_fw_reload_dhcp_stuck_inc(void); -#endif /* SDIO_TRAITS_STATS */ - -/* Common structure for module and instance linkage */ -typedef struct dhd_pub { - /* Linkage ponters */ - osl_t *osh; /* OSL handle */ - struct dhd_bus *bus; /* Bus module handle */ - struct dhd_prot *prot; /* Protocol module handle */ - struct dhd_info *info; /* Info module handle */ - struct dhd_dbg *dbg; /* Debugability module handle */ - - /* to NDIS developer, the structure dhd_common is redundant, - * please do NOT merge it back from other branches !!! - */ - -#ifdef BCMDBUS - struct dbus_pub *dbus; -#endif /* BCMDBUS */ - - /* Internal dhd items */ - bool up; /* Driver up/down (to OS) */ -#ifdef WL_CFG80211 - spinlock_t up_lock; /* Synchronization with CFG80211 down */ -#endif /* WL_CFG80211 */ - bool txoff; /* Transmit flow-controlled */ - bool dongle_reset; /* TRUE = DEVRESET put dongle into reset */ - enum dhd_bus_state busstate; - uint dhd_bus_busy_state; /* Bus busy state */ - uint hdrlen; /* Total DHD header length (proto + bus) */ - uint maxctl; /* Max size rxctl request from proto to bus */ - uint rxsz; /* Rx buffer size bus module should use */ - uint8 wme_dp; /* wme discard priority */ - - /* Dongle media info */ - bool iswl; /* Dongle-resident driver is wl */ - ulong drv_version; /* Version of dongle-resident driver */ - struct ether_addr mac; /* MAC address obtained from dongle */ - dngl_stats_t dstats; /* Stats for dongle-based data */ - - /* Additional stats for the bus level */ - ulong tx_packets; /* Data packets sent to dongle */ - ulong tx_dropped; /* Data packets dropped in dhd */ - ulong tx_multicast; /* Multicast data packets sent to dongle */ - ulong tx_errors; /* Errors in sending data to dongle */ - ulong tx_ctlpkts; /* Control packets sent to dongle */ - ulong tx_ctlerrs; /* Errors sending control frames to dongle */ - ulong rx_packets; /* Packets sent up the network interface */ - ulong rx_multicast; /* Multicast packets sent up the network interface */ - ulong rx_errors; /* Errors processing rx data packets */ - ulong rx_ctlpkts; /* Control frames processed from dongle */ - ulong rx_ctlerrs; /* Errors in processing rx control frames */ - ulong rx_dropped; /* Packets dropped locally (no memory) */ - ulong rx_flushed; /* Packets flushed due to unscheduled sendup thread */ - ulong wd_dpc_sched; /* Number of times dhd dpc scheduled by watchdog timer */ - ulong rx_pktgetfail; /* Number of PKTGET failures in DHD on RX */ - ulong tx_pktgetfail; /* Number of PKTGET failures in DHD on TX */ - ulong rx_readahead_cnt; /* Number of packets where header read-ahead was used. */ - ulong tx_realloc; /* Number of tx packets we had to realloc for headroom */ - ulong fc_packets; /* Number of flow control pkts recvd */ - -#ifdef DMAMAP_STATS - /* DMA Mapping statistics */ - dma_stats_t dma_stats; -#endif /* DMAMAP_STATS */ - - /* Last error return */ - int bcmerror; - uint tickcnt; - - /* Last error from dongle */ - int dongle_error; - - uint8 country_code[WLC_CNTRY_BUF_SZ]; - - /* Suspend disable flag and "in suspend" flag */ - int suspend_disable_flag; /* "1" to disable all extra powersaving during suspend */ - int in_suspend; /* flag set to 1 when early suspend called */ -#ifdef PNO_SUPPORT - int pno_enable; /* pno status : "1" is pno enable */ - int pno_suspend; /* pno suspend status : "1" is pno suspended */ -#endif /* PNO_SUPPORT */ - /* DTIM skip value, default 0(or 1) means wake each DTIM - * 3 means skip 2 DTIMs and wake up 3rd DTIM(9th beacon when AP DTIM is 3) - */ - int suspend_bcn_li_dtim; /* bcn_li_dtim value in suspend mode */ -#ifdef PKT_FILTER_SUPPORT - int early_suspended; /* Early suspend status */ - int dhcp_in_progress; /* DHCP period */ -#endif - - /* Pkt filter defination */ - char *pktfilter[100]; - int pktfilter_count; -#ifdef PF_SETUP_COMMAND - int pktfilter_count_ext; -#endif /* PF_SETUP_COMMAND */ - - wl_country_t dhd_cspec; /* Current Locale info */ -#ifdef CUSTOM_COUNTRY_CODE - uint dhd_cflags; -#endif /* CUSTOM_COUNTRY_CODE */ -#if defined(DHD_BLOB_EXISTENCE_CHECK) - bool is_blob; /* Checking for existance of Blob file */ -#endif /* DHD_BLOB_EXISTENCE_CHECK */ - bool force_country_change; - char eventmask[WL_EVENTING_MASK_LEN]; - int op_mode; /* STA, HostAPD, WFD, SoftAP */ - -/* Set this to 1 to use a seperate interface (p2p0) for p2p operations. - * For ICS MR1 releases it should be disable to be compatable with ICS MR1 Framework - * see target dhd-cdc-sdmmc-panda-cfg80211-icsmr1-gpl-debug in Makefile - */ -/* #define WL_ENABLE_P2P_IF 1 */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - struct mutex wl_start_stop_lock; /* lock/unlock for Android start/stop */ - struct mutex wl_softap_lock; /* lock/unlock for any SoftAP/STA settings */ -#endif - -#ifdef PROP_TXSTATUS - bool wlfc_enabled; - int wlfc_mode; - void* wlfc_state; - /* - Mode in which the dhd flow control shall operate. Must be set before - traffic starts to the device. - 0 - Do not do any proptxtstatus flow control - 1 - Use implied credit from a packet status - 2 - Use explicit credit - 3 - Only AMPDU hostreorder used. no wlfc. - */ - uint8 proptxstatus_mode; - bool proptxstatus_txoff; - bool proptxstatus_module_ignore; - bool proptxstatus_credit_ignore; - bool proptxstatus_txstatus_ignore; - - bool wlfc_rxpkt_chk; -#ifdef LIMIT_BORROW - bool wlfc_borrow_allowed; -#endif /* LIMIT_BORROW */ - /* - * implement below functions in each platform if needed. - */ - /* platform specific function whether to skip flow control */ - bool (*skip_fc)(void * dhdp, uint8 ifx); - /* platform specific function for wlfc_enable and wlfc_deinit */ - void (*plat_init)(void *dhd); - void (*plat_deinit)(void *dhd); -#ifdef DHD_WLFC_THREAD - bool wlfc_thread_go; - struct task_struct* wlfc_thread; - wait_queue_head_t wlfc_wqhead; -#endif /* DHD_WLFC_THREAD */ -#endif /* PROP_TXSTATUS */ -#ifdef PNO_SUPPORT - void *pno_state; -#endif -#ifdef RTT_SUPPORT - void *rtt_state; - bool rtt_supported; -#endif - bool dongle_isolation; - bool is_pcie_watchdog_reset; - bool dongle_trap_occured; /* flag for sending HANG event to upper layer */ - bool iovar_timeout_occured; /* flag to indicate iovar resumed on timeout */ -#ifdef PCIE_FULL_DONGLE - bool d3ack_timeout_occured; /* flag to indicate d3ack resumed on timeout */ -#endif /* PCIE_FULL_DONGLE */ -#ifdef BT_OVER_SDIO - bool is_bt_recovery_required; -#endif - int hang_was_sent; - int rxcnt_timeout; /* counter rxcnt timeout to send HANG */ - int txcnt_timeout; /* counter txcnt timeout to send HANG */ -#ifdef BCMPCIE - int d3ackcnt_timeout; /* counter d3ack timeout to send HANG */ -#endif /* BCMPCIE */ - bool hang_report; /* enable hang report by default */ - uint16 hang_reason; /* reason codes for HANG event */ -#if defined(DHD_HANG_SEND_UP_TEST) - uint req_hang_type; -#endif /* DHD_HANG_SEND_UP_TEST */ -#if defined(CONFIG_BCM_DETECT_CONSECUTIVE_HANG) - uint hang_counts; -#endif /* CONFIG_BCM_DETECT_CONSECUTIVE_HANG */ -#ifdef WLMEDIA_HTSF - uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */ -#endif -#ifdef WLTDLS - bool tdls_enable; -#endif - struct reorder_info *reorder_bufs[WLHOST_REORDERDATA_MAXFLOWS]; - #define WLC_IOCTL_MAXBUF_FWCAP 512 - char fw_capabilities[WLC_IOCTL_MAXBUF_FWCAP]; - #define MAXSKBPEND 1024 - void *skbbuf[MAXSKBPEND]; - uint32 store_idx; - uint32 sent_idx; -#ifdef DHDTCPACK_SUPPRESS - uint8 tcpack_sup_mode; /* TCPACK suppress mode */ - void *tcpack_sup_module; /* TCPACK suppress module */ - uint32 tcpack_sup_ratio; - uint32 tcpack_sup_delay; -#endif /* DHDTCPACK_SUPPRESS */ -#if defined(ARP_OFFLOAD_SUPPORT) - uint32 arp_version; -#endif -#ifdef DEBUG_DPC_THREAD_WATCHDOG - bool dhd_bug_on; -#endif /* DEBUG_DPC_THREAD_WATCHDOG */ -#ifdef CUSTOM_SET_CPUCORE - struct task_struct * current_dpc; - struct task_struct * current_rxf; - int chan_isvht80; -#endif /* CUSTOM_SET_CPUCORE */ - - - void *sta_pool; /* pre-allocated pool of sta objects */ - void *staid_allocator; /* allocator of sta indexes */ -#ifdef PCIE_FULL_DONGLE - bool flow_rings_inited; /* set this flag after initializing flow rings */ -#endif /* PCIE_FULL_DONGLE */ - void *flowid_allocator; /* unique flowid allocator */ - void *flow_ring_table; /* flow ring table, include prot and bus info */ - void *if_flow_lkup; /* per interface flowid lkup hash table */ - void *flowid_lock; /* per os lock for flowid info protection */ - void *flowring_list_lock; /* per os lock for flowring list protection */ - uint32 num_flow_rings; - cumm_ctr_t cumm_ctr; /* cumm queue length placeholder */ - cumm_ctr_t l2cumm_ctr; /* level 2 cumm queue length placeholder */ - uint32 d2h_sync_mode; /* D2H DMA completion sync mode */ - uint8 flow_prio_map[NUMPRIO]; - uint8 flow_prio_map_type; - char enable_log[MAX_EVENT]; - bool dma_d2h_ring_upd_support; - bool dma_h2d_ring_upd_support; - bool dma_ring_upd_overwrite; /* host overwrites support setting */ - - bool idma_enable; - uint idma_inited; - bool idma_retention_ds; /* Implicit DMA memory retention */ - - bool ifrm_enable; /* implicit frm enable */ - uint ifrm_inited; /* implicit frm init */ - -#ifdef DHD_WMF - bool wmf_ucast_igmp; -#ifdef DHD_IGMP_UCQUERY - bool wmf_ucast_igmp_query; -#endif -#ifdef DHD_UCAST_UPNP - bool wmf_ucast_upnp; -#endif -#endif /* DHD_WMF */ -#if defined(TRAFFIC_MGMT_DWM) - dhd_trf_mgmt_dwm_tbl_t dhd_tm_dwm_tbl; -#endif -#ifdef DHD_L2_FILTER - unsigned long l2_filter_cnt; /* for L2_FILTER ARP table timeout */ -#endif /* DHD_L2_FILTER */ -#ifdef DHD_SSSR_DUMP - bool sssr_inited; - sssr_reg_info_t sssr_reg_info; - uint8 *sssr_mempool; - uint *sssr_d11_before[MAX_NUM_D11CORES]; - uint *sssr_d11_after[MAX_NUM_D11CORES]; - bool sssr_d11_outofreset[MAX_NUM_D11CORES]; - uint *sssr_vasip_buf_before; - uint *sssr_vasip_buf_after; -#endif /* DHD_SSSR_DUMP */ - uint8 *soc_ram; - uint32 soc_ram_length; - uint32 memdump_type; -#ifdef DHD_FW_COREDUMP - uint32 memdump_enabled; - bool memdump_success; -#endif /* DHD_FW_COREDUMP */ -#ifdef PCIE_FULL_DONGLE -#ifdef WLTDLS - tdls_peer_tbl_t peer_tbl; -#endif /* WLTDLS */ - uint8 tx_in_progress; -#endif /* PCIE_FULL_DONGLE */ -#ifdef DHD_ULP - void *dhd_ulp; -#endif -#ifdef CACHE_FW_IMAGES - char *cached_fw; - int cached_fw_length; - char *cached_nvram; - int cached_nvram_length; - char *cached_clm; - int cached_clm_length; -#endif -#ifdef WLTDLS - uint32 tdls_mode; -#endif -#ifdef GSCAN_SUPPORT - bool lazy_roam_enable; -#endif -#if defined(PKT_FILTER_SUPPORT) && defined(APF) - bool apf_set; -#endif /* PKT_FILTER_SUPPORT && APF */ -#ifdef DHD_WET - void *wet_info; -#endif - bool h2d_phase_supported; - bool force_dongletrap_on_bad_h2d_phase; - uint32 dongle_trap_data; - bool cto_enable; /* enable PCIE CTO Prevention and recovery */ - uint32 cto_threshold; /* PCIE CTO timeout threshold */ - bool fw_download_done; - trap_t last_trap_info; /* trap info from the last trap */ - uint8 rand_mac_oui[DOT11_OUI_LEN]; -#ifdef DHD_LOSSLESS_ROAMING - uint8 dequeue_prec_map; - uint8 prio_8021x; -#endif -#ifdef REPORT_FATAL_TIMEOUTS - timeout_info_t *timeout_info; -#endif /* REPORT_FATAL_TIMEOUTS */ - /* timesync link */ - struct dhd_ts *ts; - bool d2h_hostrdy_supported; -#if defined(DBG_PKT_MON) || defined(DHD_PKT_LOGGING) - bool d11_tx_status; -#endif /* DBG_PKT_MON || DHD_PKT_LOGGING */ - uint16 ndo_version; /* ND offload version supported */ -#ifdef NDO_CONFIG_SUPPORT - bool ndo_enable; /* ND offload feature enable */ - bool ndo_host_ip_overflow; /* # of host ip addr exceed FW capacity */ - uint32 ndo_max_host_ip; /* # of host ip addr supported by FW */ -#endif /* NDO_CONFIG_SUPPORT */ -#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) - uint8 log_capture_enable; -#endif /* DHD_EFI && DHD_LOG_DUMP */ - bool max_dtim_enable; /* use MAX bcn_li_dtim value in suspend mode */ -#ifdef PCIE_OOB - bool d2h_no_oob_dw; -#endif /* PCIE_OOB */ -#ifdef PCIE_INB_DW - bool d2h_inband_dw; - enum dhd_bus_ds_state ds_state; -#endif /* PCIE_INB_DW */ -#ifdef CUSTOM_SET_ANTNPM - uint32 mimo_ant_set; -#endif /* CUSTOM_SET_ANTNPM */ -#ifdef CUSTOM_SET_OCLOFF - bool ocl_off; -#endif /* CUSTOM_SET_OCLOFF */ -#ifdef HOFFLOAD_MODULES - struct module_metadata hmem; -#endif - bool wbtext_support; -#ifdef DUMP_IOCTL_IOV_LIST - /* dump iovar list */ - dll_t dump_iovlist_head; - uint8 dump_iovlist_len; -#endif /* DUMP_IOCTL_IOV_LIST */ -#ifdef DHD_DEBUG -/* memwaste feature */ - dll_t mw_list_head; /* memwaste list head */ - uint32 mw_id; /* memwaste list unique id */ -#endif /* DHD_DEBUG */ -#ifdef WLTDLS - spinlock_t tdls_lock; -#endif /* WLTDLS */ -#ifdef WLADPS_SEAK_AP_WAR - uint32 disabled_adps; -#endif /* WLADPS_SEAK_AP_WAR */ - bool ext_trap_data_supported; - uint32 *extended_trap_data; -#ifdef DHD_PKT_LOGGING - struct dhd_pktlog *pktlog; -#endif /* DHD_PKT_LOGGING */ -#if defined(STAT_REPORT) - void *stat_report_info; -#endif - char *clm_path; /* module_param: path to clm vars file */ - char *conf_path; /* module_param: path to config vars file */ - char *reg_path; /* module_param; path to reg vars file */ - struct dhd_conf *conf; /* Bus module handle */ - void *adapter; /* adapter information, interrupt, fw path etc. */ -#ifdef BCMDBUS - bool dhd_remove; -#endif /* BCMDBUS */ -#ifdef IDSUP_STATS - wifi_wpa_state_t wpa_state; - bool is_4way_timeout; -#endif /* IDSUP_STATS */ -#ifdef HAL_API - uint8 block_fw_cmd; -#endif /* HAL_API */ -#ifdef RELOAD_WIFI - uint8 fw_need_reload; - uint8 wifi_recover_reason; -#endif /* RELOAD_WIFI */ -#if EVENT_DATA_HOSTWAKE - uint8 evt_data_sendup; - uint8 pending_evt_data; - uint8 hal_req_sched_wake; -#endif /* EVENT_DATA_HOSTWAKE */ -#ifdef RESUME_INIT - bool resume_init; -#endif /* RESUME_INIT */ -#ifdef UART_HB_CONFIG - uint32 wowl_alive; -#endif /* UART_HB_CONFIG */ - bool padsiso; -#ifdef BCOL_TCPKA_SYNC - struct mutex dhd_tcpka_mutex; -#endif /* BCOL_TCPKA_SYNC */ -} dhd_pub_t; - -typedef struct { - uint rxwake; - uint rcwake; -#ifdef WIFI_STATS - uint8 event[4]; -#endif /* WIFI_STATS */ -#ifdef DHD_WAKE_RX_STATUS - uint rx_bcast; - uint rx_arp; - uint rx_mcast; - uint rx_multi_ipv6; - uint rx_icmpv6; - uint rx_icmpv6_ra; - uint rx_icmpv6_na; - uint rx_icmpv6_ns; - uint rx_multi_ipv4; - uint rx_multi_other; - uint rx_ucast; -#endif /* DHD_WAKE_RX_STATUS */ -#ifdef DHD_WAKE_EVENT_STATUS - uint rc_event[WLC_E_LAST]; -#endif /* DHD_WAKE_EVENT_STATUS */ -} wake_counts_t; - -#if defined(PCIE_FULL_DONGLE) - -/* Packet Tag for PCIE Full Dongle DHD */ -typedef struct dhd_pkttag_fd { - uint16 flowid; /* Flowring Id */ - uint16 dataoff; /* start of packet */ - uint16 dma_len; /* pkt len for DMA_MAP/UNMAP */ - dmaaddr_t pa; /* physical address */ - void *dmah; /* dma mapper handle */ - void *secdma; /* secure dma sec_cma_info handle */ -} dhd_pkttag_fd_t; - -/* Packet Tag for DHD PCIE Full Dongle */ -#define DHD_PKTTAG_FD(pkt) ((dhd_pkttag_fd_t *)(PKTTAG(pkt))) - -#define DHD_PKT_GET_FLOWID(pkt) ((DHD_PKTTAG_FD(pkt))->flowid) -#define DHD_PKT_SET_FLOWID(pkt, pkt_flowid) \ - DHD_PKTTAG_FD(pkt)->flowid = (uint16)(pkt_flowid) - -#define DHD_PKT_GET_DATAOFF(pkt) ((DHD_PKTTAG_FD(pkt))->dataoff) -#define DHD_PKT_SET_DATAOFF(pkt, pkt_dataoff) \ - DHD_PKTTAG_FD(pkt)->dataoff = (uint16)(pkt_dataoff) - -#define DHD_PKT_GET_DMA_LEN(pkt) ((DHD_PKTTAG_FD(pkt))->dma_len) -#define DHD_PKT_SET_DMA_LEN(pkt, pkt_dma_len) \ - DHD_PKTTAG_FD(pkt)->dma_len = (uint16)(pkt_dma_len) - -#define DHD_PKT_GET_PA(pkt) ((DHD_PKTTAG_FD(pkt))->pa) -#define DHD_PKT_SET_PA(pkt, pkt_pa) \ - DHD_PKTTAG_FD(pkt)->pa = (dmaaddr_t)(pkt_pa) - -#define DHD_PKT_GET_DMAH(pkt) ((DHD_PKTTAG_FD(pkt))->dmah) -#define DHD_PKT_SET_DMAH(pkt, pkt_dmah) \ - DHD_PKTTAG_FD(pkt)->dmah = (void *)(pkt_dmah) - -#define DHD_PKT_GET_SECDMA(pkt) ((DHD_PKTTAG_FD(pkt))->secdma) -#define DHD_PKT_SET_SECDMA(pkt, pkt_secdma) \ - DHD_PKTTAG_FD(pkt)->secdma = (void *)(pkt_secdma) -#endif /* PCIE_FULL_DONGLE */ - -#if defined(BCMWDF) -typedef struct { - dhd_pub_t *dhd_pub; -} dhd_workitem_context_t; - -WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(dhd_workitem_context_t, dhd_get_dhd_workitem_context) -#endif /* (BCMWDF) */ - - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) - - #define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); - #define _DHD_PM_RESUME_WAIT(a, b) do {\ - int retry = 0; \ - SMP_RD_BARRIER_DEPENDS(); \ - while (dhd_mmc_suspend && retry++ != b) { \ - SMP_RD_BARRIER_DEPENDS(); \ - wait_event_interruptible_timeout(a, !dhd_mmc_suspend, 1); \ - } \ - } while (0) - #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 200) - #define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0) - #define DHD_PM_RESUME_RETURN_ERROR(a) do { \ - if (dhd_mmc_suspend) { \ - printf("%s[%d]: mmc is still in suspend state!!!\n", \ - __FUNCTION__, __LINE__); \ - return a; \ - } \ - } while (0) - #define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0) - - #define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); - #define SPINWAIT_SLEEP(a, exp, us) do { \ - uint countdown = (us) + 9999; \ - while ((exp) && (countdown >= 10000)) { \ - wait_event_interruptible_timeout(a, FALSE, 1); \ - countdown -= 10000; \ - } \ - } while (0) - - #else - - #define DHD_PM_RESUME_WAIT_INIT(a) - #define DHD_PM_RESUME_WAIT(a) - #define DHD_PM_RESUME_WAIT_FOREVER(a) - #define DHD_PM_RESUME_RETURN_ERROR(a) - #define DHD_PM_RESUME_RETURN - - #define DHD_SPINWAIT_SLEEP_INIT(a) - #define SPINWAIT_SLEEP(a, exp, us) do { \ - uint countdown = (us) + 9; \ - while ((exp) && (countdown >= 10)) { \ - OSL_DELAY(10); \ - countdown -= 10; \ - } \ - } while (0) - - #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ - -#ifndef OSL_SLEEP -#define OSL_SLEEP(ms) OSL_DELAY(ms*1000) -#endif /* OSL_SLEEP */ - -#define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */ - -#ifdef PNO_SUPPORT -int dhd_pno_clean(dhd_pub_t *dhd); -#endif /* PNO_SUPPORT */ - -#ifdef HOFFLOAD_MODULES -void dhd_linux_get_modfw_address(dhd_pub_t *dhd); -#endif - -/* - * Wake locks are an Android power management concept. They are used by applications and services - * to request CPU resources. - */ -extern int dhd_os_wake_lock(dhd_pub_t *pub); -extern int dhd_os_wake_unlock(dhd_pub_t *pub); -extern int dhd_os_wake_lock_waive(dhd_pub_t *pub); -extern int dhd_os_wake_lock_restore(dhd_pub_t *pub); -extern void dhd_event_wake_lock(dhd_pub_t *pub); -extern void dhd_event_wake_unlock(dhd_pub_t *pub); -extern void dhd_pm_wake_lock_timeout(dhd_pub_t *pub, int val); -extern void dhd_pm_wake_unlock(dhd_pub_t *pub); -extern void dhd_txfl_wake_lock_timeout(dhd_pub_t *pub, int val); -extern void dhd_txfl_wake_unlock(dhd_pub_t *pub); -extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub); -extern int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val); -extern int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val); -extern int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub); -extern int dhd_os_wd_wake_lock(dhd_pub_t *pub); -extern int dhd_os_wd_wake_unlock(dhd_pub_t *pub); -extern void dhd_os_wake_lock_init(struct dhd_info *dhd); -extern void dhd_os_wake_lock_destroy(struct dhd_info *dhd); -#ifdef DHD_USE_SCAN_WAKELOCK -extern void dhd_os_scan_wake_lock_timeout(dhd_pub_t *pub, int val); -extern void dhd_os_scan_wake_unlock(dhd_pub_t *pub); -#endif /* BCMPCIE_SCAN_WAKELOCK */ - -inline static void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_init(&dhdp->wl_softap_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -inline static void MUTEX_LOCK_SOFTAP_SET(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_lock(&dhdp->wl_softap_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&dhdp->wl_softap_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -#define PRINT_CALL_INFO(str) -#define PRINT_CALL_INFO_TIMEOUT(str, val) -#define DHD_OS_WAKE_LOCK(pub) \ - do { \ - PRINT_CALL_INFO("call wakelock"); \ - dhd_os_wake_lock(pub); \ - } while (0) -#define DHD_OS_WAKE_UNLOCK(pub) \ - do { \ - PRINT_CALL_INFO("call wake_unlock"); \ - dhd_os_wake_unlock(pub); \ - } while (0) -#define DHD_EVENT_WAKE_LOCK(pub) \ - do { \ - PRINT_CALL_INFO("call event_wake lock"); \ - dhd_event_wake_lock(pub); \ - } while (0) -#define DHD_EVENT_WAKE_UNLOCK(pub) \ - do { \ - PRINT_CALL_INFO("call event_wake unlock"); \ - dhd_event_wake_unlock(pub); \ - } while (0) -#define DHD_PM_WAKE_LOCK_TIMEOUT(pub, val) \ - do { \ - PRINT_CALL_INFO("call pm_wake_timeout enable"); \ - dhd_pm_wake_lock_timeout(pub, val); \ - } while (0) -#define DHD_PM_WAKE_UNLOCK(pub) \ - do { \ - PRINT_CALL_INFO("call pm_wake unlock"); \ - dhd_pm_wake_unlock(pub); \ - } while (0) -#define DHD_TXFL_WAKE_LOCK_TIMEOUT(pub, val) \ - do { \ - PRINT_CALL_INFO("call pm_wake_timeout enable"); \ - dhd_txfl_wake_lock_timeout(pub, val); \ - } while (0) -#define DHD_TXFL_WAKE_UNLOCK(pub) \ - do { \ - PRINT_CALL_INFO("call pm_wake unlock"); \ - dhd_txfl_wake_unlock(pub); \ - } while (0) -#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) \ - do { \ - PRINT_CALL_INFO("call wake_lock_timeout"); \ - dhd_os_wake_lock_timeout(pub); \ - } while (0) -#define DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(pub, val) \ - do { \ - PRINT_CALL_INFO_TIMEOUT("call wake_lock_rx_timeout_enable", val); \ - dhd_os_wake_lock_rx_timeout_enable(pub, val); \ - } while (0) -#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(pub, val) \ - do { \ - PRINT_CALL_INFO_TIMEOUT("call wake_lock_ctrl_timeout_enable", val); \ - dhd_os_wake_lock_ctrl_timeout_enable(pub, val); \ - } while (0) -#define DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_CANCEL(pub) \ - do { \ - PRINT_CALL_INFO("call wake_lock_ctrl_timeout_cancel"); \ - dhd_os_wake_lock_ctrl_timeout_cancel(pub); \ - } while (0) -#define DHD_OS_WAKE_LOCK_WAIVE(pub) \ - do { \ - PRINT_CALL_INFO("call wake_lock_waive"); \ - dhd_os_wake_lock_waive(pub); \ - } while (0) -#define DHD_OS_WAKE_LOCK_RESTORE(pub) \ - do { \ - PRINT_CALL_INFO("call wake_lock_restore"); \ - dhd_os_wake_lock_restore(pub); \ - } while (0) -#define DHD_OS_WAKE_LOCK_INIT(dhd) \ - do { \ - PRINT_CALL_INFO("call wake_lock_init"); \ - dhd_os_wake_lock_init(dhd); \ - } while (0) -#define DHD_OS_WAKE_LOCK_DESTROY(dhd) \ - do { \ - PRINT_CALL_INFO("call wake_lock_destroy"); \ - dhd_os_wake_lock_destroy(dhd); \ - } while (0) - -#define DHD_OS_WD_WAKE_LOCK(pub) dhd_os_wd_wake_lock(pub) -#define DHD_OS_WD_WAKE_UNLOCK(pub) dhd_os_wd_wake_unlock(pub) - -#ifdef DHD_USE_SCAN_WAKELOCK -#ifdef DHD_DEBUG_SCAN_WAKELOCK -#define PRINT_SCAN_CALL(str) printf("%s: %s %d\n", \ - str, __FUNCTION__, __LINE__) -#else -#define PRINT_SCAN_CALL(str) -#endif /* DHD_DEBUG_SCAN_WAKELOCK */ -#define DHD_OS_SCAN_WAKE_LOCK_TIMEOUT(pub, val) \ - do { \ - PRINT_SCAN_CALL("call wake_lock_scan"); \ - dhd_os_scan_wake_lock_timeout(pub, val); \ - } while (0) -#define DHD_OS_SCAN_WAKE_UNLOCK(pub) \ - do { \ - PRINT_SCAN_CALL("call wake_unlock_scan"); \ - dhd_os_scan_wake_unlock(pub); \ - } while (0) -#else -#define DHD_OS_SCAN_WAKE_LOCK_TIMEOUT(pub, val) -#define DHD_OS_SCAN_WAKE_UNLOCK(pub) -#endif /* DHD_USE_SCAN_WAKELOCK */ - -#ifdef BCMPCIE_OOB_HOST_WAKE -#define OOB_WAKE_LOCK_TIMEOUT 500 -extern void dhd_os_oob_irq_wake_lock_timeout(dhd_pub_t *pub, int val); -extern void dhd_os_oob_irq_wake_unlock(dhd_pub_t *pub); -#define DHD_OS_OOB_IRQ_WAKE_LOCK_TIMEOUT(pub, val) dhd_os_oob_irq_wake_lock_timeout(pub, val) -#define DHD_OS_OOB_IRQ_WAKE_UNLOCK(pub) dhd_os_oob_irq_wake_unlock(pub) -#endif /* BCMPCIE_OOB_HOST_WAKE */ - -#define DHD_PACKET_TIMEOUT_MS 500 -#define DHD_EVENT_TIMEOUT_MS 1500 -#define SCAN_WAKE_LOCK_TIMEOUT 10000 -#define MAX_TX_TIMEOUT 500 - -/* Enum for IOCTL recieved status */ -typedef enum dhd_ioctl_recieved_status -{ - IOCTL_WAIT = 0, - IOCTL_RETURN_ON_SUCCESS, - IOCTL_RETURN_ON_TRAP, - IOCTL_RETURN_ON_BUS_STOP, - IOCTL_RETURN_ON_ERROR -} dhd_ioctl_recieved_status_t; - -/* interface operations (register, remove) should be atomic, use this lock to prevent race - * condition among wifi on/off and interface operation functions - */ -void dhd_net_if_lock(struct net_device *dev); -void dhd_net_if_unlock(struct net_device *dev); -#if defined(MULTIPLE_SUPPLICANT) -extern void wl_android_post_init(void); // terence 20120530: fix critical section in dhd_open and dhdsdio_probe -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && defined(MULTIPLE_SUPPLICANT) -extern struct mutex _dhd_mutex_lock_; -#define DHD_MUTEX_IS_LOCK_RETURN() \ - if (mutex_is_locked(&_dhd_mutex_lock_) != 0) { \ - DHD_INFO(("%s : probe is already running! return.\n", __FUNCTION__)); \ - return 0; \ - } -#define DHD_MUTEX_LOCK() \ - do { \ - if (mutex_is_locked(&_dhd_mutex_lock_) == 0) { \ - DHD_INFO(("%s : no mutex held. set lock\n", __FUNCTION__)); \ - } else { \ - DHD_INFO(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__)); \ - } \ - mutex_lock(&_dhd_mutex_lock_); \ - } while (0) -#define DHD_MUTEX_UNLOCK() \ - do { \ - mutex_unlock(&_dhd_mutex_lock_); \ - DHD_INFO(("%s : the lock is released.\n", __FUNCTION__)); \ - } while (0) -#else -#define DHD_MUTEX_IS_LOCK_RETURN(a) do {} while (0) -#define DHD_MUTEX_LOCK(a) do {} while (0) -#define DHD_MUTEX_UNLOCK(a) do {} while (0) -#endif - -typedef enum dhd_attach_states -{ - DHD_ATTACH_STATE_INIT = 0x0, - DHD_ATTACH_STATE_NET_ALLOC = 0x1, - DHD_ATTACH_STATE_DHD_ALLOC = 0x2, - DHD_ATTACH_STATE_ADD_IF = 0x4, - DHD_ATTACH_STATE_PROT_ATTACH = 0x8, - DHD_ATTACH_STATE_WL_ATTACH = 0x10, - DHD_ATTACH_STATE_THREADS_CREATED = 0x20, - DHD_ATTACH_STATE_WAKELOCKS_INIT = 0x40, - DHD_ATTACH_STATE_CFG80211 = 0x80, - DHD_ATTACH_STATE_EARLYSUSPEND_DONE = 0x100, - DHD_ATTACH_TIMESYNC_ATTACH_DONE = 0x200, - DHD_ATTACH_LOGTRACE_INIT = 0x400, - DHD_ATTACH_STATE_LB_ATTACH_DONE = 0x800, - DHD_ATTACH_STATE_DONE = 0x1000 -} dhd_attach_states_t; - -/* Value -1 means we are unsuccessful in creating the kthread. */ -#define DHD_PID_KT_INVALID -1 -/* Value -2 means we are unsuccessful in both creating the kthread and tasklet */ -#define DHD_PID_KT_TL_INVALID -2 - -/* - * Exported from dhd OS modules (dhd_linux/dhd_ndis) - */ - -/* Indication from bus module regarding presence/insertion of dongle. - * Return dhd_pub_t pointer, used as handle to OS module in later calls. - * Returned structure should have bus and prot pointers filled in. - * bus_hdrlen specifies required headroom for bus module header. - */ -extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen -#ifdef BCMDBUS - , void *adapter -#endif -); -#if defined(WLP2P) && defined(WL_CFG80211) -/* To allow attach/detach calls corresponding to p2p0 interface */ -extern int dhd_attach_p2p(dhd_pub_t *); -extern int dhd_detach_p2p(dhd_pub_t *); -#endif /* WLP2P && WL_CFG80211 */ -extern int dhd_register_if(dhd_pub_t *dhdp, int idx, bool need_rtnl_lock); - -/* Indication from bus module regarding removal/absence of dongle */ -extern void dhd_detach(dhd_pub_t *dhdp); -extern void dhd_free(dhd_pub_t *dhdp); -extern void dhd_clear(dhd_pub_t *dhdp); - -/* Indication from bus module to change flow-control state */ -extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on); - -/* Store the status of a connection attempt for later retrieval by an iovar */ -extern void dhd_store_conn_status(uint32 event, uint32 status, uint32 reason); - -extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec); - -extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt, uint8 chan); - -/* Return pointer to interface name */ -extern char *dhd_ifname(dhd_pub_t *dhdp, int idx); - -#ifdef DHD_UCODE_DOWNLOAD -/* Returns the ucode path */ -extern char *dhd_get_ucode_path(dhd_pub_t *dhdp); -#endif /* DHD_UCODE_DOWNLOAD */ - -/* Request scheduling of the bus dpc */ -extern void dhd_sched_dpc(dhd_pub_t *dhdp); - -/* Notify tx completion */ -extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success); - -#define WIFI_FEATURE_INFRA 0x0001 /* Basic infrastructure mode */ -#define WIFI_FEATURE_INFRA_5G 0x0002 /* Support for 5 GHz Band */ -#define WIFI_FEATURE_HOTSPOT 0x0004 /* Support for GAS/ANQP */ -#define WIFI_FEATURE_P2P 0x0008 /* Wifi-Direct */ -#define WIFI_FEATURE_SOFT_AP 0x0010 /* Soft AP */ -#define WIFI_FEATURE_GSCAN 0x0020 /* Google-Scan APIs */ -#define WIFI_FEATURE_NAN 0x0040 /* Neighbor Awareness Networking */ -#define WIFI_FEATURE_D2D_RTT 0x0080 /* Device-to-device RTT */ -#define WIFI_FEATURE_D2AP_RTT 0x0100 /* Device-to-AP RTT */ -#define WIFI_FEATURE_BATCH_SCAN 0x0200 /* Batched Scan (legacy) */ -#define WIFI_FEATURE_PNO 0x0400 /* Preferred network offload */ -#define WIFI_FEATURE_ADDITIONAL_STA 0x0800 /* Support for two STAs */ -#define WIFI_FEATURE_TDLS 0x1000 /* Tunnel directed link setup */ -#define WIFI_FEATURE_TDLS_OFFCHANNEL 0x2000 /* Support for TDLS off channel */ -#define WIFI_FEATURE_EPR 0x4000 /* Enhanced power reporting */ -#define WIFI_FEATURE_AP_STA 0x8000 /* Support for AP STA Concurrency */ -#define WIFI_FEATURE_LINKSTAT 0x10000 /* Support for Linkstats */ -#define WIFI_FEATURE_LOGGER 0x20000 /* WiFi Logger */ -#define WIFI_FEATURE_HAL_EPNO 0x40000 /* WiFi PNO enhanced */ -#define WIFI_FEATURE_RSSI_MONITOR 0x80000 /* RSSI Monitor */ -#define WIFI_FEATURE_MKEEP_ALIVE 0x100000 /* WiFi mkeep_alive */ -#define WIFI_FEATURE_CONFIG_NDO 0x200000 /* ND offload configure */ -#define WIFI_FEATURE_TX_TRANSMIT_POWER 0x400000 /* Capture Tx transmit power levels */ -#define WIFI_FEATURE_INVALID 0xFFFFFFFF /* Invalid Feature */ - -#define MAX_FEATURE_SET_CONCURRRENT_GROUPS 3 - -extern int dhd_dev_get_feature_set(struct net_device *dev); -extern int dhd_dev_get_feature_set_matrix(struct net_device *dev, int num); -extern int dhd_dev_cfg_rand_mac_oui(struct net_device *dev, uint8 *oui); -#ifdef CUSTOM_FORCE_NODFS_FLAG -extern int dhd_dev_set_nodfs(struct net_device *dev, uint nodfs); -#endif /* CUSTOM_FORCE_NODFS_FLAG */ - -#ifdef NDO_CONFIG_SUPPORT -#ifndef NDO_MAX_HOST_IP_ENTRIES -#define NDO_MAX_HOST_IP_ENTRIES 10 -#endif /* NDO_MAX_HOST_IP_ENTRIES */ -extern int dhd_dev_ndo_cfg(struct net_device *dev, u8 enable); -extern int dhd_dev_ndo_update_inet6addr(struct net_device * dev); -#endif /* NDO_CONFIG_SUPPORT */ -extern int dhd_set_rand_mac_oui(dhd_pub_t *dhd); -#ifdef GSCAN_SUPPORT -extern int dhd_dev_set_lazy_roam_cfg(struct net_device *dev, - wlc_roam_exp_params_t *roam_param); -extern int dhd_dev_lazy_roam_enable(struct net_device *dev, uint32 enable); -extern int dhd_dev_set_lazy_roam_bssid_pref(struct net_device *dev, - wl_bssid_pref_cfg_t *bssid_pref, uint32 flush); -extern int dhd_dev_set_blacklist_bssid(struct net_device *dev, maclist_t *blacklist, - uint32 len, uint32 flush); -extern int dhd_dev_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *whitelist, - uint32 len, uint32 flush); -#endif /* GSCAN_SUPPORT */ - -/* OS independent layer functions */ -extern void dhd_os_dhdiovar_lock(dhd_pub_t *pub); -extern void dhd_os_dhdiovar_unlock(dhd_pub_t *pub); -extern int dhd_os_proto_block(dhd_pub_t * pub); -extern int dhd_os_proto_unblock(dhd_pub_t * pub); -extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition, bool resched); -extern int dhd_os_ioctl_resp_wake(dhd_pub_t * pub); -extern unsigned int dhd_os_get_ioctl_resp_timeout(void); -extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec); -extern void dhd_os_ioctl_resp_lock(dhd_pub_t * pub); -extern void dhd_os_ioctl_resp_unlock(dhd_pub_t * pub); -#ifdef PCIE_FULL_DONGLE -extern void dhd_wakeup_ioctl_event(dhd_pub_t *pub, dhd_ioctl_recieved_status_t reason); -#else -static INLINE void dhd_wakeup_ioctl_event(dhd_pub_t *pub, dhd_ioctl_recieved_status_t reason) -{ printf("%s is NOT implemented for SDIO", __FUNCTION__); return; } -#endif -#ifdef SHOW_LOGTRACE -extern int dhd_os_read_file(void *file, char *buf, uint32 size); -extern int dhd_os_seek_file(void *file, int64 offset); -#endif /* SHOW_LOGTRACE */ - -extern void -dhd_pcie_dump_core_regs(dhd_pub_t * pub, uint32 index, uint32 first_addr, uint32 last_addr); -extern void wl_dhdpcie_dump_regs(void * context); - -#define DHD_OS_IOCTL_RESP_LOCK(x) -#define DHD_OS_IOCTL_RESP_UNLOCK(x) - - -extern int dhd_os_get_image_block(char * buf, int len, void * image); -extern int dhd_os_get_image_size(void * image); -#if defined(BT_OVER_SDIO) -extern int dhd_os_gets_image(dhd_pub_t *pub, char *str, int len, void *image); -extern void dhdsdio_bus_usr_cnt_inc(dhd_pub_t *pub); -extern void dhdsdio_bus_usr_cnt_dec(dhd_pub_t *pub); -#endif /* (BT_OVER_SDIO) */ -extern void * dhd_os_open_image(char * filename); -extern void dhd_os_close_image(void * image); -extern void dhd_os_wd_timer(void *bus, uint wdtick); -#ifdef DHD_PCIE_RUNTIMEPM -extern void dhd_os_runtimepm_timer(void *bus, uint tick); -#endif /* DHD_PCIE_RUNTIMEPM */ -extern void dhd_os_sdlock(dhd_pub_t * pub); -extern void dhd_os_sdunlock(dhd_pub_t * pub); -extern void dhd_os_sdlock_txq(dhd_pub_t * pub); -extern void dhd_os_sdunlock_txq(dhd_pub_t * pub); -extern void dhd_os_sdlock_rxq(dhd_pub_t * pub); -extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub); -extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub); -extern void dhd_os_tracelog(const char *format, ...); -#ifdef DHDTCPACK_SUPPRESS -extern unsigned long dhd_os_tcpacklock(dhd_pub_t *pub); -extern void dhd_os_tcpackunlock(dhd_pub_t *pub, unsigned long flags); -#endif /* DHDTCPACK_SUPPRESS */ - -extern int dhd_customer_oob_irq_map(void *adapter, unsigned long *irq_flags_ptr); -extern int dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff); -extern int dhd_custom_get_mac_address(void *adapter, unsigned char *buf); -#if defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) -extern void get_customized_country_code(void *adapter, char *country_iso_code, - wl_country_t *cspec, u32 flags); -#else -extern void get_customized_country_code(void *adapter, char *country_iso_code, wl_country_t *cspec); -#endif /* defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) */ -extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); -extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); -extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); -extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret); -extern int dhd_os_send_hang_message(dhd_pub_t *dhdp); -extern void dhd_set_version_info(dhd_pub_t *pub, char *fw); -extern bool dhd_os_check_if_up(dhd_pub_t *pub); -extern int dhd_os_check_wakelock(dhd_pub_t *pub); -extern int dhd_os_check_wakelock_all(dhd_pub_t *pub); -extern int dhd_get_instance(dhd_pub_t *pub); -#ifdef CUSTOM_SET_CPUCORE -extern void dhd_set_cpucore(dhd_pub_t *dhd, int set); -#endif /* CUSTOM_SET_CPUCORE */ - -#if defined(KEEP_ALIVE) -extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); -#endif /* KEEP_ALIVE */ - -#if defined(DHD_FW_COREDUMP) -void dhd_schedule_memdump(dhd_pub_t *dhdp, uint8 *buf, uint32 size); -#endif /* DHD_FW_COREDUMP */ - -void dhd_schedule_sssr_dump(dhd_pub_t *dhdp); - -#ifdef SUPPORT_AP_POWERSAVE -extern int dhd_set_ap_powersave(dhd_pub_t *dhdp, int ifidx, int enable); -#endif /* SUPPORT_AP_POWERSAVE */ - -#ifdef PKT_FILTER_SUPPORT -#define DHD_UNICAST_FILTER_NUM 0 -#define DHD_BROADCAST_FILTER_NUM 1 -#define DHD_MULTICAST4_FILTER_NUM 2 -#define DHD_MULTICAST6_FILTER_NUM 3 -#define DHD_MDNS_FILTER_NUM 4 -#define DHD_ARP_FILTER_NUM 5 -#define DHD_BROADCAST_ARP_FILTER_NUM 6 -#define DHD_IP4BCAST_DROP_FILTER_NUM 7 -#define DISCARD_IPV4_MCAST "102 1 6 IP4_H:16 0xf0 0xe0" -#define DISCARD_IPV6_MCAST "103 1 6 IP6_H:24 0xff 0xff" -extern int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val); -extern void dhd_enable_packet_filter(int value, dhd_pub_t *dhd); -extern int dhd_packet_filter_sync(struct net_device *dev); -extern int dhd_packet_filter_add_remove(dhd_pub_t *dhdp, int add_remove, int num); -extern int net_os_enable_packet_filter(struct net_device *dev, int val); -extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num); -extern int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val); -#ifdef PF_SETUP_COMMAND -#define DHD_RESERVED_STATIC_FILTER_NUM 20 -#define DHD_FILTER_NUMBER_START 300 -#define MAX_FILTER_CONFIG_LEN 300 -typedef struct { - u32 id; - u8 addremove; - u32 len; - char config[MAX_FILTER_CONFIG_LEN]; -} pf_config_t; -extern int dhd_packet_filter_add_remove_ext(struct net_device *dev, - bool add, int pf_id, pf_config_t *pf_cfg, bool sync); -#endif /* PF_SETUP_COMMAND */ -#endif /* PKT_FILTER_SUPPORT */ - - -#if defined(BCMPCIE) -extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd, int *dtim_period, int *bcn_interval); -#else -extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); -#endif /* OEM_ANDROID && BCMPCIE */ - -extern bool dhd_support_sta_mode(dhd_pub_t *dhd); -extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); - -#ifdef RSSI_MONITOR_SUPPORT -extern int dhd_dev_set_rssi_monitor_cfg(struct net_device *dev, int start, - int8 max_rssi, int8 min_rssi); -#endif /* RSSI_MONITOR_SUPPORT */ - -#ifdef DHDTCPACK_SUPPRESS -extern int dhd_dev_set_tcpack_sup_mode_cfg(struct net_device *dev, uint8 enable); -#endif /* DHDTCPACK_SUPPRESS */ - -#define DHD_RSSI_MONITOR_EVT_VERSION 1 -typedef struct { - uint8 version; - int8 cur_rssi; - struct ether_addr BSSID; -} dhd_rssi_monitor_evt_t; - -typedef struct { - uint32 limit; /* Expiration time (usec) */ - uint32 increment; /* Current expiration increment (usec) */ - uint32 elapsed; /* Current elapsed time (usec) */ - uint32 tick; /* O/S tick time (usec) */ -} dhd_timeout_t; - -#ifdef SHOW_LOGTRACE -typedef struct { - int num_fmts; - char **fmts; - char *raw_fmts; - char *raw_sstr; - uint32 fmts_size; - uint32 raw_fmts_size; - uint32 raw_sstr_size; - uint32 ramstart; - uint32 rodata_start; - uint32 rodata_end; - char *rom_raw_sstr; - uint32 rom_raw_sstr_size; - uint32 rom_ramstart; - uint32 rom_rodata_start; - uint32 rom_rodata_end; -} dhd_event_log_t; -#endif /* SHOW_LOGTRACE */ - -#ifdef KEEP_ALIVE -extern int dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, uint8 mkeep_alive_id, uint8 *ip_pkt, - uint16 ip_pkt_len, uint8* src_mac_addr, uint8* dst_mac_addr, uint32 period_msec); -extern int dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, uint8 mkeep_alive_id); -#endif /* KEEP_ALIVE */ - -#if defined(PKT_FILTER_SUPPORT) && defined(APF) -/* - * As per Google's current implementation, there will be only one APF filter. - * Therefore, userspace doesn't bother about filter id and because of that - * DHD has to manage the filter id. - */ -#define PKT_FILTER_APF_ID 200 -#define DHD_APF_LOCK(ndev) dhd_apf_lock(ndev) -#define DHD_APF_UNLOCK(ndev) dhd_apf_unlock(ndev) - -extern void dhd_apf_lock(struct net_device *dev); -extern void dhd_apf_unlock(struct net_device *dev); -extern int dhd_dev_apf_get_version(struct net_device *ndev, uint32 *version); -extern int dhd_dev_apf_get_max_len(struct net_device *ndev, uint32 *max_len); -extern int dhd_dev_apf_add_filter(struct net_device *ndev, u8* program, - uint32 program_len); -extern int dhd_dev_apf_enable_filter(struct net_device *ndev); -extern int dhd_dev_apf_disable_filter(struct net_device *ndev); -extern int dhd_dev_apf_delete_filter(struct net_device *ndev); -#endif /* PKT_FILTER_SUPPORT && APF */ - -extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec); -extern int dhd_timeout_expired(dhd_timeout_t *tmo); - -extern int dhd_ifindex2idx(struct dhd_info *dhd, int ifindex); -extern int dhd_ifname2idx(struct dhd_info *dhd, char *name); -extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net); -extern struct net_device * dhd_idx2net(void *pub, int ifidx); -extern int net_os_send_hang_message(struct net_device *dev); -extern int net_os_send_hang_message_reason(struct net_device *dev, const char *string_num); -extern bool dhd_wowl_cap(void *bus); -extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, uint pktlen, - wl_event_msg_t *, void **data_ptr, void *); -extern int wl_process_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, uint pktlen, - wl_event_msg_t *, void **data_ptr, void *); -#ifdef SHOW_EVENTS -void wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, - void *raw_event_ptr, char *eventmask); -#endif /* SHOW_EVENTS */ -extern void wl_event_to_host_order(wl_event_msg_t * evt); -extern int wl_host_event_get_data(void *pktdata, uint pktlen, bcm_event_msg_u_t *evu); -extern int dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len); -extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, - int ifindex); -extern int dhd_wl_ioctl_get_intiovar(dhd_pub_t *dhd_pub, char *name, uint *pval, - int cmd, uint8 set, int ifidx); -extern int dhd_wl_ioctl_set_intiovar(dhd_pub_t *dhd_pub, char *name, uint val, - int cmd, uint8 set, int ifidx); -extern void dhd_common_init(osl_t *osh); - -extern int dhd_do_driver_init(struct net_device *net); -extern int dhd_event_ifadd(struct dhd_info *dhd, struct wl_event_data_if *ifevent, - char *name, uint8 *mac); -extern int dhd_event_ifdel(struct dhd_info *dhd, struct wl_event_data_if *ifevent, - char *name, uint8 *mac); -extern int dhd_event_ifchange(struct dhd_info *dhd, struct wl_event_data_if *ifevent, - char *name, uint8 *mac); -#ifdef DHD_UPDATE_INTF_MAC -extern int dhd_op_if_update(dhd_pub_t *dhdpub, int ifidx); -#endif /* DHD_UPDATE_INTF_MAC */ -extern struct net_device* dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, const char *name, - uint8 *mac, uint8 bssidx, bool need_rtnl_lock, const char *dngl_name); -extern int dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock); -extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char * name); -extern void dhd_vif_del(struct dhd_info *dhd, int ifidx); -extern void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx); -extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len); - -/* Send packet to dongle via data channel */ -extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt); - -/* send up locally generated event */ -extern void dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); -/* Send event to host */ -extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); -#ifdef LOG_INTO_TCPDUMP -extern void dhd_sendup_log(dhd_pub_t *dhdp, void *data, int len); -#endif /* LOG_INTO_TCPDUMP */ -extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag); -extern uint dhd_bus_status(dhd_pub_t *dhdp); -extern int dhd_bus_start(dhd_pub_t *dhdp); -extern int dhd_bus_suspend(dhd_pub_t *dhdpub); -extern int dhd_bus_resume(dhd_pub_t *dhdpub, int stage); -extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size); -extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line); -extern bool dhd_is_associated(dhd_pub_t *dhd, uint8 ifidx, int *retval); -#if defined(BCMSDIO) || defined(BCMPCIE) -extern uint dhd_bus_chip_id(dhd_pub_t *dhdp); -extern uint dhd_bus_chiprev_id(dhd_pub_t *dhdp); -extern uint dhd_bus_chippkg_id(dhd_pub_t *dhdp); -#endif /* defined(BCMSDIO) || defined(BCMPCIE) */ -int dhd_bus_get_fw_mode(dhd_pub_t *dhdp); - -#if defined(KEEP_ALIVE) -extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); -#endif /* KEEP_ALIVE */ - -/* OS spin lock API */ -extern void *dhd_os_spin_lock_init(osl_t *osh); -extern void dhd_os_spin_lock_deinit(osl_t *osh, void *lock); -extern unsigned long dhd_os_spin_lock(void *lock); -void dhd_os_spin_unlock(void *lock, unsigned long flags); - -#ifdef DHD_EFI -extern int dhd_os_ds_enter_wait(dhd_pub_t * pub, uint * condition); -extern int dhd_os_ds_enter_wake(dhd_pub_t * pub); -#else -static INLINE int dhd_os_ds_enter_wait(dhd_pub_t * pub, uint * condition) -{ printf("%s is Not supported for this platform", __FUNCTION__); return 0; } -static INLINE int dhd_os_ds_enter_wake(dhd_pub_t * pub) -{ return 0; } -#endif /* DHD_EFI */ - -#ifdef PCIE_INB_DW -extern int dhd_os_ds_exit_wait(dhd_pub_t * pub, uint * condition); -extern int dhd_os_ds_exit_wake(dhd_pub_t * pub); -#endif /* PCIE_INB_DW */ -extern int dhd_os_busbusy_wake(dhd_pub_t * pub); -extern int dhd_os_busbusy_wait_condition(dhd_pub_t *pub, uint *var, uint condition); -extern int dhd_os_busbusy_wait_negation(dhd_pub_t * pub, uint * condition); -extern int dhd_os_d3ack_wait(dhd_pub_t * pub, uint * condition); -extern int dhd_os_d3ack_wake(dhd_pub_t * pub); - -/* - * Manage sta objects in an interface. Interface is identified by an ifindex and - * sta(s) within an interfaces are managed using a MacAddress of the sta. - */ -struct dhd_sta; -extern bool dhd_sta_associated(dhd_pub_t *dhdp, uint32 bssidx, uint8 *mac); -extern struct dhd_sta *dhd_find_sta(void *pub, int ifidx, void *ea); -extern struct dhd_sta *dhd_findadd_sta(void *pub, int ifidx, void *ea); -extern void dhd_del_all_sta(void *pub, int ifidx); -extern void dhd_del_sta(void *pub, int ifidx, void *ea); -extern int dhd_get_ap_isolate(dhd_pub_t *dhdp, uint32 idx); -extern int dhd_set_ap_isolate(dhd_pub_t *dhdp, uint32 idx, int val); -#if defined(BCM_GMAC3) -extern int dhd_set_dev_def(dhd_pub_t *dhdp, uint32 idx, int val); -#endif -extern int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx); -extern struct net_device *dhd_linux_get_primary_netdev(dhd_pub_t *dhdp); - -extern bool dhd_is_concurrent_mode(dhd_pub_t *dhd); -int dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *param_buf, uint param_len, - char *res_buf, uint res_len, int set); -extern int dhd_getiovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, - uint cmd_len, char **resptr, uint resp_len); - -#ifdef DHD_MCAST_REGEN -extern int dhd_get_mcast_regen_bss_enable(dhd_pub_t *dhdp, uint32 idx); -extern int dhd_set_mcast_regen_bss_enable(dhd_pub_t *dhdp, uint32 idx, int val); -#endif -typedef enum cust_gpio_modes { - WLAN_RESET_ON, - WLAN_RESET_OFF, - WLAN_POWER_ON, - WLAN_POWER_OFF -} cust_gpio_modes_t; - -typedef struct dmaxref_mem_map { - dhd_dma_buf_t *srcmem; - dhd_dma_buf_t *dstmem; -} dmaxref_mem_map_t; - -extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); -extern int wl_iw_send_priv_event(struct net_device *dev, char *flag); -/* - * Insmod parameters for debug/test - */ - -/* Watchdog timer interval */ -extern uint dhd_watchdog_ms; -extern bool dhd_os_wd_timer_enabled(void *bus); -#ifdef DHD_PCIE_RUNTIMEPM -extern uint dhd_runtimepm_ms; -#endif /* DHD_PCIE_RUNTIMEPM */ - -/* Console output poll interval */ -extern uint dhd_console_ms; -extern uint android_msg_level; -extern uint config_msg_level; -extern uint sd_msglevel; -#ifdef BCMDBUS -extern uint dbus_msglevel; -#endif /* BCMDBUS */ -#ifdef WL_WIRELESS_EXT -extern uint iw_msg_level; -#endif -#ifdef WL_CFG80211 -extern uint wl_dbg_level; -#endif - -extern uint dhd_slpauto; - -/* Use interrupts */ -extern uint dhd_intr; - -/* Use polling */ -extern uint dhd_poll; - -/* ARP offload agent mode */ -extern uint dhd_arp_mode; - -/* ARP offload enable */ -extern uint dhd_arp_enable; - -/* Pkt filte enable control */ -extern uint dhd_pkt_filter_enable; - -/* Pkt filter init setup */ -extern uint dhd_pkt_filter_init; - -/* Pkt filter mode control */ -extern uint dhd_master_mode; - -/* Roaming mode control */ -extern uint dhd_roam_disable; - -/* Roaming mode control */ -extern uint dhd_radio_up; - -/* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */ -extern int dhd_idletime; -#ifdef DHD_USE_IDLECOUNT -#define DHD_IDLETIME_TICKS 5 -#else -#define DHD_IDLETIME_TICKS 1 -#endif /* DHD_USE_IDLECOUNT */ - -/* SDIO Drive Strength */ -extern uint dhd_sdiod_drive_strength; - -/* triggers bcm_bprintf to print to kernel log */ -extern bool bcm_bprintf_bypass; - -/* Override to force tx queueing all the time */ -extern uint dhd_force_tx_queueing; - -/* Default bcn_timeout value is 4 */ -#define DEFAULT_BCN_TIMEOUT_VALUE 4 -#ifndef CUSTOM_BCN_TIMEOUT_SETTING -#define CUSTOM_BCN_TIMEOUT_SETTING DEFAULT_BCN_TIMEOUT_VALUE -#endif - -/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ -#define DEFAULT_KEEP_ALIVE_VALUE 55000 /* msec */ -#ifndef CUSTOM_KEEP_ALIVE_SETTING -#define CUSTOM_KEEP_ALIVE_SETTING DEFAULT_KEEP_ALIVE_VALUE -#endif /* DEFAULT_KEEP_ALIVE_VALUE */ - -#define NULL_PKT_STR "null_pkt" - -/* hooks for custom glom setting option via Makefile */ -#define DEFAULT_GLOM_VALUE -1 -#ifndef CUSTOM_GLOM_SETTING -#define CUSTOM_GLOM_SETTING DEFAULT_GLOM_VALUE -#endif -#define WL_AUTO_ROAM_TRIGGER -75 -/* hooks for custom Roaming Trigger setting via Makefile */ -#define DEFAULT_ROAM_TRIGGER_VALUE -75 /* dBm default roam trigger all band */ -#define DEFAULT_ROAM_TRIGGER_SETTING -1 -#ifndef CUSTOM_ROAM_TRIGGER_SETTING -#define CUSTOM_ROAM_TRIGGER_SETTING DEFAULT_ROAM_TRIGGER_VALUE -#endif - -/* hooks for custom Roaming Romaing setting via Makefile */ -#define DEFAULT_ROAM_DELTA_VALUE 10 /* dBm default roam delta all band */ -#define DEFAULT_ROAM_DELTA_SETTING -1 -#ifndef CUSTOM_ROAM_DELTA_SETTING -#define CUSTOM_ROAM_DELTA_SETTING DEFAULT_ROAM_DELTA_VALUE -#endif - -/* hooks for custom PNO Event wake lock to guarantee enough time - for the Platform to detect Event before system suspended -*/ -#define DEFAULT_PNO_EVENT_LOCK_xTIME 2 /* multiplay of DHD_PACKET_TIMEOUT_MS */ -#ifndef CUSTOM_PNO_EVENT_LOCK_xTIME -#define CUSTOM_PNO_EVENT_LOCK_xTIME DEFAULT_PNO_EVENT_LOCK_xTIME -#endif -/* hooks for custom dhd_dpc_prio setting option via Makefile */ -#define DEFAULT_DHP_DPC_PRIO 1 -#ifndef CUSTOM_DPC_PRIO_SETTING -#define CUSTOM_DPC_PRIO_SETTING DEFAULT_DHP_DPC_PRIO -#endif - -#ifndef CUSTOM_LISTEN_INTERVAL -#define CUSTOM_LISTEN_INTERVAL LISTEN_INTERVAL -#endif /* CUSTOM_LISTEN_INTERVAL */ - -#define DEFAULT_SUSPEND_BCN_LI_DTIM 3 -#ifndef CUSTOM_SUSPEND_BCN_LI_DTIM -#define CUSTOM_SUSPEND_BCN_LI_DTIM DEFAULT_SUSPEND_BCN_LI_DTIM -#endif - -#ifndef BCN_TIMEOUT_IN_SUSPEND -#define BCN_TIMEOUT_IN_SUSPEND 6 /* bcn timeout value in suspend mode */ -#endif - -#ifndef CUSTOM_RXF_PRIO_SETTING -#define CUSTOM_RXF_PRIO_SETTING MAX((CUSTOM_DPC_PRIO_SETTING - 1), 1) -#endif - -#define DEFAULT_WIFI_TURNOFF_DELAY 0 -#define WIFI_TURNOFF_DELAY DEFAULT_WIFI_TURNOFF_DELAY - -#define DEFAULT_WIFI_TURNON_DELAY 200 -#ifndef WIFI_TURNON_DELAY -#define WIFI_TURNON_DELAY DEFAULT_WIFI_TURNON_DELAY -#endif /* WIFI_TURNON_DELAY */ - -#ifdef BCMSDIO -#define DEFAULT_DHD_WATCHDOG_INTERVAL_MS 10 /* msec */ -#else -#define DEFAULT_DHD_WATCHDOG_INTERVAL_MS 0 /* msec */ -#endif -#ifndef CUSTOM_DHD_WATCHDOG_MS -#define CUSTOM_DHD_WATCHDOG_MS DEFAULT_DHD_WATCHDOG_INTERVAL_MS -#endif /* DEFAULT_DHD_WATCHDOG_INTERVAL_MS */ - -#define DEFAULT_ASSOC_RETRY_MAX 3 -#ifndef CUSTOM_ASSOC_RETRY_MAX -#define CUSTOM_ASSOC_RETRY_MAX DEFAULT_ASSOC_RETRY_MAX -#endif /* DEFAULT_ASSOC_RETRY_MAX */ - -#if defined(BCMSDIO) || defined(DISABLE_FRAMEBURST) -#define DEFAULT_FRAMEBURST_SET 0 -#else -#define DEFAULT_FRAMEBURST_SET 1 -#endif /* BCMSDIO */ - -#ifndef CUSTOM_FRAMEBURST_SET -#define CUSTOM_FRAMEBURST_SET DEFAULT_FRAMEBURST_SET -#endif /* CUSTOM_FRAMEBURST_SET */ - -#ifdef WLTDLS -#ifndef CUSTOM_TDLS_IDLE_MODE_SETTING -#define CUSTOM_TDLS_IDLE_MODE_SETTING 60000 /* 60sec to tear down TDLS of not active */ -#endif -#ifndef CUSTOM_TDLS_RSSI_THRESHOLD_HIGH -#define CUSTOM_TDLS_RSSI_THRESHOLD_HIGH -70 /* rssi threshold for establishing TDLS link */ -#endif -#ifndef CUSTOM_TDLS_RSSI_THRESHOLD_LOW -#define CUSTOM_TDLS_RSSI_THRESHOLD_LOW -80 /* rssi threshold for tearing down TDLS link */ -#endif -#endif /* WLTDLS */ - -#if defined(VSDB) || defined(ROAM_ENABLE) -#define DEFAULT_BCN_TIMEOUT 8 -#else -#define DEFAULT_BCN_TIMEOUT 4 -#endif - -#ifndef CUSTOM_BCN_TIMEOUT -#define CUSTOM_BCN_TIMEOUT DEFAULT_BCN_TIMEOUT -#endif - -#define MAX_DTIM_SKIP_BEACON_INTERVAL 100 /* max allowed associated AP beacon for DTIM skip */ -#ifndef MAX_DTIM_ALLOWED_INTERVAL -#define MAX_DTIM_ALLOWED_INTERVAL 600 /* max allowed total beacon interval for DTIM skip */ -#endif - -#ifndef MIN_DTIM_FOR_ROAM_THRES_EXTEND -#define MIN_DTIM_FOR_ROAM_THRES_EXTEND 600 /* minimum dtim interval to extend roam threshold */ -#endif - -#define NO_DTIM_SKIP 1 -#ifdef SDTEST -/* Echo packet generator (SDIO), pkts/s */ -extern uint dhd_pktgen; - -/* Echo packet len (0 => sawtooth, max 1800) */ -extern uint dhd_pktgen_len; -#define MAX_PKTGEN_LEN 1800 -#endif - - -/* optionally set by a module_param_string() */ -#define MOD_PARAM_PATHLEN 2048 -#define MOD_PARAM_INFOLEN 512 -#define MOD_PARAM_SRLEN 64 - -#ifdef SOFTAP -extern char fw_path2[MOD_PARAM_PATHLEN]; -#endif - -#ifdef DHD_LEGACY_FILE_PATH -#define PLATFORM_PATH "/data/" -#elif defined(PLATFORM_SLP) -#define PLATFORM_PATH "/opt/etc/" -#else -#define PLATFORM_PATH "/data/misc/conn/" -#endif /* DHD_LEGACY_FILE_PATH */ - -#ifdef BCOL_TCPKA_SYNC -#define TCPKA_DEFAULT_SESS_ID 2 -#define TCPKA_MAX_SESSION 2 -#define PF_FOR_TCPKA_ID_BASE 400 -#define PF_FOR_WEAVE_ID_BASE 420 - -typedef struct bcol_tcpka_sync { - void *tcpka_iovbuf; - uint32 tcpka_iovbuf_len; - tcpka_conn_t *tcpka_conn; - tcpka_conn_sess_t *tcpka_en_info; - uint16 tcpka_sync_mode; - uint16 tcpka_sync_state; - void *tcpka_act_buf; - uint32 tcpka_act_buf_len; - void *tcpka_noti_buf; - struct sock *tcpka_sk; - uint32 tcpka_noti_buf_len; - tcpka_conn_repair_t tcpka_rp; - /* for IPv6 */ - tcpka6_conn_t *tcpka6_conn; - uint8 sess_type; - tcpka_noti_pkt_hold_t tcpka_noti_capture; - bool tcpka_drop; - uint32 tcpka_repair_block; -} bcol_tcpka_sync_t; - -typedef struct bcok_tcpka_sync_info { - uint8 sync_ip_type; - uint8 sync_mode; - uint16 src_port; - uint16 dst_port; -} bcol_tcpka_sync_info_t; -#endif /* BCOL_TCPKA_SYNC */ - -/* Flag to indicate if we should download firmware on driver load */ -extern uint dhd_download_fw_on_driverload; -#ifndef BCMDBUS -extern int allow_delay_fwdl; -#endif /* !BCMDBUS */ - -extern int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost); -extern int dhd_write_file(const char *filepath, char *buf, int buf_len); -extern int dhd_read_file(const char *filepath, char *buf, int buf_len); -extern int dhd_write_file_and_check(const char *filepath, char *buf, int buf_len); - -#ifdef READ_MACADDR -extern int dhd_set_macaddr_from_file(dhd_pub_t *dhdp); -#else -static INLINE int dhd_set_macaddr_from_file(dhd_pub_t *dhdp) { return 0; } -#endif /* READ_MACADDR */ -#ifdef WRITE_MACADDR -extern int dhd_write_macaddr(struct ether_addr *mac); -#else -static INLINE int dhd_write_macaddr(struct ether_addr *mac) { return 0; } -#endif /* WRITE_MACADDR */ -static INLINE int dhd_check_module_cid(dhd_pub_t *dhdp) { return 0; } -#ifdef GET_MAC_FROM_OTP -extern int dhd_check_module_mac(dhd_pub_t *dhdp); -#else -static INLINE int dhd_check_module_mac(dhd_pub_t *dhdp) { return 0; } -#endif /* GET_MAC_FROM_OTP */ - -#if defined(READ_MACADDR) || defined(WRITE_MACADDR) || defined(GET_MAC_FROM_OTP) -#define DHD_USE_CISINFO -#endif - -#ifdef DHD_USE_CISINFO -int dhd_read_cis(dhd_pub_t *dhdp); -void dhd_clear_cis(dhd_pub_t *dhdp); -#else -static INLINE int dhd_read_cis(dhd_pub_t *dhdp) { return 0; } -static INLINE void dhd_clear_cis(dhd_pub_t *dhdp) { } -#endif /* DHD_USE_CISINFO */ - -#define IBSS_COALESCE_DEFAULT 1 -#define IBSS_INITIAL_SCAN_ALLOWED_DEFAULT 1 - - -extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar); -extern void dhd_wait_event_wakeup(dhd_pub_t*dhd); - -#define IFLOCK_INIT(lock) *lock = 0 -#define IFLOCK(lock) while (InterlockedCompareExchange((lock), 1, 0)) \ - NdisStallExecution(1); -#define IFUNLOCK(lock) InterlockedExchange((lock), 0) -#define IFLOCK_FREE(lock) -#define FW_SUPPORTED(dhd, capa) ((strstr(dhd->fw_capabilities, " " #capa " ") != NULL)) -#ifdef ARP_OFFLOAD_SUPPORT -#define MAX_IPV4_ENTRIES 8 -void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode); -void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable); - -/* dhd_commn arp offload wrapers */ -void dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx); -void dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx); -int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx); -void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx); -#endif /* ARP_OFFLOAD_SUPPORT */ -#ifdef WLTDLS -int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac); -int dhd_tdls_set_mode(dhd_pub_t *dhd, bool wfd_mode); -#ifdef PCIE_FULL_DONGLE -int dhd_tdls_update_peer_info(dhd_pub_t *dhdp, wl_event_msg_t *event); -int dhd_tdls_event_handler(dhd_pub_t *dhd_pub, wl_event_msg_t *event); -int dhd_free_tdls_peer_list(dhd_pub_t *dhd_pub); -#endif /* PCIE_FULL_DONGLE */ -#endif /* WLTDLS */ - -/* Neighbor Discovery Offload Support */ -extern int dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable); -int dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipaddr, int idx); -int dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx); - -/* Enhanced ND offload support */ -uint16 dhd_ndo_get_version(dhd_pub_t *dhdp); -int dhd_ndo_add_ip_with_type(dhd_pub_t *dhdp, char *ipv6addr, uint8 type, int idx); -int dhd_ndo_remove_ip_by_addr(dhd_pub_t *dhdp, char *ipv6addr, int idx); -int dhd_ndo_remove_ip_by_type(dhd_pub_t *dhdp, uint8 type, int idx); -int dhd_ndo_unsolicited_na_filter_enable(dhd_pub_t *dhdp, int enable); - -/* ioctl processing for nl80211 */ -int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, struct dhd_ioctl *ioc, void *data_buf); - -void dhd_bus_update_fw_nv_path(struct dhd_bus *bus, char *pfw_path, char *pnv_path, - char *pclm_path, char *pconf_path, char *preg_path); -void dhd_set_bus_state(void *bus, uint32 state); - -/* Remove proper pkts(either one no-frag pkt or whole fragmented pkts) */ -typedef int (*f_droppkt_t)(dhd_pub_t *dhdp, int prec, void* p, bool bPktInQ); -extern bool dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_droppkt_t fn); - -#ifdef PROP_TXSTATUS -int dhd_os_wlfc_block(dhd_pub_t *pub); -int dhd_os_wlfc_unblock(dhd_pub_t *pub); -extern const uint8 prio2fifo[]; -#endif /* PROP_TXSTATUS */ - -int dhd_os_socram_dump(struct net_device *dev, uint32 *dump_size); -int dhd_os_get_socram_dump(struct net_device *dev, char **buf, uint32 *size); -int dhd_common_socram_dump(dhd_pub_t *dhdp); - -int dhd_os_get_version(struct net_device *dev, bool dhd_ver, char **buf, uint32 size); - -uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail); -void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size); - -#if defined(CONFIG_DHD_USE_STATIC_BUF) -#define DHD_OS_PREALLOC(dhdpub, section, size) dhd_os_prealloc(dhdpub, section, size, FALSE) -#define DHD_OS_PREFREE(dhdpub, addr, size) dhd_os_prefree(dhdpub, addr, size) -#else -#define DHD_OS_PREALLOC(dhdpub, section, size) MALLOC(dhdpub->osh, size) -#define DHD_OS_PREFREE(dhdpub, addr, size) MFREE(dhdpub->osh, addr, size) -#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */ - -#ifdef USE_WFA_CERT_CONF -enum { - SET_PARAM_BUS_TXGLOM_MODE, - SET_PARAM_ROAMOFF, -#ifdef USE_WL_FRAMEBURST - SET_PARAM_FRAMEBURST, -#endif /* USE_WL_FRAMEBURST */ -#ifdef USE_WL_TXBF - SET_PARAM_TXBF, -#endif /* USE_WL_TXBF */ -#ifdef PROP_TXSTATUS - SET_PARAM_PROPTX, - SET_PARAM_PROPTXMODE, -#endif /* PROP_TXSTATUS */ - PARAM_LAST_VALUE -}; -extern int sec_get_param_wfa_cert(dhd_pub_t *dhd, int mode, uint* read_val); -#endif /* USE_WFA_CERT_CONF */ - -#define dhd_add_flowid(pub, ifidx, ac_prio, ea, flowid) do {} while (0) -#define dhd_del_flowid(pub, ifidx, flowid) do {} while (0) -bool dhd_wet_chainable(dhd_pub_t *dhdp); - -extern unsigned long dhd_os_general_spin_lock(dhd_pub_t *pub); -extern void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags); - -/** Miscellaenous DHD Spin Locks */ - -/* Disable router 3GMAC bypass path perimeter lock */ -#define DHD_PERIM_LOCK(dhdp) do {} while (0) -#define DHD_PERIM_UNLOCK(dhdp) do {} while (0) -#define DHD_PERIM_LOCK_ALL(processor_id) do {} while (0) -#define DHD_PERIM_UNLOCK_ALL(processor_id) do {} while (0) - -/* Enable DHD general spin lock/unlock */ -#define DHD_GENERAL_LOCK(dhdp, flags) \ - (flags) = dhd_os_general_spin_lock(dhdp) -#define DHD_GENERAL_UNLOCK(dhdp, flags) \ - dhd_os_general_spin_unlock((dhdp), (flags)) - -/* Enable DHD timer spin lock/unlock */ -#define DHD_TIMER_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) -#define DHD_TIMER_UNLOCK(lock, flags) dhd_os_spin_unlock(lock, (flags)) - -/* Enable DHD flowring spin lock/unlock */ -#define DHD_FLOWRING_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) -#define DHD_FLOWRING_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags)) - -/* Enable DHD common flowring info spin lock/unlock */ -#define DHD_FLOWID_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) -#define DHD_FLOWID_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags)) - -/* Enable DHD common flowring list spin lock/unlock */ -#define DHD_FLOWRING_LIST_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) -#define DHD_FLOWRING_LIST_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags)) - -#define DHD_SPIN_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) -#define DHD_SPIN_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags)) - -#define DHD_BUS_INB_DW_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) -#define DHD_BUS_INB_DW_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags)) - -/* Enable DHD TDLS peer list spin lock/unlock */ -#ifdef WLTDLS -#define DHD_TDLS_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) -#define DHD_TDLS_UNLOCK(lock, flags) dhd_os_spin_unlock((lock), (flags)) -#endif /* WLTDLS */ - -#ifdef DBG_PKT_MON -/* Enable DHD PKT MON spin lock/unlock */ -#define DHD_PKT_MON_LOCK(lock, flags) (flags) = dhd_os_spin_lock(lock) -#define DHD_PKT_MON_UNLOCK(lock, flags) dhd_os_spin_unlock(lock, (flags)) -#endif /* DBG_PKT_MON */ - -#define DHD_LINUX_GENERAL_LOCK(dhdp, flags) DHD_GENERAL_LOCK(dhdp, flags) -#define DHD_LINUX_GENERAL_UNLOCK(dhdp, flags) DHD_GENERAL_UNLOCK(dhdp, flags) - -extern void dhd_dump_to_kernelog(dhd_pub_t *dhdp); - -#ifdef BCMDBUS -extern uint dhd_get_rxsz(dhd_pub_t *pub); -extern void dhd_set_path(dhd_pub_t *pub); -extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); -extern void dhd_bus_clearcounts(dhd_pub_t *dhdp); -#endif /* BCMDBUS */ - -#ifdef DHD_L2_FILTER -extern int dhd_get_parp_status(dhd_pub_t *dhdp, uint32 idx); -extern int dhd_set_parp_status(dhd_pub_t *dhdp, uint32 idx, int val); -extern int dhd_get_dhcp_unicast_status(dhd_pub_t *dhdp, uint32 idx); -extern int dhd_set_dhcp_unicast_status(dhd_pub_t *dhdp, uint32 idx, int val); -extern int dhd_get_block_ping_status(dhd_pub_t *dhdp, uint32 idx); -extern int dhd_set_block_ping_status(dhd_pub_t *dhdp, uint32 idx, int val); -extern int dhd_get_grat_arp_status(dhd_pub_t *dhdp, uint32 idx); -extern int dhd_set_grat_arp_status(dhd_pub_t *dhdp, uint32 idx, int val); -#endif /* DHD_L2_FILTER */ - - -typedef struct wl_io_pport { - dhd_pub_t *dhd_pub; - uint ifidx; -} wl_io_pport_t; - -typedef struct wl_evt_pport { - dhd_pub_t *dhd_pub; - int *ifidx; - void *pktdata; - uint data_len; - void **data_ptr; - void *raw_event; -} wl_evt_pport_t; - -extern void *dhd_pub_shim(dhd_pub_t *dhd_pub); -#ifdef DHD_FW_COREDUMP -void* dhd_get_fwdump_buf(dhd_pub_t *dhd_pub, uint32 length); -#endif /* DHD_FW_COREDUMP */ - -#if defined(SET_RPS_CPUS) -int dhd_rps_cpus_enable(struct net_device *net, int enable); -int custom_rps_map_set(struct netdev_rx_queue *queue, char *buf, size_t len); -void custom_rps_map_clear(struct netdev_rx_queue *queue); -#define PRIMARY_INF 0 -#define VIRTUAL_INF 1 -#if defined(CONFIG_MACH_UNIVERSAL5433) || defined(CONFIG_MACH_UNIVERSAL7420) || \ - defined(CONFIG_SOC_EXYNOS8890) -#define RPS_CPUS_MASK "10" -#define RPS_CPUS_MASK_P2P "10" -#define RPS_CPUS_MASK_IBSS "10" -#define RPS_CPUS_WLAN_CORE_ID 4 -#else -#define RPS_CPUS_MASK "6" -#define RPS_CPUS_MASK_P2P "6" -#define RPS_CPUS_MASK_IBSS "6" -#endif /* CONFIG_MACH_UNIVERSAL5433 || CONFIG_MACH_UNIVERSAL7420 || CONFIG_SOC_EXYNOS8890 */ -#endif - -int dhd_get_download_buffer(dhd_pub_t *dhd, char *file_path, download_type_t component, - char ** buffer, int *length); - -void dhd_free_download_buffer(dhd_pub_t *dhd, void *buffer, int length); - -int dhd_download_blob(dhd_pub_t *dhd, unsigned char *image, - uint32 len, char *iovar); - -int dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path); - -#ifdef SHOW_LOGTRACE -int dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size, - dhd_event_log_t *event_log); -int dhd_parse_map_file(osl_t *osh, void *file, uint32 *ramstart, - uint32 *rodata_start, uint32 *rodata_end); -#ifdef PCIE_FULL_DONGLE -int dhd_event_logtrace_infobuf_pkt_process(dhd_pub_t *dhdp, void *pktbuf, - dhd_event_log_t *event_data); -#endif /* PCIE_FULL_DONGLE */ -#endif /* SHOW_LOGTRACE */ - -#define dhd_is_device_removed(x) FALSE -#define dhd_os_ind_firmware_stall(x) - -#if defined(DHD_FW_COREDUMP) -extern void dhd_get_memdump_info(dhd_pub_t *dhd); -#endif /* defined(DHD_FW_COREDUMP) */ -#ifdef BCMASSERT_LOG -extern void dhd_get_assert_info(dhd_pub_t *dhd); -#else -static INLINE void dhd_get_assert_info(dhd_pub_t *dhd) { } -#endif /* BCMASSERT_LOG */ - -#define DMAXFER_FREE(dhdp, dmap) dhd_schedule_dmaxfer_free(dhdp, dmap); - -#if defined(PCIE_FULL_DONGLE) -extern void dmaxfer_free_prev_dmaaddr(dhd_pub_t *dhdp, dmaxref_mem_map_t *dmmap); -void dhd_schedule_dmaxfer_free(dhd_pub_t *dhdp, dmaxref_mem_map_t *dmmap); -#endif /* PCIE_FULL_DONGLE */ - -#define DHD_LB_STATS_NOOP do { /* noop */ } while (0) -#if defined(DHD_LB_STATS) -#include <bcmutils.h> -extern void dhd_lb_stats_init(dhd_pub_t *dhd); -extern void dhd_lb_stats_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); -extern void dhd_lb_stats_update_napi_histo(dhd_pub_t *dhdp, uint32 count); -extern void dhd_lb_stats_update_txc_histo(dhd_pub_t *dhdp, uint32 count); -extern void dhd_lb_stats_update_rxc_histo(dhd_pub_t *dhdp, uint32 count); -extern void dhd_lb_stats_txc_percpu_cnt_incr(dhd_pub_t *dhdp); -extern void dhd_lb_stats_rxc_percpu_cnt_incr(dhd_pub_t *dhdp); -#define DHD_LB_STATS_INIT(dhdp) dhd_lb_stats_init(dhdp) -#define DHD_LB_STATS_DEINIT(dhdp) dhd_lb_stats_deinit(dhdp) -/* Reset is called from common layer so it takes dhd_pub_t as argument */ -#define DHD_LB_STATS_RESET(dhdp) dhd_lb_stats_init(dhdp) -#define DHD_LB_STATS_CLR(x) (x) = 0U -#define DHD_LB_STATS_INCR(x) (x) = (x) + 1 -#define DHD_LB_STATS_ADD(x, c) (x) = (x) + (c) -#define DHD_LB_STATS_PERCPU_ARR_INCR(x) \ - { \ - int cpu = get_cpu(); put_cpu(); \ - DHD_LB_STATS_INCR(x[cpu]); \ - } -#define DHD_LB_STATS_UPDATE_NAPI_HISTO(dhdp, x) dhd_lb_stats_update_napi_histo(dhdp, x) -#define DHD_LB_STATS_UPDATE_TXC_HISTO(dhdp, x) dhd_lb_stats_update_txc_histo(dhdp, x) -#define DHD_LB_STATS_UPDATE_RXC_HISTO(dhdp, x) dhd_lb_stats_update_rxc_histo(dhdp, x) -#define DHD_LB_STATS_TXC_PERCPU_CNT_INCR(dhdp) dhd_lb_stats_txc_percpu_cnt_incr(dhdp) -#define DHD_LB_STATS_RXC_PERCPU_CNT_INCR(dhdp) dhd_lb_stats_rxc_percpu_cnt_incr(dhdp) -#else /* !DHD_LB_STATS */ -#define DHD_LB_STATS_INIT(dhdp) DHD_LB_STATS_NOOP -#define DHD_LB_STATS_DEINIT(dhdp) DHD_LB_STATS_NOOP -#define DHD_LB_STATS_RESET(dhdp) DHD_LB_STATS_NOOP -#define DHD_LB_STATS_CLR(x) DHD_LB_STATS_NOOP -#define DHD_LB_STATS_INCR(x) DHD_LB_STATS_NOOP -#define DHD_LB_STATS_ADD(x, c) DHD_LB_STATS_NOOP -#define DHD_LB_STATS_PERCPU_ARR_INCR(x) DHD_LB_STATS_NOOP -#define DHD_LB_STATS_UPDATE_NAPI_HISTO(dhd, x) DHD_LB_STATS_NOOP -#define DHD_LB_STATS_UPDATE_TXC_HISTO(dhd, x) DHD_LB_STATS_NOOP -#define DHD_LB_STATS_UPDATE_RXC_HISTO(dhd, x) DHD_LB_STATS_NOOP -#define DHD_LB_STATS_TXC_PERCPU_CNT_INCR(dhdp) DHD_LB_STATS_NOOP -#define DHD_LB_STATS_RXC_PERCPU_CNT_INCR(dhdp) DHD_LB_STATS_NOOP -#endif /* !DHD_LB_STATS */ - -#ifdef DHD_SSSR_DUMP -#define DHD_SSSR_MEMPOOL_SIZE (1024 * 1024) /* 1MB size */ -extern int dhd_sssr_mempool_init(dhd_pub_t *dhd); -extern void dhd_sssr_mempool_deinit(dhd_pub_t *dhd); -extern int dhd_sssr_dump_init(dhd_pub_t *dhd); -extern void dhd_sssr_dump_deinit(dhd_pub_t *dhd); -#define DHD_SSSR_MEMPOOL_INIT(dhdp) dhd_sssr_mempool_init(dhdp) -#define DHD_SSSR_MEMPOOL_DEINIT(dhdp) dhd_sssr_mempool_deinit(dhdp) -#define DHD_SSSR_DUMP_INIT(dhdp) dhd_sssr_dump_init(dhdp) -#define DHD_SSSR_DUMP_DEINIT(dhdp) dhd_sssr_dump_deinit(dhdp) -#else -#define DHD_SSSR_MEMPOOL_INIT(dhdp) do { /* noop */ } while (0) -#define DHD_SSSR_MEMPOOL_DEINIT(dhdp) do { /* noop */ } while (0) -#define DHD_SSSR_DUMP_INIT(dhdp) do { /* noop */ } while (0) -#define DHD_SSSR_DUMP_DEINIT(dhdp) do { /* noop */ } while (0) -#endif /* DHD_SSSR_DUMP */ - -#ifdef SHOW_LOGTRACE -void dhd_get_read_buf_ptr(dhd_pub_t *dhd_pub, trace_buf_info_t *read_buf_info); -#endif /* SHOW_LOGTRACE */ - -#ifdef BCMPCIE -extern int dhd_prot_debug_info_print(dhd_pub_t *dhd); -#else -#define dhd_prot_debug_info_print(x) -#endif /* BCMPCIE */ - -extern bool dhd_prot_is_cmpl_ring_empty(dhd_pub_t *dhd, void *prot_info); - -bool dhd_fw_download_status(dhd_pub_t * dhd_pub); - -/* Bitmask used for Join Timeout */ -#define WLC_SSID_MASK 0x01 -#define WLC_WPA_MASK 0x02 - -extern int dhd_start_join_timer(dhd_pub_t *pub); -extern int dhd_stop_join_timer(dhd_pub_t *pub); -extern int dhd_start_scan_timer(dhd_pub_t *pub); -extern int dhd_stop_scan_timer(dhd_pub_t *pub); -extern int dhd_start_cmd_timer(dhd_pub_t *pub); -extern int dhd_stop_cmd_timer(dhd_pub_t *pub); -extern int dhd_start_bus_timer(dhd_pub_t *pub); -extern int dhd_stop_bus_timer(dhd_pub_t *pub); -extern uint16 dhd_get_request_id(dhd_pub_t *pub); -extern int dhd_set_request_id(dhd_pub_t *pub, uint16 id, uint32 cmd); -extern void dhd_set_join_error(dhd_pub_t *pub, uint32 mask); -extern void dhd_clear_join_error(dhd_pub_t *pub, uint32 mask); -extern void dhd_get_scan_to_val(dhd_pub_t *pub, uint32 *to_val); -extern void dhd_set_scan_to_val(dhd_pub_t *pub, uint32 to_val); -extern void dhd_get_join_to_val(dhd_pub_t *pub, uint32 *to_val); -extern void dhd_set_join_to_val(dhd_pub_t *pub, uint32 to_val); -extern void dhd_get_cmd_to_val(dhd_pub_t *pub, uint32 *to_val); -extern void dhd_set_cmd_to_val(dhd_pub_t *pub, uint32 to_val); -extern void dhd_get_bus_to_val(dhd_pub_t *pub, uint32 *to_val); -extern void dhd_set_bus_to_val(dhd_pub_t *pub, uint32 to_val); -extern int dhd_start_timesync_timer(dhd_pub_t *pub); -extern int dhd_stop_timesync_timer(dhd_pub_t *pub); - -#ifdef DHD_PKTID_AUDIT_ENABLED -void dhd_pktid_error_handler(dhd_pub_t *dhdp); -#endif /* DHD_PKTID_AUDIT_ENABLED */ - -#ifdef DHD_PCIE_RUNTIMEPM -extern bool dhd_runtimepm_state(dhd_pub_t *dhd); -extern bool dhd_runtime_bus_wake(struct dhd_bus *bus, bool wait, void *func_addr); -extern bool dhdpcie_runtime_bus_wake(dhd_pub_t *dhdp, bool wait, void *func_addr); -extern void dhdpcie_block_runtime_pm(dhd_pub_t *dhdp); -extern bool dhdpcie_is_resume_done(dhd_pub_t *dhdp); -extern void dhd_runtime_pm_disable(dhd_pub_t *dhdp); -extern void dhd_runtime_pm_enable(dhd_pub_t *dhdp); -/* Disable the Runtime PM and wake up if the bus is already in suspend */ -#define DHD_DISABLE_RUNTIME_PM(dhdp) \ -do { \ - dhd_runtime_pm_disable(dhdp); \ -} while (0); - -/* Enable the Runtime PM */ -#define DHD_ENABLE_RUNTIME_PM(dhdp) \ -do { \ - dhd_runtime_pm_enable(dhdp); \ -} while (0); -#else -#define DHD_DISABLE_RUNTIME_PM(dhdp) -#define DHD_ENABLE_RUNTIME_PM(dhdp) -#endif /* DHD_PCIE_RUNTIMEPM */ - -/* - * Enable this macro if you want to track the calls to wake lock - * This records can be printed using the following command - * cat /sys/bcm-dhd/wklock_trace - * DHD_TRACE_WAKE_LOCK supports over linux 2.6.0 version - */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) -#undef DHD_TRACE_WAKE_LOCK -#endif /* KERNEL_VER < KERNEL_VERSION(2, 6, 0) */ - -#if defined(DHD_TRACE_WAKE_LOCK) -void dhd_wk_lock_stats_dump(dhd_pub_t *dhdp); -#endif - -extern bool dhd_query_bus_erros(dhd_pub_t *dhdp); - -extern void init_dhd_timeouts(dhd_pub_t *pub); -extern void deinit_dhd_timeouts(dhd_pub_t *pub); - -typedef enum timeout_resons { - DHD_REASON_COMMAND_TO, - DHD_REASON_JOIN_TO, - DHD_REASON_SCAN_TO, - DHD_REASON_OQS_TO -} timeout_reasons_t; - -#if defined(PCIE_OOB) || defined(PCIE_INB_DW) -extern int dhd_bus_set_device_wake(struct dhd_bus *bus, bool val); -#endif /* defined(PCIE_OOB) || defined(PCIE_INB_DW) */ - -#ifdef DHD_EFI -extern void dhd_schedule_reset(dhd_pub_t *dhdp); -#else -static INLINE void dhd_schedule_reset(dhd_pub_t *dhdp) {;} -#endif - -#ifdef ENABLE_TEMP_THROTTLING -#ifndef TEMP_THROTTLE_CONTROL_BIT -#define TEMP_THROTTLE_CONTROL_BIT 0xd -#endif -#endif /* ENABLE_TEMP_THROTTLING */ - -int dhd_send_msg_to_daemon(struct sk_buff *skb, void *data, int size); -#ifdef REPORT_FATAL_TIMEOUTS -void dhd_send_trap_to_fw_for_timeout(dhd_pub_t * pub, timeout_reasons_t reason); -#endif - -#if defined(CONFIG_64BIT) -#define DHD_SUPPORT_64BIT -#elif defined(DHD_EFI) -#define DHD_SUPPORT_64BIT -/* by default disabled for other platforms, can enable appropriate macro to enable 64 bit support */ -#endif /* (linux || LINUX) && CONFIG_64BIT */ - -#ifdef SET_PCIE_IRQ_CPU_CORE -extern void dhd_set_irq_cpucore(dhd_pub_t *dhdp, int set); -extern void set_irq_cpucore(unsigned int irq, int set); -#endif /* SET_PCIE_IRQ_CPU_CORE */ -#if defined(DHD_HANG_SEND_UP_TEST) -extern void dhd_make_hang_with_reason(struct net_device *dev, const char *string_num); -#endif /* DHD_HANG_SEND_UP_TEST */ - -#if defined(DHD_BLOB_EXISTENCE_CHECK) -extern void dhd_set_blob_support(dhd_pub_t *dhdp, char *fw_path); -#endif /* DHD_BLOB_EXISTENCE_CHECK */ - -#ifdef DHD_WAKE_STATUS -wake_counts_t* dhd_get_wakecount(dhd_pub_t *dhdp); -#endif /* DHD_WAKE_STATUS */ - -#ifdef BCM_ASLR_HEAP -extern uint32 dhd_get_random_number(void); -#endif /* BCM_ASLR_HEAP */ - -/* Use for SDIO reconnect */ -extern int dhd_chip_alive; - -#ifdef SCHED_WAKE -extern int dhd_sched_wake_setup(dhd_pub_t *dhdp, uint32 reason); -#endif /* SCHED_WAKE */ - -#ifdef SCHED_WAKE -#define SCHEDWAKE_RSN_EVTDATA 0x01 -#define SCHEDWAKE_RSN_TCPKA_NOTRDY 0x02 -#define SCHEDWAKE_RSN_PENDING_WAKE 0x04 - -typedef struct { - uint32 wake_time; - uint32 reason; -} sched_wake_param_t; -#endif /* SCHED_WAKE */ - -#define REG_LOCATION_UNKNOWN -1 -#define REG_LOCATION_INDOOR 0 -#define REG_LOCATION_OUTDOOR 1 -typedef struct { - char ccode[WLC_CNTRY_BUF_SZ]; - int location; -} reg_location_t; - -enum dhd_load_mode { - DHD_LOAD_MODE_COLD, - DHD_LOAD_MODE_PARTIAL, - DHD_LOAD_MODE_WARM, -}; -extern int dhd_load_mode; -#ifdef RELOAD_WIFI -#define FW_RELOAD_BACKOFF_UNIT_SEC 3600 -#define FW_RELOAD_BACKOFF_MAX_INCR_CNT 3 -enum fw_reload_mode { - NO_FW_RELOAD = 0, - FW_RELOAD_NEEDED, - FW_RELOADED, -}; -#define FW_RECOVER_BASE_RELOAD 10 -#define FW_RECOVER_BASE_DISASSOC 0 -#endif /* RELOAD_WIFI */ -#endif /* _dhd_h_ */
diff --git a/bcmdhd.1.579.77.41.x/dhd_bcol_tcpka.h b/bcmdhd.1.579.77.41.x/dhd_bcol_tcpka.h deleted file mode 100644 index 15eedf6..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_bcol_tcpka.h +++ /dev/null
@@ -1,169 +0,0 @@ -/* - * Header file describing the BCOL TCPKA interfaces. - * - * Provides type definitions and function prototypes used to link the - * DHD OS, bus, and protocol modules. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id:$ - */ - -#ifndef _DHD_BCOL_TCPKA_ -#define _DHD_BCOL_TCPKA_ - -#include <typedefs.h> -#include <osl.h> - -typedef struct tcpka_conn { - uint32 sess_id; - struct ether_addr dst_mac; - struct ipv4_addr src_ip; - struct ipv4_addr dst_ip; - uint16 ipid; - uint16 srcport; - uint16 dstport; - uint32 seq; - uint32 ack; - uint16 tcpwin; - uint32 tsval; - uint32 tsecr; -#ifdef TCPKA_BYPASS - bool bypass; /* bypass tcpka pkt to pkt filter process */ -#endif /* TCPKA_BYPASS */ - uint32 last_payload_len; /* last packet payload len */ - uint32 ka_payload_len; /* keep alive payload length */ - uint8 ka_payload[1]; /* keep alive payload */ -} tcpka_conn_t; - -typedef struct tcpka6_conn { - uint32 sess_id; - struct ether_addr dst_mac; - uint8 src_ip[IPV6_ADDR_LEN]; - uint8 dst_ip[IPV6_ADDR_LEN]; - uint32 type; - uint16 srcport; - uint16 dstport; - uint32 seq; - uint32 ack; - uint16 tcpwin; - uint32 tsval; - uint32 tsecr; -#ifdef TCPKA_BYPASS - bool bypass; /* bypass tcpka pkt to pkt filter process */ -#endif /* TCPKA_BYPASS */ - uint32 last_payload_len; /* last packet payload len */ - uint32 ka_payload_len; /* keep alive payload length */ - uint8 ka_payload[1]; /* keep alive payload */ -} tcpka6_conn_t; - -typedef struct tcpka_conn_sess { - uint32 sess_id; - uint32 flag; - wl_mtcpkeep_alive_timers_pkt_t tcp_keepalive_timers; - uint32 snd_wl1; - uint32 snd_wnd; - uint32 max_window; - uint32 rcv_wnd; - uint32 rcv_wup; - uint16 mss; - uint8 snd_wscale; - uint8 rcv_wscale; - uint8 tcpi_options; -} tcpka_conn_sess_t; - -typedef struct tcpka_conn_info { - uint32 tcpka_sess_ipid; - uint32 tcpka_sess_seq; - uint32 tcpka_sess_ack; - bool tcpka_sess_active; -} tcpka_conn_sess_info_t; - -#define max_tcpka_slen 128 - -typedef struct tcpka_conn_send { - uint32 tcpka_sess_ipid; - uint16 send_type; - uint16 send_length; - uint8 send_data[max_tcpka_slen]; /* keep alive payload */ -} tcpka_conn_sess_send_t; - -typedef struct tcpka_conn_reinit { - uint32 tcpka_sess_ipid; - uint8 enable; - uint8 tcpka_handshake_timeout; - uint16 tcpka_timeout_trigger; -} tcpka_conn_sess_reinit_t; - -#ifdef TCPKA_REPAIR -typedef struct tcpka_conn_repair { - bool block_tcpka; - uint16 block_tcpka_timeout; //sec - uint32 block_tcpka_start_time; //timestamp - void *skbhead; - void *skbprev; - uint32 pkt_in_q_num; - bool configured; - uint32 src_ip; - uint32 dst_ip; - uint16 src_port; - uint16 dst_port; -} tcpka_conn_repair_t; - -/* Pkttag format for skb->cb of rx */ -typedef struct dhd_pkttag_rx { - bool queue_needed; - uint8 ifidx; -} dhd_pkttag_rx_t; - -typedef struct noti_pkt_hold { - int8 type; - uint16 min_len; - uint16 max_len; -} tcpka_noti_pkt_hold_t; - -typedef struct noti_payload { - uint8 tcpka_sess_id; - uint8 gpio_slot; - uint8 type; - uint16 noti_len; - uint8 noti_data[1]; -} wifi_noti_payload_t; -#define DHD_PKTTAG_SET_QUEUED(tag, val) ((tag)->queue_needed = (uint8)(val)) -#define DHD_PKTTAG_QUEUED(tag) ((tag)->queue_needed) - -#define DHD_PKTTAG_SET_IFIDX(tag, val) ((tag)->ifidx = (uint8)(val)) -#define DHD_PKTTAG_IFIDX(tag) ((tag)->ifidx) - -#endif /* TCPKA_REPAIR */ - -/* FW BCOL TCPKA IOVARs */ -#define CMD_STR_TCPKA_CONN_EN "tcpka_conn_enable" -#define CMD_STR_TCPKA_CONN_ADD "tcpka_conn_add" -#define CMD_STR_TCPKA_CONN_DEL "tcpka_conn_del" -#define CMD_STR_TCPKA6_CONN_ADD "tcpka6_conn_add" -/* DHD only IOVAR */ -#define CMD_STR_TCPKA_CONN_SYNC "tcpka_conn_sync" - -#endif /* _DHD_BCOL_TCPKA_ */
diff --git a/bcmdhd.1.579.77.41.x/dhd_bcol_tcpka_pub.h b/bcmdhd.1.579.77.41.x/dhd_bcol_tcpka_pub.h deleted file mode 100644 index 29b96ab..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_bcol_tcpka_pub.h +++ /dev/null
@@ -1,476 +0,0 @@ -/* - * Header file describing the BCOL TCPKA interfaces/public functions - * - * Provides type definitions and function prototypes used to link the - * DHD OS, bus, and protocol modules. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id:$ - */ - -#ifndef _DHD_BCOL_TCPKA_PUB_ -#define _DHD_BCOL_TCPKA_PUB_ - -#include <typedefs.h> -#include <osl.h> -#include <dhd_bcol_tcpka.h> -#include <bcmtcp.h> -#include <dhd_ip.h> -#include <dhd.h> - -#ifdef TCPKA_DEBUG -#define DHD_TCPKA_INFO(x) printf x -#else -#define DHD_TCPKA_INFO(x) -#endif - -enum { - BCOL_TCPKA_SYNC_MODE_OFF = 0, - BCOL_TCPKA_SYNC_MODE_ON -}; - -enum { - BCOL_TCPKA_SYNC_STATE_NONE = 0, - BCOL_TCPKA_SYNC_STATE_TRAC, - BCOL_TCPKA_SYNC_STATE_READY, - BCOL_TCPKA_SYNC_STATE_BUSY, - BCOL_TCPKA_SYNC_STATE_DONE -}; - -typedef struct { - uint8 sess_id; - uint8 gpio_slot; - uint8 type; - uint16 len; - uint8 data[1]; -} tcpka_noti_cfg_t; - -#define TCPKA_NOTI_BLOCK_ALL -2 - -#ifdef TCPKA_DEBUG -static inline char * -dhd_bcol_ipv6_ntoa(uint8 *ia, char *buf) -{ - snprintf(buf, 64, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:" - "%02x%02x:%02x%02x:%02x%02x:%02x%02x", - ia[0], ia[1], ia[2], ia[3], ia[4], ia[5], ia[6], ia[7], - ia[8], ia[9], ia[10], ia[11], ia[12], ia[13], ia[14], ia[15]); - - return (buf); -} - -static inline void dhd_bcol_dump_tcpka6_conn(tcpka6_conn_t *tcpka) -{ - uint8 ipbuf[64]; - printf("%s: dump %s:\n", __func__, CMD_STR_TCPKA6_CONN_ADD); - printf("sess_id=%d, dst_mac=%02x:%02x:%02x:%02x:%02x:%02x\n", tcpka->sess_id, - tcpka->dst_mac.octet[0], tcpka->dst_mac.octet[1], - tcpka->dst_mac.octet[2], tcpka->dst_mac.octet[3], - tcpka->dst_mac.octet[4], tcpka->dst_mac.octet[5]); - printf("srcip=%s dstip=%s", dhd_bcol_ipv6_ntoa((uint8 *)&tcpka->src_ip, ipbuf), - dhd_bcol_ipv6_ntoa((uint8 *)&tcpka->dst_ip, ipbuf)); - printf("srcport=%d, dstport=%d, seq=%u, ack=%u\n", - tcpka->srcport, tcpka->dstport, tcpka->seq, tcpka->ack); - printf("window=%u, tsval=%u, tsecr=%u, last_payload_len=%u\n", - tcpka->tcpwin, tcpka->tsval, tcpka->tsecr, tcpka->last_payload_len); - printf("ka_payload_len=%d\n", tcpka->ka_payload_len); -} - -static inline void dhd_bcol_dump_tcpka_conn(tcpka_conn_t *tcpka) -{ - printf("%s: dump %s:\n", __func__, CMD_STR_TCPKA_CONN_ADD); - printf("sess_id=%d, dst_mac=%02x:%02x:%02x:%02x:%02x:%02x\n", tcpka->sess_id, - tcpka->dst_mac.octet[0], tcpka->dst_mac.octet[1], - tcpka->dst_mac.octet[2], tcpka->dst_mac.octet[3], - tcpka->dst_mac.octet[4], tcpka->dst_mac.octet[5]); - printf("ipid=%u, srcport=%d, dstport=%d, seq=%u, ack=%u\n", - tcpka->ipid, tcpka->srcport, tcpka->dstport, tcpka->seq, tcpka->ack); - printf("window=%u, tsval=%u, tsecr=%u, last_payload_len=%u\n", - tcpka->tcpwin, tcpka->tsval, tcpka->tsecr, tcpka->last_payload_len); - printf("ka_payload_len=%d\n", tcpka->ka_payload_len); -} - -static inline void dhd_bcol_dump_tcpka_conn_sess(tcpka_conn_sess_t *tcpka) -{ - printf("%s: dump %s:\n", __func__, CMD_STR_TCPKA_CONN_EN); - printf("sess_id=%d, flag=%x\n", tcpka->sess_id, tcpka->flag); - if (tcpka->flag) { - printf("tcp keepalive timers:interval=%d\n", tcpka->tcp_keepalive_timers.interval); - printf("retry_interval=%d. retry_count=%d\n", - tcpka->tcp_keepalive_timers.retry_interval, - tcpka->tcp_keepalive_timers.retry_count); - } -} -#else -#define dhd_bcol_dump_tcpka_conn(x) -#define dhd_bcol_dump_tcpka6_conn(x) -#define dhd_bcol_dump_tcpka_conn_sess(x) -#endif /* TCPKA_DEBUG */ - -static inline int dhd_bcol_tcpka_check_xmit(dhd_pub_t *dhdp, void *pkt) -{ - uint8 *new_ether_hdr; /* Ethernet header of the new packet */ - uint16 new_ether_type; /* Ethernet type of the new packet */ - uint8 *new_ip_hdr; /* IP header of the new packet */ - uint8 *new_tcp_hdr; /* TCP header of the new packet */ - uint32 new_ip_hdr_len; /* IP header length of the new packet */ - uint32 cur_framelen; - uint16 new_ip_total_len; /* Total length of IP packet for the new packet */ - uint16 new_ip_payload_len; /* Total payload length of IPv6 packet for the new packet */ - uint32 new_tcp_hdr_len; /* TCP header length of the new packet */ - uint32 tcp_option_len; - tcpka_conn_t *tcpka, tcpka_orig; - tcpka6_conn_t *tcpka6, tcpka6_orig; - struct tcphdr *tcph; /* TCP header */ - uint8 *payload; /* TCP data begin pointer */ - uint16 last_payload_len = 0; - - cur_framelen = PKTLEN(dhdp->osh, pkt); - - if (tcpka_sync.tcpka_sync_mode == BCOL_TCPKA_SYNC_MODE_OFF || - (!tcpka_sync.tcpka_conn && !tcpka_sync.tcpka6_conn)) { - if (tcpka_sync.tcpka_drop) { - DHD_ERROR(("%s: mode %d, tcpka_conn %p, tcpka6_conn %p, cur_framelen %d\n", __func__, tcpka_sync.tcpka_sync_mode, tcpka_sync.tcpka_conn, tcpka_sync.tcpka6_conn, cur_framelen)); - } - return BCME_NOTFOUND; - } - - /* config is going */ - if (tcpka_sync.tcpka_sync_state == BCOL_TCPKA_SYNC_STATE_BUSY) { - if (tcpka_sync.tcpka_drop) { - DHD_ERROR(("%s: sync state busy, cur_framelen: %d\n", __func__, cur_framelen)); - } - return BCME_BUSY; - } - - if (tcpka_sync.tcpka_sync_state == BCOL_TCPKA_SYNC_STATE_NONE) { - if (tcpka_sync.tcpka_drop) { - DHD_ERROR(("%s: sync_state %d, cur_framelen %d\n", __func__, tcpka_sync.tcpka_sync_state, cur_framelen)); - } - return BCME_NOTFOUND; - } - - /* get the right tcpka_conn for IPv6 or IPv4 */ - if (tcpka_sync.sess_type) { - tcpka6 = tcpka_sync.tcpka6_conn; - if (!tcpka6 || !tcpka6->sess_id) { - DHD_ERROR(("%s: tcpka6 config has no vaild session id\n", __func__)); - return BCME_NOTREADY; - } - memcpy(&tcpka6_orig, tcpka6, sizeof(tcpka6_conn_t)); - } else { - tcpka = tcpka_sync.tcpka_conn; - if (!tcpka || !tcpka->sess_id) { - DHD_ERROR(("%s: tcpka config has no vaild session id\n", __func__)); - return BCME_NOTREADY; - } - memcpy(&tcpka_orig, tcpka, sizeof(tcpka_conn_t)); - } - - new_ether_hdr = PKTDATA(dhdp->osh, pkt); - if (cur_framelen < TCPACKSZMIN) { - if (tcpka_sync.tcpka_drop) { - DHD_ERROR(("%s: cur_framelen: %d\n", __func__, cur_framelen)); - } - return BCME_NOTFOUND; - } - - new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13]; - if ((new_ether_type != ETHER_TYPE_IP) && (new_ether_type != ETHER_TYPE_IPV6)) { - if (tcpka_sync.tcpka_drop) { - DHD_ERROR(("%s: new_ether_type: %d, cur_framelen: %d\n", __func__, new_ether_type, cur_framelen)); - } - return BCME_NOTFOUND; - } - - new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN; - if (((IP_VER(new_ip_hdr) != IP_VER_4) || (IPV4_PROT(new_ip_hdr) != IP_PROT_TCP)) && - ((IP_VER(new_ip_hdr) != IP_VER_6) || (IPV6_PROT(new_ip_hdr) != IP_PROT_TCP))) { - if (tcpka_sync.tcpka_drop) { - DHD_ERROR(("%s: wrong ip header, cur_framelen: %d\n", __func__, cur_framelen)); - } - return BCME_NOTFOUND; - } - - new_tcp_hdr = (uint8 *)tcp_hdr((struct sk_buff *)pkt); - /* if session type is IPV4 and packet is IPv4 */ - if ((IP_VER(new_ip_hdr) == IP_VER_4) && (tcpka_sync.sess_type == 0)) { - new_ip_hdr_len = IPV4_HLEN(new_ip_hdr); -#ifdef BCOL_TCPKA_SYNC_MATCHED_BY_PORT - /* If TCP port number does not match, skip. */ - if (tcpka->srcport == 0) { - /* skip the src port match */ - uint16 srcport = ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]); - uint16 dstport = ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]); - if (dstport != tcpka->dstport) { - if (tcpka_sync.tcpka_drop) { - DHD_ERROR(("%s: wrong port dst(%d,%d), cur_framelen: %d\n", __func__, dstport, tcpka->dstport, cur_framelen)); - } - return BCME_NOTFOUND; - } - tcpka->srcport = srcport; - } else { - uint16 srcport = ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]); - uint16 dstport = ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]); - if ((srcport != tcpka->srcport) || (dstport != tcpka->dstport)) { - if (tcpka_sync.tcpka_drop) { - DHD_ERROR(("%s: wrong port src(%d, %d), dst(%d, %d), cur_framelen: %d\n", __func__, srcport, tcpka->srcport, dstport, tcpka->dstport, cur_framelen)); - } - return BCME_NOTFOUND; - } - } - memcpy(tcpka->src_ip.addr, &new_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN); - memcpy(tcpka->dst_ip.addr, &new_ip_hdr[IPV4_DEST_IP_OFFSET], IPV4_ADDR_LEN); -#else - /* If either of IP address or TCP port number does not match, skip. */ - if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET], tcpka->src_ip.addr, IPV4_ADDR_LEN) || - memcmp(&new_ip_hdr[IPV4_DEST_IP_OFFSET], tcpka->dst_ip.addr, IPV4_ADDR_LEN) || - (ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]) != tcpka->srcport) || - (ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]) != tcpka->dstport)) { - return BCME_NOTFOUND; - } -#endif /* BCOL_TCPKA_SYNC_MATCHED_BY_PORT */ - /* update the destination mac */ - memcpy(tcpka->dst_mac.octet, new_ether_hdr, ETHER_ADDR_LEN); - /* update the ID of IP */ - tcpka->ipid = ntoh16_ua(&new_ip_hdr[IPV4_ID_OFFSET]); - - DHD_TCPKA_INFO(("%s: before\n", __func__)); - dhd_bcol_dump_tcpka_conn(tcpka); - - tcpka->seq = ntoh32_ua(&new_tcp_hdr[TCP_SEQ_NUM_OFFSET]); - tcpka->ack = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]); - tcpka->tcpwin = ntoh16_ua(&new_tcp_hdr[TCP_WINDOW_OFFSET]); -#ifdef TCPKA_BYPASS - tcpka->bypass = TRUE; -#endif - } - else if ((IP_VER(new_ip_hdr) == IP_VER_6) && (tcpka_sync.sess_type == 1)) { -#ifdef BCOL_TCPKA_SYNC_MATCHED_BY_PORT - /* If TCP port number does not match, skip. */ - if (tcpka6->srcport == 0) { - /* skip the src port match */ - if ((ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]) != tcpka6->dstport)) { - if (tcpka_sync.tcpka_drop) { - DHD_ERROR(("%s: %d, wrong port, cur_framelen: %d\n", __func__, __LINE__, cur_framelen)); - } - return BCME_NOTFOUND; - } - tcpka6->srcport = ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]); - } else { - if ((ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]) != tcpka6->srcport) || - (ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]) != tcpka6->dstport)) { - if (tcpka_sync.tcpka_drop) { - DHD_ERROR(("%s: %d, wrong port, cur_framelen: %d\n", __func__, __LINE__, cur_framelen)); - } - return BCME_NOTFOUND; - } - } - /* update the dst mac, src ip, dst ip */ - memcpy(tcpka6->src_ip, &new_ip_hdr[IPV6_SRC_IP_OFFSET], IPV6_ADDR_LEN); - memcpy(tcpka6->dst_ip, &new_ip_hdr[IPV6_DEST_IP_OFFSET], IPV6_ADDR_LEN); -#else - /* If either of IP address or TCP port number does not match, skip. */ - if (memcmp(&new_ip_hdr[IPV6_SRC_IP_OFFSET], tcpka6->src_ip, IPV6_ADDR_LEN) || - memcmp(&new_ip_hdr[IPV6_DEST_IP_OFFSET], tcpka6->dst_ip, IPV6_ADDR_LEN) || - (ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]) != tcpka6->srcport) || - (ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]) != tcpka6->dstport)) { - if (tcpka_sync.tcpka_drop) { - DHD_ERROR(("%s: %d, wrong port, cur_framelen: %d\n", __func__, __LINE__, cur_framelen)); - } - return BCME_NOTFOUND; - } -#endif /* BCOL_TCPKA_SYNC_MATCHED_BY_PORT */ - memcpy(tcpka6->dst_mac.octet, new_ether_hdr, ETHER_ADDR_LEN); - - DHD_TCPKA_INFO(("%s: before\n", __func__)); - dhd_bcol_dump_tcpka6_conn(tcpka6); - - tcpka6->seq = ntoh32_ua(&new_tcp_hdr[TCP_SEQ_NUM_OFFSET]); - tcpka6->ack = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]); - tcpka6->tcpwin = ntoh16_ua(&new_tcp_hdr[TCP_WINDOW_OFFSET]); -#ifdef TCPKA_BYPASS - tcpka6->bypass = TRUE; -#endif - } - else { - DHD_TCPKA_INFO(("%s: curr sess type %d, pkt type %d. Skip it.\n", __func__, - tcpka_sync.sess_type, IP_VER(new_ip_hdr))); - if (tcpka_sync.tcpka_drop) { - DHD_ERROR(("%s: wrong pkt type %d, cur_framelen: %d\n", __func__, IP_VER(new_ip_hdr), cur_framelen)); - } - return BCME_NOTFOUND; - } - - new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]); - - /* TCP options */ - tcp_option_len = new_tcp_hdr_len - TCP_MIN_HEADER_LEN; - if (tcp_option_len) { - uint8 *new_tcp_opt_hdr = new_tcp_hdr + TCP_MIN_HEADER_LEN; - uint32 i = 0; - uint8 kind, length; - bool opt_end = false; - - do { - kind = new_tcp_opt_hdr[i]; - i++; - - switch (kind) { - case 0: /* End of option list. */ - opt_end = true; - break; - case 1: /* No operation. */ - break; - case 8: /* Timestamp */ - length = new_tcp_opt_hdr[i]; - i++; - if (length != 10) { - DHD_ERROR(("%s: tcp opt timestamp has wrong length(%d).\n", - __func__, length)); - opt_end = true; - break; - } - if (tcpka_sync.sess_type == 0) { - tcpka->tsval = ntoh32_ua(&new_tcp_opt_hdr[i]); - i+=4; - tcpka->tsecr = ntoh32_ua(&new_tcp_opt_hdr[i]); - i+=4; - } - else if (tcpka_sync.sess_type == 1) { - tcpka6->tsval = ntoh32_ua(&new_tcp_opt_hdr[i]); - i+=4; - tcpka6->tsecr = ntoh32_ua(&new_tcp_opt_hdr[i]); - i+=4; - } - break; - default: /* just skip */ - length = new_tcp_opt_hdr[i]; - i = i + 1 + length; - break; - } - - if (opt_end) break; - } while(i < tcp_option_len); - } - - /* check the sess type for IPv4 or IPv6 and set the payload len */ - if (!tcpka_sync.sess_type) { - new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]); - tcpka->last_payload_len = new_ip_total_len - (new_ip_hdr_len + new_tcp_hdr_len); - last_payload_len = tcpka->last_payload_len; - dhd_bcol_dump_tcpka_conn(tcpka); - } else if (tcpka_sync.sess_type) { - new_ip_payload_len = IPV6_PAYLOAD_LEN(new_ip_hdr); - tcpka6->last_payload_len = new_ip_payload_len - new_tcp_hdr_len; - last_payload_len = tcpka6->last_payload_len; - dhd_bcol_dump_tcpka6_conn(tcpka6); - } - DHD_TCPKA_INFO(("%s: last_payload_len %d\n", __func__, last_payload_len)); - - if (tcpka_sync.tcpka_sync_state == BCOL_TCPKA_SYNC_STATE_DONE) { - /* free all packets from target session after sync done */ - DHD_ERROR(("%s: FREE post-sync packet, payload %d\n", __func__, last_payload_len)); - return BCME_BUSY; - } - - if (tcpka_sync.tcpka_noti_capture.type != -1) { - DHD_ERROR(("%s: got len %d v%s pkt, capture_type %d\n", - __func__, - last_payload_len, - tcpka_sync.sess_type ? "6" : "4", - tcpka_sync.tcpka_noti_capture.type)); - } - - if ((last_payload_len >= 2) && - (tcpka_sync.tcpka_noti_capture.min_len <= last_payload_len) && - (tcpka_sync.tcpka_noti_capture.max_len >= last_payload_len) && - (tcpka_sync.tcpka_noti_capture.type >= 0)) { - int buflen = 0; - tcpka_noti_cfg_t *np = NULL; - uint16 weave_pkt_len = 0; - - tcph = tcp_hdr((struct sk_buff *)pkt); - /* Find tcp payload */ - payload = (unsigned char *)((unsigned char *)tcph + (tcph->doff * 4)); - //prhex("TCPDATA", payload, last_payload_len); - - weave_pkt_len = *(uint16 *)payload; - DHD_ERROR(("%s: tcpka_noti, weave_pkt_len %d, payload_len %d\n", __func__, weave_pkt_len, last_payload_len)); - if ((weave_pkt_len + 2) != last_payload_len) { - /* This TCP segment is not complete weave msg */ - goto done; - } - buflen = sizeof(tcpka_noti_cfg_t) + last_payload_len - 1; - if (tcpka_sync.tcpka_noti_buf) { - MFREE(dhdp->osh, tcpka_sync.tcpka_noti_buf, - tcpka_sync.tcpka_noti_buf_len); - tcpka_sync.tcpka_noti_buf = NULL; - } - - if (tcpka_sync.tcpka_noti_buf == NULL) - tcpka_sync.tcpka_noti_buf_len = 0; - - if ((tcpka_sync.tcpka_noti_buf = - (unsigned char *)MALLOCZ(dhdp->osh, buflen)) != NULL) { - tcpka_sync.tcpka_noti_buf_len = buflen; - - np = (tcpka_noti_cfg_t *)tcpka_sync.tcpka_noti_buf; - memset(np, 0, buflen); - np->len = last_payload_len; - memcpy(np->data, payload, last_payload_len); - np->sess_id = TCPKA_DEFAULT_SESS_ID; - np->gpio_slot = 0; - np->type = tcpka_sync.tcpka_noti_capture.type; - DHD_ERROR(("%s: Captured tcpka_noti pyaload %d bytes\n", - __func__, last_payload_len)); - } else { - DHD_ERROR(("%s: Failed to allocate memory %d bytes " - "for tcpka noti buf\n", __func__, buflen)); - } - } - -done: - - if (tcpka_sync.tcpka_drop && last_payload_len > 0) { - DHD_ERROR(("%s: Free len %d v%s pkt\n", - __func__, last_payload_len, tcpka_sync.sess_type ? "6" : "4")); - if (tcpka_sync.sess_type) { - memcpy(tcpka6, &tcpka6_orig, sizeof(tcpka6_conn_t)); - } else { - memcpy(tcpka, &tcpka_orig, sizeof(tcpka_conn_t)); - } - return BCME_BUSY; - } - - tcpka_sync.tcpka_sync_state = BCOL_TCPKA_SYNC_STATE_READY; - tcpka_sync.tcpka_sk = ((struct sk_buff *)pkt)->sk; - - if (tcpka_sync.tcpka_drop) { - DHD_ERROR(("%s: packet sent, last_payload_len: %d\n", __func__, last_payload_len)); - } - return BCME_OK; -} -#endif /* _DHD_BCOL_TCPKA_PUB_ */
diff --git a/bcmdhd.1.579.77.41.x/dhd_bus.h b/bcmdhd.1.579.77.41.x/dhd_bus.h deleted file mode 100644 index 53a9317..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_bus.h +++ /dev/null
@@ -1,296 +0,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-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_bus.h 698895 2017-05-11 02:55:17Z $ - */ - -#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) - */ - -/* 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, char *reg_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); - -/* Size of Extended Trap data Buffer */ -#ifdef BCMPCIE -#define BCMPCIE_EXT_TRAP_DATA_MAXLEN 4096 -#endif - -/* Send a data frame to the dongle. Callee disposes of txp. */ -#ifdef BCMPCIE -extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp, uint8 ifidx); -#else -extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp); -#endif - -extern struct device * dhd_bus_to_dev(struct dhd_bus *bus); - -/* 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); - -/* 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 const 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 - -#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); -#else -#define dhd_bus_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, -#ifdef HOFFLOAD_MODULES - WRT_HOST_MODULE_ADDR -#endif -}; - -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); -extern void dhd_bus_set_linkdown(dhd_pub_t *dhdp, bool val); - -#ifdef IDLE_TX_FLOW_MGMT -extern void dhd_bus_flow_ring_resume_response(struct dhd_bus *bus, uint16 flowid, int32 status); -#endif /* IDLE_TX_FLOW_MGMT */ - - -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 dhdpcie_cto_init(struct dhd_bus *bus, bool enable); - - -#ifdef DHD_FW_COREDUMP -extern struct dhd_bus *g_dhd_bus; -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); - -/* 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); - -#ifdef DHD_ULP -extern void dhd_bus_ulp_disable_console(dhd_pub_t *dhdp); -extern void dhd_bus_ucode_download(struct dhd_bus *bus); -#endif /* DHD_ULP */ -extern int dhd_bus_readwrite_bp_addr(dhd_pub_t *dhdp, uint addr, uint size, uint* data, bool read); - -#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 */ -#ifdef BCMPCIE -extern void dhd_bus_dump_console_buffer(struct dhd_bus *bus); -#else -#define dhd_bus_dump_console_buffer(x) -#endif /* BCMPCIE */ - -extern uint16 dhd_get_chipid(dhd_pub_t *dhd); - -extern int dhd_get_idletime(dhd_pub_t *dhd); -extern int dhd_set_idletime(dhd_pub_t *dhd, int32 idletime); - -#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 */ -#endif /* _dhd_bus_h_ */
diff --git a/bcmdhd.1.579.77.41.x/dhd_buzzz.h b/bcmdhd.1.579.77.41.x/dhd_buzzz.h deleted file mode 100644 index e349a3f..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_buzzz.h +++ /dev/null
@@ -1,37 +0,0 @@ -#ifndef _DHD_BUZZZ_H_INCLUDED_ -#define _DHD_BUZZZ_H_INCLUDED_ - -/* - * Broadcom logging system - Empty implementaiton - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id$ - */ - -#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_ */
diff --git a/bcmdhd.1.579.77.41.x/dhd_cdc.c b/bcmdhd.1.579.77.41.x/dhd_cdc.c deleted file mode 100644 index 34db8d7..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_cdc.c +++ /dev/null
@@ -1,983 +0,0 @@ -/* - * DHD Protocol Module for CDC and BDC. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_cdc.c 699163 2017-05-12 05:18:23Z $ - * - * 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 -#ifdef BCMDBUS -#include <dhd_config.h> -#endif /* BCMDBUS */ - -#ifdef DHD_ULP -#include <dhd_ulp.h> -#endif /* DHD_ULP */ - -#ifdef TCPKA_REPAIR -#include <dhd_bcol_tcpka.h> -#endif /* TCPKA_REPAIR */ - -#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; - -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, false); - 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, false); - 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, false); - 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)); - - 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; -} - - -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) { - 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 -} - -/* 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 - 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 - 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; - } - -#ifdef TCPKA_REPAIR - if (h->flags & BDC_FLAG_QUEUE_NEEDED) { - DHD_PKTTAG_SET_QUEUED((dhd_pkttag_rx_t *)PKTTAG(pktbuf), TRUE); - } -#endif /* TCPKA_REPAIR */ - - 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 - 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 - 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; - char iovbuf[64]; - uint32 enable = 0; - 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 */ - - memset(iovbuf, 0, sizeof(iovbuf)); - -#ifdef DHD_BUILTIN - if (dhd_load_mode == DHD_LOAD_MODE_PARTIAL) { - enable = 2; - } -#endif /* DHD_BUILTIN */ - bcm_mkiovar("host_off", (char *)&enable, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - - /* 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); - dhd_conf_read_reg(dhd, dhd->reg_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; -}
diff --git a/bcmdhd.1.579.77.41.x/dhd_cfg80211.c b/bcmdhd.1.579.77.41.x/dhd_cfg80211.c deleted file mode 100644 index 26780f6..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_cfg80211.c +++ /dev/null
@@ -1,282 +0,0 @@ -/* - * Linux cfg80211 driver - Dongle Host Driver (DHD) related - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_cfg80211.c 699163 2017-05-12 05:18:23Z $ - */ - -#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 - -#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 - -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; - - WL_TRACE(("In\n")); - if (!dhd_dongle_up) { - WL_ERR(("Dongle is already down\n")); - return err; - } - - ndev = bcmcfg_to_prmry_ndev(cfg); - wl_dongle_down(ndev); - dhd_dongle_up = FALSE; - return 0; -} - -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; -} - -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); -} - -struct net_device * dhd_cfg80211_netdev_free(struct net_device *ndev) -{ - if (ndev) { - if (ndev->ieee80211_ptr) { - kfree(ndev->ieee80211_ptr); - 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 -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) - if (ndev) - free_netdev(ndev); -#endif -} - -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 dhd_config_dongle(struct bcm_cfg80211 *cfg) -{ -#ifndef DHD_SDALIGN -#define DHD_SDALIGN 32 -#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, err = 0; - int8 index; - - WL_TRACE(("entry: cmd = %d\n", nlioc->cmd)); - - dhd = cfg->pub; - DHD_OS_WAKE_LOCK(dhd); - - /* send to dongle only if we are not waiting for reload already */ - if (dhd->hang_was_sent) { - WL_ERR(("HANG was sent up earlier\n")); - DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhd, DHD_EVENT_TIMEOUT_MS); - DHD_OS_WAKE_UNLOCK(dhd); - return OSL_ERROR(BCME_DONGLE_DOWN); - } - - index = dhd_ifindex2idx(dhd->info, nlioc->ifindex); - if (index == DHD_BAD_IF) { - ndev = wdev_to_wlc_ndev(wdev, cfg); - index = dhd_net2idx(dhd->info, ndev); - if (index == DHD_BAD_IF) { - WL_ERR(("Bad ifidx %d, wdev:%p\n", nlioc->ifindex, wdev)); - ret = BCME_ERROR; - goto done; - } - } - - ioc.cmd = nlioc->cmd; - ioc.len = nlioc->len; - ioc.set = nlioc->set; - ioc.driver = nlioc->magic; - err = dhd_ioctl_process(dhd, index, &ioc, buf); - if (err) { - ret = OSL_ERROR(err); - ndev = dhd_idx2net(dhd, index); - if(ndev && (ndev->flags & IFF_UP)) { - if ((err == BCME_NOTFOUND) || (err == BCME_NOTREADY)) { - WL_TRACE(("cmd %d return err %d on %s, ret %d\n", - nlioc->cmd, err, ndev->name, ret)); - } else { - WL_ERR(("cmd %d return err %d on %s, ret %d\n", - nlioc->cmd, err, ndev->name, ret)); - } - } - goto done; - } - -done: - DHD_OS_WAKE_UNLOCK(dhd); - return ret; -}
diff --git a/bcmdhd.1.579.77.41.x/dhd_cfg80211.h b/bcmdhd.1.579.77.41.x/dhd_cfg80211.h deleted file mode 100644 index 20923ce..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_cfg80211.h +++ /dev/null
@@ -1,54 +0,0 @@ -/* - * Linux cfg80211 driver - Dongle Host Driver (DHD) related - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_cfg80211.h 612483 2016-01-14 03:44:27Z $ - */ - - -#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 -#ifndef WL_TRACE -#define WL_TRACE CFG80211_TRACE -#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); - -#endif /* __DHD_CFG80211__ */
diff --git a/bcmdhd.1.579.77.41.x/dhd_common.c b/bcmdhd.1.579.77.41.x/dhd_common.c deleted file mode 100644 index 5feb03b..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_common.c +++ /dev/null
@@ -1,6401 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), common DHD core. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_common.c 710862 2017-07-14 07:43:59Z $ - */ -#include <typedefs.h> -#include <osl.h> - -#include <epivers.h> -#include <bcmutils.h> - -#include <bcmendian.h> -#include <dngl_stats.h> -#include <wlioctl.h> -#include <dhd.h> -#include <dhd_ip.h> -#include <bcmevent.h> - -#ifdef PCIE_FULL_DONGLE -#include <bcmmsgbuf.h> -#endif /* PCIE_FULL_DONGLE */ - -#ifdef SHOW_LOGTRACE -#include <event_log.h> -#endif /* SHOW_LOGTRACE */ - -#ifdef BCMPCIE -#include <dhd_flowring.h> -#endif - -#include <dhd_bus.h> -#include <dhd_proto.h> -#include <dhd_config.h> -#include <bcmsdbus.h> -#include <dhd_dbg.h> -#include <dhd_debug.h> -#include <dhd_mschdbg.h> -#include <msgtrace.h> - -#ifdef WL_CFG80211 -#include <wl_cfg80211.h> -#endif -#ifdef PNO_SUPPORT -#include <dhd_pno.h> -#endif -#ifdef RTT_SUPPORT -#include <dhd_rtt.h> -#endif - -#ifdef DNGL_EVENT_SUPPORT -#include <dnglevent.h> -#endif - -#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 PROP_TXSTATUS -#include <wlfc_proto.h> -#include <dhd_wlfc.h> -#endif - -#ifdef DHD_WMF -#include <dhd_linux.h> -#include <dhd_wmf_linux.h> -#endif /* DHD_WMF */ - -#ifdef DHD_L2_FILTER -#include <dhd_l2_filter.h> -#endif /* DHD_L2_FILTER */ - -#ifdef DHD_PSTA -#include <dhd_psta.h> -#endif /* DHD_PSTA */ -#ifdef DHD_TIMESYNC -#include <dhd_timesync.h> -#endif /* DHD_TIMESYNC */ - -#ifdef DHD_WET -#include <dhd_wet.h> -#endif /* DHD_WET */ - -#if defined(BCMEMBEDIMAGE) && defined(DHD_EFI) -#include <nvram_4364.h> -#endif - -#ifdef WLMEDIA_HTSF -extern void htsf_update(struct dhd_info *dhd, void *data); -#endif - -extern int is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype, - bcm_event_msg_u_t *out_event); - -/* By default all logs are enabled */ -int dhd_msg_level = DHD_ERROR_VAL | DHD_FWLOG_VAL; - - -#if defined(WL_WLC_SHIM) -#include <wl_shim.h> -#else -#endif /* WL_WLC_SHIM */ - -#ifdef DHD_ULP -#include <dhd_ulp.h> -#endif /* DHD_ULP */ - -#ifdef DHD_DEBUG -#include <sdiovar.h> -#endif /* DHD_DEBUG */ - -#ifdef BCOL_TCPKA_SYNC -extern bcol_tcpka_sync_t tcpka_sync; -#endif /* BCOL_TCPKA_SYNC */ - -#ifdef SOFTAP -char fw_path2[MOD_PARAM_PATHLEN]; -extern bool softap_enabled; -#endif - -#ifdef REPORT_FATAL_TIMEOUTS -/* Default timeout value in ms */ -#define SCAN_TIMEOUT_DEFAULT 1 -#define JOIN_TIMEOUT_DEFAULT 7500 -#ifdef DHD_EFI -#define BUS_TIMEOUT_DEFAULT 8000000 /* 800ms, in units of 100ns */ -#define CMD_TIMEOUT_DEFAULT 15000000 /* 1.5sec, in units of 100ns */ -#else -#define BUS_TIMEOUT_DEFAULT 800 -#define CMD_TIMEOUT_DEFAULT 1200 -#endif /* DHD_EFI */ -#endif /* REPORT_FATAL_TIMEOUTS */ - -#ifdef SHOW_LOGTRACE -#define BYTES_AHEAD_NUM 11 /* address in map file is before these many bytes */ -#define READ_NUM_BYTES 1000 /* read map file each time this No. of bytes */ -#define GO_BACK_FILE_POS_NUM_BYTES 100 /* set file pos back to cur pos */ -static char *ramstart_str = "text_start"; /* string in mapfile has addr ramstart */ -static char *rodata_start_str = "rodata_start"; /* string in mapfile has addr rodata start */ -static char *rodata_end_str = "rodata_end"; /* string in mapfile has addr rodata end */ -#define RAMSTART_BIT 0x01 -#define RDSTART_BIT 0x02 -#define RDEND_BIT 0x04 -#define ALL_MAP_VAL (RAMSTART_BIT | RDSTART_BIT | RDEND_BIT) -#endif /* SHOW_LOGTRACE */ - -/* Last connection success/failure status */ -uint32 dhd_conn_event; -uint32 dhd_conn_status; -uint32 dhd_conn_reason; - -extern int dhd_iscan_request(void * dhdp, uint16 action); -extern void dhd_ind_scan_confirm(void *h, bool status); -extern int dhd_iscan_in_progress(void *h); -void dhd_iscan_lock(void); -void dhd_iscan_unlock(void); -extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); -#if !defined(AP) && defined(WLP2P) -extern int dhd_get_concurrent_capabilites(dhd_pub_t *dhd); -#endif - -extern int dhd_socram_dump(struct dhd_bus *bus); - -#ifdef DNGL_EVENT_SUPPORT -static void dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event, - bcm_dngl_event_msg_t *dngl_event, size_t pktlen); -static int dngl_host_event(dhd_pub_t *dhdp, void *pktdata, bcm_dngl_event_msg_t *dngl_event, - size_t pktlen); -#endif /* DNGL_EVENT_SUPPORT */ - -#define MAX_CHUNK_LEN 1408 /* 8 * 8 * 22 */ - -bool ap_cfg_running = FALSE; -bool ap_fw_loaded = FALSE; - -/* Version string to report */ -#ifdef DHD_DEBUG -#ifndef SRCBASE -#define SRCBASE "drivers/net/wireless/bcmdhd" -#endif -#define DHD_COMPILED "\nCompiled in " SRCBASE -#endif /* DHD_DEBUG */ - -#define CHIPID_MISMATCH 8 - -#if defined(DHD_DEBUG) -const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR; -#else -const char dhd_version[] = "\nDongle Host Driver, version " EPI_VERSION_STR; -#endif -char fw_version[FW_VER_STR_LEN] = "\0"; -char clm_version[CLM_VER_STR_LEN] = "\0"; - -char bus_api_revision[BUS_API_REV_STR_LEN] = "\0"; - -void dhd_set_timer(void *bus, uint wdtick); - -#if defined(TRAFFIC_MGMT_DWM) -static int traffic_mgmt_add_dwm_filter(dhd_pub_t *dhd, - trf_mgmt_filter_list_t * trf_mgmt_filter_list, int len); -#endif - -/* IOVar table */ -enum { - IOV_VERSION = 1, - IOV_WLMSGLEVEL, - IOV_MSGLEVEL, - IOV_BCMERRORSTR, - IOV_BCMERROR, - IOV_WDTICK, - IOV_DUMP, - IOV_CLEARCOUNTS, - IOV_LOGDUMP, - IOV_LOGCAL, - IOV_LOGSTAMP, - IOV_GPIOOB, - IOV_IOCTLTIMEOUT, - IOV_CONS, - IOV_DCONSOLE_POLL, -#if defined(DHD_DEBUG) - IOV_DHD_JOIN_TIMEOUT_DBG, - IOV_SCAN_TIMEOUT, - IOV_MEM_DEBUG, -#endif /* defined(DHD_DEBUG) */ -#ifdef PROP_TXSTATUS - IOV_PROPTXSTATUS_ENABLE, - IOV_PROPTXSTATUS_MODE, - IOV_PROPTXSTATUS_OPT, - IOV_PROPTXSTATUS_MODULE_IGNORE, - IOV_PROPTXSTATUS_CREDIT_IGNORE, - IOV_PROPTXSTATUS_TXSTATUS_IGNORE, - IOV_PROPTXSTATUS_RXPKT_CHK, -#endif /* PROP_TXSTATUS */ - IOV_BUS_TYPE, -#ifdef WLMEDIA_HTSF - IOV_WLPKTDLYSTAT_SZ, -#endif - IOV_CHANGEMTU, - IOV_HOSTREORDER_FLOWS, -#ifdef DHDTCPACK_SUPPRESS - IOV_TCPACK_SUPPRESS, -#endif /* DHDTCPACK_SUPPRESS */ -#ifdef DHD_WMF - IOV_WMF_BSS_ENAB, - IOV_WMF_UCAST_IGMP, - IOV_WMF_MCAST_DATA_SENDUP, -#ifdef WL_IGMP_UCQUERY - IOV_WMF_UCAST_IGMP_QUERY, -#endif /* WL_IGMP_UCQUERY */ -#ifdef DHD_UCAST_UPNP - IOV_WMF_UCAST_UPNP, -#endif /* DHD_UCAST_UPNP */ - IOV_WMF_PSTA_DISABLE, -#endif /* DHD_WMF */ -#if defined(TRAFFIC_MGMT_DWM) - IOV_TRAFFIC_MGMT_DWM, -#endif - IOV_AP_ISOLATE, -#ifdef DHD_L2_FILTER - IOV_DHCP_UNICAST, - IOV_BLOCK_PING, - IOV_PROXY_ARP, - IOV_GRAT_ARP, -#endif /* DHD_L2_FILTER */ - IOV_DHD_IE, -#ifdef DHD_PSTA - IOV_PSTA, -#endif /* DHD_PSTA */ -#ifdef DHD_WET - IOV_WET, - IOV_WET_HOST_IPV4, - IOV_WET_HOST_MAC, -#endif /* DHD_WET */ - IOV_CFG80211_OPMODE, - IOV_ASSERT_TYPE, - IOV_LMTEST, -#ifdef DHD_MCAST_REGEN - IOV_MCAST_REGEN_BSS_ENABLE, -#endif -#ifdef SHOW_LOGTRACE - IOV_DUMP_TRACE_LOG, -#endif /* SHOW_LOGTRACE */ -#ifdef REPORT_FATAL_TIMEOUTS - IOV_SCAN_TO, - IOV_JOIN_TO, - IOV_CMD_TO, - IOV_OQS_TO, -#endif /* REPORT_FATAL_TIMEOUTS */ - IOV_DONGLE_TRAP_TYPE, - IOV_DONGLE_TRAP_INFO, - IOV_BPADDR, - IOV_LAST, -#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) - IOV_LOG_CAPTURE_ENABLE, - IOV_LOG_DUMP, -#endif /* DHD_EFI && DHD_LOG_DUMP */ -#ifdef EVENT_DATA_HOSTWAKE - IOV_EVT_DATA_SENDUP, -#ifdef SCHED_WAKE - IOV_HOSTWAKE_EVT_SETUP, - IOV_HAL_REQ_SCHED_WAKE, -#endif /* SCHED_WAKE */ -#endif /* EVENT_DATA_HOSTWAKE */ -#ifdef UART_HB_CONFIG - IOV_HEARTBEAT, -#endif /* UART_HB_CONFIG */ -#ifdef BCOL_TCPKA_SYNC -#ifdef SCHED_WAKE - IOV_HOSTWAKE_TCPKA_SETUP, -#endif /* SCHED_WAKE */ - IOV_TCPKA_ACT_BUF, - IOV_TCPKA_NOTI_BUF, - IOV_TCPKA_NOTI_CAPTURE, - IOV_TCPKA_GET_SYNC_INFO, - IOV_TCPKA_DROP, - IOV_TCPKA_REPAIR_BLOCK, -#endif /* BCOL_TCPKA_SYNC */ -#ifdef HAL_API - IOV_BLOCK_FW_CMD, - IOV_CFG_ROAM_OFF -#endif /* HAL_API */ -}; - -const bcm_iovar_t dhd_iovars[] = { - {"version", IOV_VERSION, 0, 0, IOVT_BUFFER, sizeof(dhd_version) }, - {"wlmsglevel", IOV_WLMSGLEVEL, 0, 0, IOVT_UINT32, 0 }, -#ifdef DHD_DEBUG - {"msglevel", IOV_MSGLEVEL, 0, 0, IOVT_UINT32, 0 }, - {"mem_debug", IOV_MEM_DEBUG, 0, 0, IOVT_BUFFER, 0 }, -#endif /* DHD_DEBUG */ - {"bcmerrorstr", IOV_BCMERRORSTR, 0, 0, IOVT_BUFFER, BCME_STRLEN }, - {"bcmerror", IOV_BCMERROR, 0, 0, IOVT_INT8, 0 }, - {"wdtick", IOV_WDTICK, 0, 0, IOVT_UINT32, 0 }, - {"dump", IOV_DUMP, 0, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, - {"cons", IOV_CONS, 0, 0, IOVT_BUFFER, 0 }, - {"dconpoll", IOV_DCONSOLE_POLL, 0, 0, IOVT_UINT32, 0 }, - {"clearcounts", IOV_CLEARCOUNTS, 0, 0, IOVT_VOID, 0 }, - {"gpioob", IOV_GPIOOB, 0, 0, IOVT_UINT32, 0 }, - {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, 0, IOVT_UINT32, 0 }, -#ifdef PROP_TXSTATUS - {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, 0, IOVT_BOOL, 0 }, - /* - set the proptxtstatus operation mode: - 0 - Do not do any proptxtstatus flow control - 1 - Use implied credit from a packet status - 2 - Use explicit credit - */ - {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, 0, IOVT_UINT32, 0 }, - {"proptx_opt", IOV_PROPTXSTATUS_OPT, 0, 0, IOVT_UINT32, 0 }, - {"pmodule_ignore", IOV_PROPTXSTATUS_MODULE_IGNORE, 0, 0, IOVT_BOOL, 0 }, - {"pcredit_ignore", IOV_PROPTXSTATUS_CREDIT_IGNORE, 0, 0, IOVT_BOOL, 0 }, - {"ptxstatus_ignore", IOV_PROPTXSTATUS_TXSTATUS_IGNORE, 0, 0, IOVT_BOOL, 0 }, - {"rxpkt_chk", IOV_PROPTXSTATUS_RXPKT_CHK, 0, 0, IOVT_BOOL, 0 }, -#endif /* PROP_TXSTATUS */ - {"bustype", IOV_BUS_TYPE, 0, 0, IOVT_UINT32, 0}, -#ifdef WLMEDIA_HTSF - {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, 0, IOVT_UINT8, 0 }, -#endif - {"changemtu", IOV_CHANGEMTU, 0, 0, IOVT_UINT32, 0 }, - {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, 0, IOVT_BUFFER, - (WLHOST_REORDERDATA_MAXFLOWS + 1) }, -#ifdef DHDTCPACK_SUPPRESS - {"tcpack_suppress", IOV_TCPACK_SUPPRESS, 0, 0, IOVT_UINT8, 0 }, -#endif /* DHDTCPACK_SUPPRESS */ -#ifdef DHD_WMF - {"wmf_bss_enable", IOV_WMF_BSS_ENAB, 0, 0, IOVT_BOOL, 0 }, - {"wmf_ucast_igmp", IOV_WMF_UCAST_IGMP, 0, 0, IOVT_BOOL, 0 }, - {"wmf_mcast_data_sendup", IOV_WMF_MCAST_DATA_SENDUP, 0, 0, IOVT_BOOL, 0 }, -#ifdef WL_IGMP_UCQUERY - {"wmf_ucast_igmp_query", IOV_WMF_UCAST_IGMP_QUERY, (0), 0, IOVT_BOOL, 0 }, -#endif /* WL_IGMP_UCQUERY */ -#ifdef DHD_UCAST_UPNP - {"wmf_ucast_upnp", IOV_WMF_UCAST_UPNP, (0), 0, IOVT_BOOL, 0 }, -#endif /* DHD_UCAST_UPNP */ - {"wmf_psta_disable", IOV_WMF_PSTA_DISABLE, (0), 0, IOVT_BOOL, 0 }, -#endif /* DHD_WMF */ -#if defined(TRAFFIC_MGMT_DWM) - {"trf_mgmt_filters_add", IOV_TRAFFIC_MGMT_DWM, (0), 0, IOVT_BUFFER, 0}, -#endif -#ifdef DHD_L2_FILTER - {"dhcp_unicast", IOV_DHCP_UNICAST, (0), 0, IOVT_BOOL, 0 }, -#endif /* DHD_L2_FILTER */ - {"ap_isolate", IOV_AP_ISOLATE, (0), 0, IOVT_BOOL, 0}, -#ifdef DHD_L2_FILTER - {"block_ping", IOV_BLOCK_PING, (0), 0, IOVT_BOOL, 0}, - {"proxy_arp", IOV_PROXY_ARP, (0), 0, IOVT_BOOL, 0}, - {"grat_arp", IOV_GRAT_ARP, (0), 0, IOVT_BOOL, 0}, -#endif /* DHD_L2_FILTER */ - {"dhd_ie", IOV_DHD_IE, (0), 0, IOVT_BUFFER, 0}, -#ifdef DHD_PSTA - /* PSTA/PSR Mode configuration. 0: DIABLED 1: PSTA 2: PSR */ - {"psta", IOV_PSTA, 0, 0, IOVT_UINT32, 0}, -#endif /* DHD PSTA */ -#ifdef DHD_WET - /* WET Mode configuration. 0: DIABLED 1: WET */ - {"wet", IOV_WET, 0, 0, IOVT_UINT32, 0}, - {"wet_host_ipv4", IOV_WET_HOST_IPV4, 0, 0, IOVT_UINT32, 0}, - {"wet_host_mac", IOV_WET_HOST_MAC, 0, 0, IOVT_BUFFER, 0}, -#endif /* DHD WET */ - {"op_mode", IOV_CFG80211_OPMODE, 0, 0, IOVT_UINT32, 0 }, - {"assert_type", IOV_ASSERT_TYPE, (0), 0, IOVT_UINT32, 0}, - {"lmtest", IOV_LMTEST, 0, 0, IOVT_UINT32, 0 }, -#ifdef DHD_MCAST_REGEN - {"mcast_regen_bss_enable", IOV_MCAST_REGEN_BSS_ENABLE, 0, 0, IOVT_BOOL, 0}, -#endif -#ifdef SHOW_LOGTRACE - {"dump_trace_buf", IOV_DUMP_TRACE_LOG, 0, 0, IOVT_BUFFER, sizeof(trace_buf_info_t) }, -#endif /* SHOW_LOGTRACE */ -#ifdef REPORT_FATAL_TIMEOUTS - {"scan_timeout", IOV_SCAN_TO, 0, 0, IOVT_UINT32, 0 }, - {"join_timeout", IOV_JOIN_TO, 0, 0, IOVT_UINT32, 0 }, - {"cmd_timeout", IOV_CMD_TO, 0, 0, IOVT_UINT32, 0 }, - {"oqs_timeout", IOV_OQS_TO, 0, 0, IOVT_UINT32, 0 }, -#endif /* REPORT_FATAL_TIMEOUTS */ - {"trap_type", IOV_DONGLE_TRAP_TYPE, 0, 0, IOVT_UINT32, 0 }, - {"trap_info", IOV_DONGLE_TRAP_INFO, 0, 0, IOVT_BUFFER, sizeof(trap_t) }, -#ifdef DHD_DEBUG - {"bpaddr", IOV_BPADDR, 0, 0, IOVT_BUFFER, sizeof(sdreg_t) }, -#endif /* DHD_DEBUG */ -#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) - {"log_capture_enable", IOV_LOG_CAPTURE_ENABLE, 0, 0, IOVT_UINT8, 0}, - {"log_dump", IOV_LOG_DUMP, 0, 0, IOVT_UINT8, 0}, -#endif /* DHD_EFI && DHD_LOG_DUMP */ -#ifdef EVENT_DATA_HOSTWAKE - {"event_data_sendup", IOV_EVT_DATA_SENDUP, 0, 0, IOVT_BOOL, 0}, -#ifdef SCHED_WAKE - {"hostwake_event_setup", IOV_HOSTWAKE_EVT_SETUP, 0, 0, IOVT_BOOL, 0}, - {"hal_req_sched_wake", IOV_HAL_REQ_SCHED_WAKE, 0, 0, IOVT_BOOL, 0}, -#endif /* SCHED_WAKE */ -#endif /* EVENT_DATA_HOSTWAKE */ -#ifdef UART_HB_CONFIG - {"heartbeat", IOV_HEARTBEAT, 0, 0, IOVT_BOOL, 0}, -#endif /* UART_HB_CONFIG */ -#ifdef BCOL_TCPKA_SYNC -#ifdef SCHED_WAKE - {"hostwake_tcpka_setup", IOV_HOSTWAKE_TCPKA_SETUP, 0, 0, IOVT_BOOL, 0}, -#endif /* SCHED_WAKE */ - {"tcpka_act_buf", IOV_TCPKA_ACT_BUF, (0), 0, IOVT_BUFFER, 0}, - {"tcpka_noti_buf", IOV_TCPKA_NOTI_BUF, (0), 0, IOVT_BUFFER, 0}, - {"tcpka_hold_pkt_payload", IOV_TCPKA_NOTI_CAPTURE, (0), 0, IOVT_UINT8, 0}, - {"tcpka_get_sync_info", IOV_TCPKA_GET_SYNC_INFO, (0), 0, IOVT_BUFFER, 0}, - {"tcpka_drop", IOV_TCPKA_DROP, 0, 0, IOVT_BOOL, 0}, - {"tcpka_repair_block", IOV_TCPKA_REPAIR_BLOCK, (0), 0, IOVT_UINT32, 0}, -#endif /* BCOL_TCPKA_SYNC */ -#ifdef HAL_API - {"block_fw_cmd", IOV_BLOCK_FW_CMD, 0, 0, IOVT_BOOL, 0}, - {"cfg_roam_off", IOV_CFG_ROAM_OFF, 0, 0, IOVT_BOOL, 0}, -#endif /* HAL_API */ - {NULL, 0, 0, 0, 0, 0 } -}; - -#define DHD_IOVAR_BUF_SIZE 128 - -bool -dhd_query_bus_erros(dhd_pub_t *dhdp) -{ - bool ret = FALSE; - - if (dhdp->padsiso) { - DHD_ERROR(("%s: Dongle PAD isolation is enabled, cant not proceed\n", - __FUNCTION__)); - ret = TRUE; - } - - if (dhdp->dongle_reset) { - DHD_ERROR(("%s: Dongle Reset occurred, cannot proceed\n", - __FUNCTION__)); - ret = TRUE; - } - - if (dhdp->dongle_trap_occured) { - DHD_ERROR(("%s: FW TRAP has occurred, cannot proceed\n", - __FUNCTION__)); - ret = TRUE; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - dhdp->hang_reason = HANG_REASON_DONGLE_TRAP; - dhd_os_send_hang_message(dhdp); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ - } - - if (dhdp->iovar_timeout_occured) { - DHD_ERROR(("%s: Resumed on timeout for previous IOVAR, cannot proceed\n", - __FUNCTION__)); - ret = TRUE; - } - -#ifdef PCIE_FULL_DONGLE - if (dhdp->d3ack_timeout_occured) { - DHD_ERROR(("%s: Resumed on timeout for previous D3ACK, cannot proceed\n", - __FUNCTION__)); - ret = TRUE; - } -#endif /* PCIE_FULL_DONGLE */ - - return ret; -} - -#ifdef DHD_SSSR_DUMP -int -dhd_sssr_mempool_init(dhd_pub_t *dhd) -{ - dhd->sssr_mempool = (uint8 *) MALLOCZ(dhd->osh, DHD_SSSR_MEMPOOL_SIZE); - if (dhd->sssr_mempool == NULL) { - DHD_ERROR(("%s: MALLOC of sssr_mempool failed\n", - __FUNCTION__)); - return BCME_ERROR; - } - return BCME_OK; -} - -void -dhd_sssr_mempool_deinit(dhd_pub_t *dhd) -{ - if (dhd->sssr_mempool) { - MFREE(dhd->osh, dhd->sssr_mempool, DHD_SSSR_MEMPOOL_SIZE); - dhd->sssr_mempool = NULL; - } -} - -int -dhd_get_sssr_reg_info(dhd_pub_t *dhd) -{ - int ret = BCME_ERROR; - - DHD_ERROR(("%s: get sssr_reg_info\n", __FUNCTION__)); - /* get sssr_reg_info from firmware */ - memset((void *)&dhd->sssr_reg_info, 0, sizeof(dhd->sssr_reg_info)); - if (bcm_mkiovar("sssr_reg_info", 0, 0, (char *)&dhd->sssr_reg_info, - sizeof(dhd->sssr_reg_info))) { - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, &dhd->sssr_reg_info, - sizeof(dhd->sssr_reg_info), FALSE, 0)) < 0) { - DHD_ERROR(("%s: dhd_wl_ioctl_cmd failed (error=%d)\n", __FUNCTION__, ret)); - } - } else { - DHD_ERROR(("%s: bcm_mkiovar failed\n", __FUNCTION__)); - } - - return ret; -} - -uint32 -dhd_get_sssr_bufsize(dhd_pub_t *dhd) -{ - int i; - uint32 sssr_bufsize = 0; - /* Init all pointers to NULL */ - for (i = 0; i < MAX_NUM_D11CORES; i++) { - sssr_bufsize += dhd->sssr_reg_info.mac_regs[i].sr_size; - } - sssr_bufsize += dhd->sssr_reg_info.vasip_regs.vasip_sr_size; - - /* Double the size as different dumps will be saved before and after SR */ - sssr_bufsize = 2 * sssr_bufsize; - - return sssr_bufsize; -} - -int -dhd_sssr_dump_init(dhd_pub_t *dhd) -{ - int i; - uint32 sssr_bufsize; - uint32 mempool_used = 0; - - dhd->sssr_inited = FALSE; - - /* check if sssr mempool is allocated */ - if (dhd->sssr_mempool == NULL) { - DHD_ERROR(("%s: sssr_mempool is not allocated\n", - __FUNCTION__)); - return BCME_ERROR; - } - - /* Get SSSR reg info */ - if (dhd_get_sssr_reg_info(dhd) != BCME_OK) { - DHD_ERROR(("%s: dhd_get_sssr_reg_info failed\n", __FUNCTION__)); - return BCME_ERROR; - } - - /* Validate structure version */ - if (dhd->sssr_reg_info.version != SSSR_REG_INFO_VER) { - DHD_ERROR(("%s: dhd->sssr_reg_info.version (%d : %d) mismatch\n", - __FUNCTION__, (int)dhd->sssr_reg_info.version, SSSR_REG_INFO_VER)); - return BCME_ERROR; - } - - /* Validate structure length */ - if (dhd->sssr_reg_info.length != sizeof(dhd->sssr_reg_info)) { - DHD_ERROR(("%s: dhd->sssr_reg_info.length (%d : %d) mismatch\n", - __FUNCTION__, (int)dhd->sssr_reg_info.length, - (int)sizeof(dhd->sssr_reg_info))); - return BCME_ERROR; - } - - /* validate fifo size */ - sssr_bufsize = dhd_get_sssr_bufsize(dhd); - if (sssr_bufsize > DHD_SSSR_MEMPOOL_SIZE) { - DHD_ERROR(("%s: sssr_bufsize(%d) is greater than sssr_mempool(%d)\n", - __FUNCTION__, (int)sssr_bufsize, DHD_SSSR_MEMPOOL_SIZE)); - return BCME_ERROR; - } - - /* init all pointers to NULL */ - for (i = 0; i < MAX_NUM_D11CORES; i++) { - dhd->sssr_d11_before[i] = NULL; - dhd->sssr_d11_after[i] = NULL; - } - dhd->sssr_vasip_buf_before = NULL; - dhd->sssr_vasip_buf_after = NULL; - - /* Allocate memory */ - for (i = 0; i < MAX_NUM_D11CORES; i++) { - if (dhd->sssr_reg_info.mac_regs[i].sr_size) { - dhd->sssr_d11_before[i] = (uint32 *)(dhd->sssr_mempool + mempool_used); - mempool_used += dhd->sssr_reg_info.mac_regs[i].sr_size; - - dhd->sssr_d11_after[i] = (uint32 *)(dhd->sssr_mempool + mempool_used); - mempool_used += dhd->sssr_reg_info.mac_regs[i].sr_size; - } - } - - if (dhd->sssr_reg_info.vasip_regs.vasip_sr_size) { - dhd->sssr_vasip_buf_before = (uint32 *)(dhd->sssr_mempool + mempool_used); - mempool_used += dhd->sssr_reg_info.vasip_regs.vasip_sr_size; - - dhd->sssr_vasip_buf_after = (uint32 *)(dhd->sssr_mempool + mempool_used); - mempool_used += dhd->sssr_reg_info.vasip_regs.vasip_sr_size; - } - - dhd->sssr_inited = TRUE; - - return BCME_OK; - -} - -void -dhd_sssr_dump_deinit(dhd_pub_t *dhd) -{ - int i; - - dhd->sssr_inited = FALSE; - /* init all pointers to NULL */ - for (i = 0; i < MAX_NUM_D11CORES; i++) { - dhd->sssr_d11_before[i] = NULL; - dhd->sssr_d11_after[i] = NULL; - } - dhd->sssr_vasip_buf_before = NULL; - dhd->sssr_vasip_buf_after = NULL; - - return; -} - -#endif /* DHD_SSSR_DUMP */ - -#ifdef DHD_FW_COREDUMP -void* dhd_get_fwdump_buf(dhd_pub_t *dhd_pub, uint32 length) -{ - if (!dhd_pub->soc_ram) { -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) - dhd_pub->soc_ram = (uint8*)DHD_OS_PREALLOC(dhd_pub, - DHD_PREALLOC_MEMDUMP_RAM, length); -#else - dhd_pub->soc_ram = (uint8*) MALLOC(dhd_pub->osh, length); -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ - } - - if (dhd_pub->soc_ram == NULL) { - DHD_ERROR(("%s: Failed to allocate memory for fw crash snap shot.\n", - __FUNCTION__)); - dhd_pub->soc_ram_length = 0; - } else { - memset(dhd_pub->soc_ram, 0, length); - dhd_pub->soc_ram_length = length; - } - - /* soc_ram free handled in dhd_{free,clear} */ - return dhd_pub->soc_ram; -} -#endif /* DHD_FW_COREDUMP */ - -/* to NDIS developer, the structure dhd_common is redundant, - * please do NOT merge it back from other branches !!! - */ - -int -dhd_common_socram_dump(dhd_pub_t *dhdp) -{ -#ifdef BCMDBUS - return 0; -#else - return dhd_socram_dump(dhdp->bus); -#endif /* BCMDBUS */ -} - -static int -dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) -{ - char eabuf[ETHER_ADDR_STR_LEN]; - - struct bcmstrbuf b; - struct bcmstrbuf *strbuf = &b; - - if (!dhdp || !dhdp->prot || !buf) { - return BCME_ERROR; - } - - bcm_binit(strbuf, buf, buflen); - - /* Base DHD info */ - bcm_bprintf(strbuf, "%s\n", dhd_version); - bcm_bprintf(strbuf, "\n"); - bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n", - dhdp->up, dhdp->txoff, dhdp->busstate); - bcm_bprintf(strbuf, "pub.hdrlen %u pub.maxctl %u pub.rxsz %u\n", - dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz); - bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n", - dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf)); - bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %u\n", dhdp->bcmerror, dhdp->tickcnt); - - bcm_bprintf(strbuf, "dongle stats:\n"); - bcm_bprintf(strbuf, "tx_packets %lu tx_bytes %lu tx_errors %lu tx_dropped %lu\n", - dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes, - dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped); - bcm_bprintf(strbuf, "rx_packets %lu rx_bytes %lu rx_errors %lu rx_dropped %lu\n", - dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes, - dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped); - bcm_bprintf(strbuf, "multicast %lu\n", dhdp->dstats.multicast); - - bcm_bprintf(strbuf, "bus stats:\n"); - bcm_bprintf(strbuf, "tx_packets %lu tx_dropped %lu tx_multicast %lu tx_errors %lu\n", - dhdp->tx_packets, dhdp->tx_dropped, dhdp->tx_multicast, dhdp->tx_errors); - bcm_bprintf(strbuf, "tx_ctlpkts %lu tx_ctlerrs %lu\n", - dhdp->tx_ctlpkts, dhdp->tx_ctlerrs); - bcm_bprintf(strbuf, "rx_packets %lu rx_multicast %lu rx_errors %lu \n", - dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors); - bcm_bprintf(strbuf, "rx_ctlpkts %lu rx_ctlerrs %lu rx_dropped %lu\n", - dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped); - bcm_bprintf(strbuf, "rx_readahead_cnt %lu tx_realloc %lu\n", - dhdp->rx_readahead_cnt, dhdp->tx_realloc); - bcm_bprintf(strbuf, "tx_pktgetfail %lu rx_pktgetfail %lu\n", - dhdp->tx_pktgetfail, dhdp->rx_pktgetfail); - bcm_bprintf(strbuf, "\n"); - -#ifdef DMAMAP_STATS - /* Add DMA MAP info */ - bcm_bprintf(strbuf, "DMA MAP stats: \n"); - bcm_bprintf(strbuf, "txdata: %lu size: %luK, rxdata: %lu size: %luK\n", - dhdp->dma_stats.txdata, KB(dhdp->dma_stats.txdata_sz), - dhdp->dma_stats.rxdata, KB(dhdp->dma_stats.rxdata_sz)); -#ifndef IOCTLRESP_USE_CONSTMEM - bcm_bprintf(strbuf, "IOCTL RX: %lu size: %luK ,", - dhdp->dma_stats.ioctl_rx, KB(dhdp->dma_stats.ioctl_rx_sz)); -#endif /* !IOCTLRESP_USE_CONSTMEM */ - bcm_bprintf(strbuf, "EVENT RX: %lu size: %luK, INFO RX: %lu size: %luK, " - "TSBUF RX: %lu size %luK\n", - dhdp->dma_stats.event_rx, KB(dhdp->dma_stats.event_rx_sz), - dhdp->dma_stats.info_rx, KB(dhdp->dma_stats.info_rx_sz), - dhdp->dma_stats.tsbuf_rx, KB(dhdp->dma_stats.tsbuf_rx_sz)); - bcm_bprintf(strbuf, "Total : %luK \n", - KB(dhdp->dma_stats.txdata_sz + dhdp->dma_stats.rxdata_sz + - dhdp->dma_stats.ioctl_rx_sz + dhdp->dma_stats.event_rx_sz + - dhdp->dma_stats.tsbuf_rx_sz)); -#endif /* DMAMAP_STATS */ - - /* Add any prot info */ - dhd_prot_dump(dhdp, strbuf); - bcm_bprintf(strbuf, "\n"); - - /* Add any bus info */ - dhd_bus_dump(dhdp, strbuf); - - -#if defined(DHD_LB_STATS) - dhd_lb_stats_dump(dhdp, strbuf); -#endif /* DHD_LB_STATS */ -#ifdef DHD_WET - if (dhd_get_wet_mode(dhdp)) { - bcm_bprintf(strbuf, "Wet Dump:\n"); - dhd_wet_dump(dhdp, strbuf); - } -#endif /* DHD_WET */ - return (!strbuf->size ? BCME_BUFTOOSHORT : 0); -} - -void -dhd_dump_to_kernelog(dhd_pub_t *dhdp) -{ - char buf[512]; - - DHD_ERROR(("F/W version: %s\n", fw_version)); - bcm_bprintf_bypass = TRUE; - dhd_dump(dhdp, buf, sizeof(buf)); - bcm_bprintf_bypass = FALSE; -} - -int -dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifidx) -{ - wl_ioctl_t ioc; - - ioc.cmd = cmd; - ioc.buf = arg; - ioc.len = len; - ioc.set = set; - - return dhd_wl_ioctl(dhd_pub, ifidx, &ioc, arg, len); -} - -int -dhd_wl_ioctl_get_intiovar(dhd_pub_t *dhd_pub, char *name, uint *pval, - int cmd, uint8 set, int ifidx) -{ - char iovbuf[WLC_IOCTL_SMLEN]; - int ret = -1; - - memset(iovbuf, 0, sizeof(iovbuf)); - if (bcm_mkiovar(name, NULL, 0, iovbuf, sizeof(iovbuf))) { - ret = dhd_wl_ioctl_cmd(dhd_pub, cmd, iovbuf, sizeof(iovbuf), set, ifidx); - if (!ret) { - *pval = ltoh32(*((uint*)iovbuf)); - } else { - DHD_ERROR(("%s: get int iovar %s failed, ERR %d\n", - __FUNCTION__, name, ret)); - } - } else { - DHD_ERROR(("%s: mkiovar %s failed\n", - __FUNCTION__, name)); - } - - return ret; -} - -int -dhd_wl_ioctl_set_intiovar(dhd_pub_t *dhd_pub, char *name, uint val, - int cmd, uint8 set, int ifidx) -{ - char iovbuf[WLC_IOCTL_SMLEN] = {0}; - int ret = -1; - int lval = htol32(val); - uint len; - - len = bcm_mkiovar(name, (char*)&lval, sizeof(lval), iovbuf, sizeof(iovbuf)); - - if (len) { - ret = dhd_wl_ioctl_cmd(dhd_pub, cmd, iovbuf, len, set, ifidx); - if (ret) { - DHD_ERROR(("%s: set int iovar %s failed, ERR %d\n", - __FUNCTION__, name, ret)); - } - } else { - DHD_ERROR(("%s: mkiovar %s failed\n", - __FUNCTION__, name)); - } - - return ret; -} - -int -dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifidx, wl_ioctl_t *ioc, void *buf, int len) -{ - int ret = BCME_ERROR; - unsigned long flags; -#ifdef DUMP_IOCTL_IOV_LIST - dhd_iov_li_t *iov_li; -#endif /* DUMP_IOCTL_IOV_LIST */ -#ifdef KEEPIF_ON_DEVICE_RESET - if (ioc->cmd == WLC_GET_VAR) { - dbus_config_t config; - config.general_param = 0; - if (!strcmp(buf, "wowl_activate")) { - config.general_param = 2; /* 1 (TRUE) after decreased by 1 */ - } else if (!strcmp(buf, "wowl_clear")) { - config.general_param = 1; /* 0 (FALSE) after decreased by 1 */ - } - if (config.general_param) { - config.config_id = DBUS_CONFIG_ID_KEEPIF_ON_DEVRESET; - config.general_param--; - dbus_set_config(dhd_pub->dbus, &config); - } - } -#endif /* KEEPIF_ON_DEVICE_RESET */ - - if (dhd_chip_alive && ioc->set) { - bool ignore = TRUE; - if (ioc->cmd == WLC_SET_VAR) { - if ((strlen("host_off") == strnlen(ioc->buf, ioc->len)) && - (strncmp((char*)ioc->buf, "host_off", 8) == 0)) { - DHD_INFO(("set iovar %s allowed\n", (char *)ioc->buf)); - ignore = FALSE; - } else { - DHD_INFO(("set iovar %s ignored\n", (char *)ioc->buf)); - } - } else { - DHD_INFO(("set cmd %d ignored\n", ioc->cmd)); - } - if (ignore) - return 0; - } - - if (dhd_pub->padsiso) { - if (ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) { - DHD_INFO(("%s iovar %s ignored\n", - ioc->set ? "set" : "get", (char *)ioc->buf)); - } else { - DHD_INFO(("%s cmd %d ignored\n", - ioc->set ? "set" : "get", ioc->cmd)); - } - return 0; - } - -#ifdef HAL_API - if (ioc->cmd == WLC_SET_VAR && buf && - strlen("host_off") == strnlen(buf, len) && - strncmp(buf, "host_off", 8) == 0) { - int val = 0; - memcpy(&val, buf + strlen("host_off") + 1, 4); - dhd_pub->block_fw_cmd = (val == 1); - DHD_ERROR(("block_fw_cmd, val = %d\n", dhd_pub->block_fw_cmd)); - } else if (dhd_pub->block_fw_cmd) { - DHD_ERROR(("block_cmd: cmd %d\n", ioc->cmd)); - if ((ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) && buf) { - prhex("cmd_dump", buf, len > 16 ? 16 : len); - } - return 0; - } -#endif /* HAL_API */ - - if (dhd_os_proto_block(dhd_pub)) - { -#ifdef DHD_LOG_DUMP - int slen, i, val, rem, lval, min_len; - char *pval, *pos, *msg; - char tmp[64]; - - /* WLC_GET_VAR */ - if (ioc->cmd == WLC_GET_VAR) { - min_len = MIN(sizeof(tmp) - 1, strlen(buf)); - memset(tmp, 0, sizeof(tmp)); - bcopy(buf, tmp, min_len); - tmp[min_len] = '\0'; - } -#endif /* DHD_LOG_DUMP */ - DHD_LINUX_GENERAL_LOCK(dhd_pub, flags); - if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd_pub)) { -#ifdef DHD_EFI - DHD_INFO(("%s: returning as busstate=%d\n", - __FUNCTION__, dhd_pub->busstate)); -#else - DHD_ERROR(("%s: returning as busstate=%d\n", - __FUNCTION__, dhd_pub->busstate)); -#endif /* DHD_EFI */ - DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); - dhd_os_proto_unblock(dhd_pub); - return -ENODEV; - } - DHD_BUS_BUSY_SET_IN_IOVAR(dhd_pub); - DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); - -#ifdef DHD_PCIE_RUNTIMEPM - dhdpcie_runtime_bus_wake(dhd_pub, TRUE, dhd_wl_ioctl); -#endif /* DHD_PCIE_RUNTIMEPM */ - - DHD_LINUX_GENERAL_LOCK(dhd_pub, flags); - if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhd_pub)) { - DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state!!\n", - __FUNCTION__, dhd_pub->busstate, dhd_pub->dhd_bus_busy_state)); - DHD_BUS_BUSY_CLEAR_IN_IOVAR(dhd_pub); - dhd_os_busbusy_wake(dhd_pub); - DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); - dhd_os_proto_unblock(dhd_pub); - return -ENODEV; - } - DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); - -#if defined(WL_WLC_SHIM) - { - struct wl_shim_node *shim = dhd_pub_shim(dhd_pub); - - wl_io_pport_t io_pport; - io_pport.dhd_pub = dhd_pub; - io_pport.ifidx = ifidx; - - ret = wl_shim_ioctl(shim, ioc, len, &io_pport); - if (ret != BCME_OK) { - DHD_TRACE(("%s: wl_shim_ioctl(%d) ERR %d\n", - __FUNCTION__, ioc->cmd, ret)); - } - } -#else -#ifdef DUMP_IOCTL_IOV_LIST - if (ioc->cmd != WLC_GET_MAGIC && ioc->cmd != WLC_GET_VERSION && buf) { - if (!(iov_li = MALLOC(dhd_pub->osh, sizeof(*iov_li)))) { - DHD_ERROR(("iovar dump list item allocation Failed\n")); - } else { - iov_li->cmd = ioc->cmd; - bcopy((char *)buf, iov_li->buff, strlen((char *)buf)+1); - dhd_iov_li_append(dhd_pub, &dhd_pub->dump_iovlist_head, - &iov_li->list); - } - } -#endif /* DUMP_IOCTL_IOV_LIST */ - ret = dhd_prot_ioctl(dhd_pub, ifidx, ioc, buf, len); -#ifdef DUMP_IOCTL_IOV_LIST - if (ret == -ETIMEDOUT) { - DHD_ERROR(("Last %d issued commands: Latest one is at bottom.\n", - IOV_LIST_MAX_LEN)); - dhd_iov_li_print(&dhd_pub->dump_iovlist_head); - } -#endif /* DUMP_IOCTL_IOV_LIST */ -#endif /* defined(WL_WLC_SHIM) */ -#ifdef DHD_LOG_DUMP - if (ioc->cmd == WLC_GET_VAR || ioc->cmd == WLC_SET_VAR) { - lval = 0; - slen = strlen(buf) + 1; - msg = (char*)buf; - if (len >= slen + sizeof(lval)) { - if (ioc->cmd == WLC_GET_VAR) { - msg = tmp; - lval = *(int*)buf; - } else { - min_len = MIN(ioc->len - slen, sizeof(int)); - bcopy((msg + slen), &lval, min_len); - } - } - DHD_ERROR_MEM(("%s: cmd: %d, msg: %s, val: 0x%x, len: %d, set: %d\n", - ioc->cmd == WLC_GET_VAR ? "WLC_GET_VAR" : "WLC_SET_VAR", - ioc->cmd, msg, lval, ioc->len, ioc->set)); - } else { - slen = ioc->len; - if (buf != NULL) { - val = *(int*)buf; - pval = (char*)buf; - pos = tmp; - rem = sizeof(tmp); - memset(tmp, 0, sizeof(tmp)); - for (i = 0; i < slen; i++) { - if (rem <= 3) { - /* At least 2 byte required + 1 byte(NULL) */ - break; - } - pos += snprintf(pos, rem, "%02x ", pval[i]); - rem = sizeof(tmp) - (int)(pos - tmp); - } - /* Do not dump for WLC_GET_MAGIC and WLC_GET_VERSION */ - if (ioc->cmd != WLC_GET_MAGIC && ioc->cmd != WLC_GET_VERSION) - DHD_ERROR_MEM(("WLC_IOCTL: cmd: %d, val: %d(%s), " - "len: %d, set: %d\n", - ioc->cmd, val, tmp, ioc->len, ioc->set)); - } else { - DHD_ERROR_MEM(("WLC_IOCTL: cmd: %d, buf is NULL\n", ioc->cmd)); - } - } -#endif /* DHD_LOG_DUMP */ - if (ret && dhd_pub->up) { - /* Send hang event only if dhd_open() was success */ - dhd_os_check_hang(dhd_pub, ifidx, ret); - } - - if (ret == -ETIMEDOUT && !dhd_pub->up) { - DHD_ERROR(("%s: 'resumed on timeout' error is " - "occurred before the interface does not" - " bring up\n", __FUNCTION__)); - dhd_pub->busstate = DHD_BUS_DOWN; - } - - DHD_LINUX_GENERAL_LOCK(dhd_pub, flags); - DHD_BUS_BUSY_CLEAR_IN_IOVAR(dhd_pub); - dhd_os_busbusy_wake(dhd_pub); - DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); - - dhd_os_proto_unblock(dhd_pub); - - } - - return ret; -} - -uint wl_get_port_num(wl_io_pport_t *io_pport) -{ - return 0; -} - -/* Get bssidx from iovar params - * Input: dhd_pub - pointer to dhd_pub_t - * params - IOVAR params - * Output: idx - BSS index - * val - ponter to the IOVAR arguments - */ -static int -dhd_iovar_parse_bssidx(dhd_pub_t *dhd_pub, const char *params, uint32 *idx, const char **val) -{ - char *prefix = "bsscfg:"; - uint32 bssidx; - - if (!(strncmp(params, prefix, strlen(prefix)))) { - /* per bss setting should be prefixed with 'bsscfg:' */ - const char *p = params + strlen(prefix); - - /* Skip Name */ - while (*p != '\0') - p++; - /* consider null */ - p = p + 1; - bcopy(p, &bssidx, sizeof(uint32)); - /* Get corresponding dhd index */ - bssidx = dhd_bssidx2idx(dhd_pub, htod32(bssidx)); - - if (bssidx >= DHD_MAX_IFS) { - DHD_ERROR(("%s Wrong bssidx provided\n", __FUNCTION__)); - return BCME_ERROR; - } - - /* skip bss idx */ - p += sizeof(uint32); - *val = p; - *idx = bssidx; - } else { - DHD_ERROR(("%s: bad parameter for per bss iovar\n", __FUNCTION__)); - return BCME_ERROR; - } - - return BCME_OK; -} - -#if defined(DHD_DEBUG) && defined(BCMDBUS) -/* USB Device console input function */ -int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen) -{ - DHD_TRACE(("%s \n", __FUNCTION__)); - - return dhd_iovar(dhd, 0, "cons", msg, msglen, NULL, 0, TRUE); - -} -#endif /* DHD_DEBUG && BCMDBUS */ - -#ifdef DHD_DEBUG -int -dhd_mem_debug(dhd_pub_t *dhd, char *msg, uint msglen) -{ - unsigned long int_arg = 0; - char *p; - char *end_ptr = NULL; - dhd_dbg_mwli_t *mw_li; - dll_t *item, *next; - /* check if mwalloc, mwquery or mwfree was supplied arguement with space */ - p = bcmstrstr(msg, " "); - if (p != NULL) { - /* space should be converted to null as separation flag for firmware */ - *p = '\0'; - /* store the argument in int_arg */ - int_arg = bcm_strtoul(p+1, &end_ptr, 10); - } - - if (!p && !strcmp(msg, "query")) { - /* lets query the list inetrnally */ - if (dll_empty(dll_head_p(&dhd->mw_list_head))) { - DHD_ERROR(("memwaste list is empty, call mwalloc < size > to allocate\n")); - /* reset the id */ - dhd->mw_id = 0; - } else { - for (item = dll_head_p(&dhd->mw_list_head); - !dll_end(&dhd->mw_list_head, item); item = next) { - next = dll_next_p(item); - mw_li = (dhd_dbg_mwli_t *)CONTAINEROF(item, dhd_dbg_mwli_t, list); - DHD_ERROR(("item: <id=%d, size=%d>\n", mw_li->id, mw_li->size)); - } - } - } else if (p && end_ptr && (*end_ptr == '\0') && !strcmp(msg, "alloc")) { - int32 alloc_handle; - /* convert size into KB and append as integer */ - *((int32 *)(p+1)) = int_arg*1024; - *(p+1+sizeof(int32)) = '\0'; - - /* recalculated length -> 5 bytes for "alloc" + 4 bytes for size + - *1 bytes for null caracter - */ - msglen = strlen(msg) + sizeof(int32) + 1; - if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, msg, msglen, FALSE, 0) < 0) { - DHD_ERROR(("IOCTL failed for memdebug alloc\n")); - } - - /* returned allocated handle from dongle, basically address of the allocated unit */ - alloc_handle = *((int32 *)msg); - - /* add a node in the list with tuple <id, handle, size> */ - if (alloc_handle == 0) { - DHD_ERROR(("Reuqested size could not be allocated\n")); - } else if (!(mw_li = MALLOC(dhd->osh, sizeof(*mw_li)))) { - DHD_ERROR(("mw list item allocation Failed\n")); - } else { - mw_li->id = dhd->mw_id++; - mw_li->handle = alloc_handle; - mw_li->size = int_arg; - /* append the node in the list */ - dll_append(&dhd->mw_list_head, &mw_li->list); - } - } else if (p && end_ptr && (*end_ptr == '\0') && !strcmp(msg, "free")) { - /* inform dongle to free wasted chunk */ - int handle = 0; - int size = 0; - for (item = dll_head_p(&dhd->mw_list_head); - !dll_end(&dhd->mw_list_head, item); item = next) { - next = dll_next_p(item); - mw_li = (dhd_dbg_mwli_t *)CONTAINEROF(item, dhd_dbg_mwli_t, list); - - if (mw_li->id == (int)int_arg) { - handle = mw_li->handle; - size = mw_li->size; - dll_delete(item); - MFREE(dhd->osh, mw_li, sizeof(*mw_li)); - } - } - if (handle) { - int len; - /* append the free handle and the chunk size in first 8 bytes - * after the command and null character - */ - *((int32 *)(p+1)) = handle; - *((int32 *)((p+1)+sizeof(int32))) = size; - /* append null as terminator */ - *(p+1+2*sizeof(int32)) = '\0'; - /* recalculated length -> 4 bytes for "free" + 8 bytes for hadnle and size - * + 1 bytes for null caracter - */ - len = strlen(msg) + 2*sizeof(int32) + 1; - /* send iovar to free the chunk */ - if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, msg, len, FALSE, 0) < 0) { - DHD_ERROR(("IOCTL failed for memdebug free\n")); - } - } else { - DHD_ERROR(("specified id does not exist\n")); - } - } else { - /* for all the wrong argument formats */ - return BCME_BADARG; - } - return 0; -} - -extern void -dhd_mw_list_delete(dhd_pub_t *dhd, dll_t *list_head) -{ - dll_t *item; - dhd_dbg_mwli_t *mw_li; - while (!(dll_empty(list_head))) { - item = dll_head_p(list_head); - mw_li = (dhd_dbg_mwli_t *)CONTAINEROF(item, dhd_dbg_mwli_t, list); - dll_delete(item); - MFREE(dhd->osh, mw_li, sizeof(*mw_li)); - } -} -#endif /* DHD_DEBUG */ - -#ifdef PKT_STATICS -extern pkt_statics_t tx_statics; -extern void dhdsdio_txpktstatics(void); -#endif - -#ifdef SCHED_WAKE -int -dhd_sched_wake_setup(dhd_pub_t *dhdp, uint32 reason) -{ - int ret = 0; - sched_wake_param_t sched_wake_param = {0}; - char iovbuf[WLC_IOCTL_SMLEN] = {0}; - - sched_wake_param.wake_time = dhdp->conf->hostwake_evt_timeout; - sched_wake_param.reason = reason; - memset(iovbuf, 0, sizeof(iovbuf)); - bcm_mkiovar("sched_wake", (char *)&sched_wake_param, - sizeof(sched_wake_param), iovbuf, sizeof(iovbuf)); - ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to set sched_wake, ret=%d\n", - __FUNCTION__, ret)); - } else { - DHD_ERROR(("%s: set schedule wake after %dms, reason %d\n", - __FUNCTION__, - dhdp->conf->hostwake_evt_timeout, - sched_wake_param.reason)); - } - return ret; -} -#endif /* SCHED_WAKE */ - -static int -dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name, - void *params, int plen, void *arg, int len, int val_size) -{ - int bcmerror = 0; - int32 int_val = 0; - uint32 dhd_ver_len, bus_api_rev_len; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name)); - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) - goto exit; - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - switch (actionid) { - case IOV_GVAL(IOV_VERSION): - /* Need to have checked buffer length */ - dhd_ver_len = sizeof(dhd_version) - 1; - bus_api_rev_len = strlen(bus_api_revision); - if (len > dhd_ver_len + bus_api_rev_len) { - memcpy((char *)arg, dhd_version, dhd_ver_len); - memcpy((char *)arg + dhd_ver_len, bus_api_revision, bus_api_rev_len); - *((char *)arg + dhd_ver_len + bus_api_rev_len) = '\0'; - } -#ifdef PKT_STATICS - memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t)); -#endif - break; - - case IOV_GVAL(IOV_WLMSGLEVEL): - DHD_PRINT(("android_msg_level=0x%x\n", android_msg_level)); - DHD_PRINT(("config_msg_level=0x%x\n", config_msg_level)); -#if defined(WL_WIRELESS_EXT) - int_val = (int32)iw_msg_level; - bcopy(&int_val, arg, val_size); - DHD_PRINT(("iw_msg_level=0x%x\n", iw_msg_level)); -#endif -#ifdef WL_CFG80211 - int_val = (int32)wl_dbg_level; - bcopy(&int_val, arg, val_size); - DHD_PRINT(("cfg_msg_level=0x%x\n", wl_dbg_level)); -#endif - break; - - case IOV_SVAL(IOV_WLMSGLEVEL): - if (int_val & DHD_ANDROID_VAL) { - android_msg_level = (uint)(int_val & 0xFFFF); - DHD_PRINT(("android_msg_level=0x%x\n", android_msg_level)); - } - if (int_val & DHD_CONFIG_VAL) { - config_msg_level = (uint)(int_val & 0xFFFF); - DHD_PRINT(("config_msg_level=0x%x\n", config_msg_level)); - } -#if defined(WL_WIRELESS_EXT) - if (int_val & DHD_IW_VAL) { - iw_msg_level = (uint)(int_val & 0xFFFF); - DHD_PRINT(("iw_msg_level=0x%x\n", iw_msg_level)); - } -#endif -#ifdef WL_CFG80211 - if (int_val & DHD_CFG_VAL) { - wl_cfg80211_enable_trace((u32)(int_val & 0xFFFF)); - } -#endif - break; - - case IOV_GVAL(IOV_MSGLEVEL): - int_val = (int32)dhd_msg_level; - bcopy(&int_val, arg, val_size); -#ifdef PKT_STATICS - dhdsdio_txpktstatics(); -#endif - break; - - case IOV_SVAL(IOV_MSGLEVEL): - dhd_msg_level = int_val; - break; - - case IOV_GVAL(IOV_BCMERRORSTR): - bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); - ((char *)arg)[BCME_STRLEN - 1] = 0x00; - break; - - case IOV_GVAL(IOV_BCMERROR): - int_val = (int32)dhd_pub->bcmerror; - bcopy(&int_val, arg, val_size); - break; - -#ifndef BCMDBUS - case IOV_GVAL(IOV_WDTICK): - int_val = (int32)dhd_watchdog_ms; - bcopy(&int_val, arg, val_size); - break; -#endif /* !BCMDBUS */ - - case IOV_SVAL(IOV_WDTICK): - if (!dhd_pub->up) { - bcmerror = BCME_NOTUP; - break; - } - - if (CUSTOM_DHD_WATCHDOG_MS == 0 && int_val == 0) { - dhd_watchdog_ms = (uint)int_val; - } - - dhd_os_wd_timer(dhd_pub, (uint)int_val); - break; - - case IOV_GVAL(IOV_DUMP): - bcmerror = dhd_dump(dhd_pub, arg, len); - break; - -#ifndef BCMDBUS - case IOV_GVAL(IOV_DCONSOLE_POLL): - int_val = (int32)dhd_console_ms; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DCONSOLE_POLL): - dhd_console_ms = (uint)int_val; - break; - - case IOV_SVAL(IOV_CONS): - if (len > 0) - bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1); - break; -#endif /* !BCMDBUS */ - - case IOV_SVAL(IOV_CLEARCOUNTS): - dhd_pub->tx_packets = dhd_pub->rx_packets = 0; - dhd_pub->tx_errors = dhd_pub->rx_errors = 0; - dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0; - dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0; - dhd_pub->tx_dropped = 0; - dhd_pub->rx_dropped = 0; - dhd_pub->tx_pktgetfail = 0; - dhd_pub->rx_pktgetfail = 0; - dhd_pub->rx_readahead_cnt = 0; - dhd_pub->tx_realloc = 0; - dhd_pub->wd_dpc_sched = 0; - memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats)); - dhd_bus_clearcounts(dhd_pub); -#ifdef PROP_TXSTATUS - /* clear proptxstatus related counters */ - dhd_wlfc_clear_counts(dhd_pub); -#endif /* PROP_TXSTATUS */ -#if defined(DHD_LB_STATS) - DHD_LB_STATS_RESET(dhd_pub); -#endif /* DHD_LB_STATS */ - break; - - - case IOV_GVAL(IOV_IOCTLTIMEOUT): { - int_val = (int32)dhd_os_get_ioctl_resp_timeout(); - bcopy(&int_val, arg, sizeof(int_val)); - break; - } - - case IOV_SVAL(IOV_IOCTLTIMEOUT): { - if (int_val <= 0) - bcmerror = BCME_BADARG; - else - dhd_os_set_ioctl_resp_timeout((unsigned int)int_val); - break; - } - -#ifdef PROP_TXSTATUS - case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): { - bool wlfc_enab = FALSE; - bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab); - if (bcmerror != BCME_OK) - goto exit; - int_val = wlfc_enab ? 1 : 0; - bcopy(&int_val, arg, val_size); - break; - } - case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE): { - bool wlfc_enab = FALSE; - bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab); - if (bcmerror != BCME_OK) - goto exit; - - /* wlfc is already set as desired */ - if (wlfc_enab == (int_val == 0 ? FALSE : TRUE)) - goto exit; - - if (int_val == TRUE) - bcmerror = dhd_wlfc_init(dhd_pub); - else - bcmerror = dhd_wlfc_deinit(dhd_pub); - - break; - } - case IOV_GVAL(IOV_PROPTXSTATUS_MODE): - bcmerror = dhd_wlfc_get_mode(dhd_pub, &int_val); - if (bcmerror != BCME_OK) - goto exit; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PROPTXSTATUS_MODE): - dhd_wlfc_set_mode(dhd_pub, int_val); - break; - - case IOV_GVAL(IOV_PROPTXSTATUS_MODULE_IGNORE): - bcmerror = dhd_wlfc_get_module_ignore(dhd_pub, &int_val); - if (bcmerror != BCME_OK) - goto exit; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PROPTXSTATUS_MODULE_IGNORE): - dhd_wlfc_set_module_ignore(dhd_pub, int_val); - break; - - case IOV_GVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE): - bcmerror = dhd_wlfc_get_credit_ignore(dhd_pub, &int_val); - if (bcmerror != BCME_OK) - goto exit; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE): - dhd_wlfc_set_credit_ignore(dhd_pub, int_val); - break; - - case IOV_GVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE): - bcmerror = dhd_wlfc_get_txstatus_ignore(dhd_pub, &int_val); - if (bcmerror != BCME_OK) - goto exit; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE): - dhd_wlfc_set_txstatus_ignore(dhd_pub, int_val); - break; - - case IOV_GVAL(IOV_PROPTXSTATUS_RXPKT_CHK): - bcmerror = dhd_wlfc_get_rxpkt_chk(dhd_pub, &int_val); - if (bcmerror != BCME_OK) - goto exit; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PROPTXSTATUS_RXPKT_CHK): - dhd_wlfc_set_rxpkt_chk(dhd_pub, int_val); - break; - -#endif /* PROP_TXSTATUS */ - - case IOV_GVAL(IOV_BUS_TYPE): - /* The dhd application queries the driver to check if its usb or sdio. */ -#ifdef BCMDBUS - int_val = BUS_TYPE_USB; -#endif /* BCMDBUS */ -#ifdef BCMSDIO - int_val = BUS_TYPE_SDIO; -#endif -#ifdef PCIE_FULL_DONGLE - int_val = BUS_TYPE_PCIE; -#endif - bcopy(&int_val, arg, val_size); - break; - - -#ifdef WLMEDIA_HTSF - case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ): - int_val = dhd_pub->htsfdlystat_sz; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ): - dhd_pub->htsfdlystat_sz = int_val & 0xff; - DHD_PRINT(("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz)); - break; -#endif - case IOV_SVAL(IOV_CHANGEMTU): - int_val &= 0xffff; - bcmerror = dhd_change_mtu(dhd_pub, int_val, 0); - break; - - case IOV_GVAL(IOV_HOSTREORDER_FLOWS): - { - uint i = 0; - uint8 *ptr = (uint8 *)arg; - uint8 count = 0; - - ptr++; - for (i = 0; i < WLHOST_REORDERDATA_MAXFLOWS; i++) { - if (dhd_pub->reorder_bufs[i] != NULL) { - *ptr = dhd_pub->reorder_bufs[i]->flow_id; - ptr++; - count++; - } - } - ptr = (uint8 *)arg; - *ptr = count; - break; - } -#ifdef DHDTCPACK_SUPPRESS - case IOV_GVAL(IOV_TCPACK_SUPPRESS): { - int_val = (uint32)dhd_pub->tcpack_sup_mode; - bcopy(&int_val, arg, val_size); - break; - } - case IOV_SVAL(IOV_TCPACK_SUPPRESS): { - bcmerror = dhd_tcpack_suppress_set(dhd_pub, (uint8)int_val); - break; - } -#endif /* DHDTCPACK_SUPPRESS */ -#ifdef DHD_WMF - case IOV_GVAL(IOV_WMF_BSS_ENAB): { - uint32 bssidx; - dhd_wmf_t *wmf; - const char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: wmf_bss_enable: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - - wmf = dhd_wmf_conf(dhd_pub, bssidx); - int_val = wmf->wmf_enable ? 1 :0; - bcopy(&int_val, arg, val_size); - break; - } - case IOV_SVAL(IOV_WMF_BSS_ENAB): { - /* Enable/Disable WMF */ - uint32 bssidx; - dhd_wmf_t *wmf; - const char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: wmf_bss_enable: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - - ASSERT(val); - bcopy(val, &int_val, sizeof(uint32)); - wmf = dhd_wmf_conf(dhd_pub, bssidx); - if (wmf->wmf_enable == int_val) - break; - if (int_val) { - /* Enable WMF */ - if (dhd_wmf_instance_add(dhd_pub, bssidx) != BCME_OK) { - DHD_ERROR(("%s: Error in creating WMF instance\n", - __FUNCTION__)); - break; - } - if (dhd_wmf_start(dhd_pub, bssidx) != BCME_OK) { - DHD_ERROR(("%s: Failed to start WMF\n", __FUNCTION__)); - break; - } - wmf->wmf_enable = TRUE; - } else { - /* Disable WMF */ - wmf->wmf_enable = FALSE; - dhd_wmf_stop(dhd_pub, bssidx); - dhd_wmf_instance_del(dhd_pub, bssidx); - } - break; - } - case IOV_GVAL(IOV_WMF_UCAST_IGMP): - int_val = dhd_pub->wmf_ucast_igmp ? 1 : 0; - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_WMF_UCAST_IGMP): - if (dhd_pub->wmf_ucast_igmp == int_val) - break; - - if (int_val >= OFF && int_val <= ON) - dhd_pub->wmf_ucast_igmp = int_val; - else - bcmerror = BCME_RANGE; - break; - case IOV_GVAL(IOV_WMF_MCAST_DATA_SENDUP): - int_val = dhd_wmf_mcast_data_sendup(dhd_pub, 0, FALSE, FALSE); - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_WMF_MCAST_DATA_SENDUP): - dhd_wmf_mcast_data_sendup(dhd_pub, 0, TRUE, int_val); - break; - -#ifdef WL_IGMP_UCQUERY - case IOV_GVAL(IOV_WMF_UCAST_IGMP_QUERY): - int_val = dhd_pub->wmf_ucast_igmp_query ? 1 : 0; - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_WMF_UCAST_IGMP_QUERY): - if (dhd_pub->wmf_ucast_igmp_query == int_val) - break; - - if (int_val >= OFF && int_val <= ON) - dhd_pub->wmf_ucast_igmp_query = int_val; - else - bcmerror = BCME_RANGE; - break; -#endif /* WL_IGMP_UCQUERY */ -#ifdef DHD_UCAST_UPNP - case IOV_GVAL(IOV_WMF_UCAST_UPNP): - int_val = dhd_pub->wmf_ucast_upnp ? 1 : 0; - bcopy(&int_val, arg, val_size); - break; - case IOV_SVAL(IOV_WMF_UCAST_UPNP): - if (dhd_pub->wmf_ucast_upnp == int_val) - break; - - if (int_val >= OFF && int_val <= ON) - dhd_pub->wmf_ucast_upnp = int_val; - else - bcmerror = BCME_RANGE; - break; -#endif /* DHD_UCAST_UPNP */ - - case IOV_GVAL(IOV_WMF_PSTA_DISABLE): { - uint32 bssidx; - const char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: ap isoalate: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - - int_val = dhd_get_wmf_psta_disable(dhd_pub, bssidx); - bcopy(&int_val, arg, val_size); - break; - } - - case IOV_SVAL(IOV_WMF_PSTA_DISABLE): { - uint32 bssidx; - const char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: ap isolate: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - - ASSERT(val); - bcopy(val, &int_val, sizeof(uint32)); - dhd_set_wmf_psta_disable(dhd_pub, bssidx, int_val); - break; - } -#endif /* DHD_WMF */ - -#if defined(TRAFFIC_MGMT_DWM) - case IOV_SVAL(IOV_TRAFFIC_MGMT_DWM): { - trf_mgmt_filter_list_t *trf_mgmt_filter_list = - (trf_mgmt_filter_list_t *)(arg); - bcmerror = traffic_mgmt_add_dwm_filter(dhd_pub, trf_mgmt_filter_list, len); - } - break; -#endif - -#ifdef DHD_L2_FILTER - case IOV_GVAL(IOV_DHCP_UNICAST): { - uint32 bssidx; - const char *val; - if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: IOV_DHCP_UNICAST: bad parameterand name = %s\n", - __FUNCTION__, name)); - bcmerror = BCME_BADARG; - break; - } - int_val = dhd_get_dhcp_unicast_status(dhd_pub, bssidx); - memcpy(arg, &int_val, val_size); - break; - } - case IOV_SVAL(IOV_DHCP_UNICAST): { - uint32 bssidx; - const char *val; - if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: IOV_DHCP_UNICAST: bad parameterand name = %s\n", - __FUNCTION__, name)); - bcmerror = BCME_BADARG; - break; - } - memcpy(&int_val, val, sizeof(int_val)); - bcmerror = dhd_set_dhcp_unicast_status(dhd_pub, bssidx, int_val ? 1 : 0); - break; - } - case IOV_GVAL(IOV_BLOCK_PING): { - uint32 bssidx; - const char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: IOV_BLOCK_PING: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - int_val = dhd_get_block_ping_status(dhd_pub, bssidx); - memcpy(arg, &int_val, val_size); - break; - } - case IOV_SVAL(IOV_BLOCK_PING): { - uint32 bssidx; - const char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: IOV_BLOCK_PING: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - memcpy(&int_val, val, sizeof(int_val)); - bcmerror = dhd_set_block_ping_status(dhd_pub, bssidx, int_val ? 1 : 0); - break; - } - case IOV_GVAL(IOV_PROXY_ARP): { - uint32 bssidx; - const char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: IOV_PROXY_ARP: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - int_val = dhd_get_parp_status(dhd_pub, bssidx); - bcopy(&int_val, arg, val_size); - break; - } - case IOV_SVAL(IOV_PROXY_ARP): { - uint32 bssidx; - const char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: IOV_PROXY_ARP: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - bcopy(val, &int_val, sizeof(int_val)); - - /* Issue a iovar request to WL to update the proxy arp capability bit - * in the Extended Capability IE of beacons/probe responses. - */ - bcmerror = dhd_iovar(dhd_pub, bssidx, "proxy_arp_advertise", val, sizeof(int_val), - NULL, 0, TRUE); - if (bcmerror == BCME_OK) { - dhd_set_parp_status(dhd_pub, bssidx, int_val ? 1 : 0); - } - break; - } - case IOV_GVAL(IOV_GRAT_ARP): { - uint32 bssidx; - const char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: IOV_GRAT_ARP: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - int_val = dhd_get_grat_arp_status(dhd_pub, bssidx); - memcpy(arg, &int_val, val_size); - break; - } - case IOV_SVAL(IOV_GRAT_ARP): { - uint32 bssidx; - const char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: IOV_GRAT_ARP: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - memcpy(&int_val, val, sizeof(int_val)); - bcmerror = dhd_set_grat_arp_status(dhd_pub, bssidx, int_val ? 1 : 0); - break; - } -#endif /* DHD_L2_FILTER */ - case IOV_SVAL(IOV_DHD_IE): { - uint32 bssidx; - const char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: dhd ie: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - - break; - } - case IOV_GVAL(IOV_AP_ISOLATE): { - uint32 bssidx; - const char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: ap isoalate: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - - int_val = dhd_get_ap_isolate(dhd_pub, bssidx); - bcopy(&int_val, arg, val_size); - break; - } - case IOV_SVAL(IOV_AP_ISOLATE): { - uint32 bssidx; - const char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: ap isolate: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - - ASSERT(val); - bcopy(val, &int_val, sizeof(uint32)); - dhd_set_ap_isolate(dhd_pub, bssidx, int_val); - break; - } -#ifdef DHD_PSTA - case IOV_GVAL(IOV_PSTA): { - int_val = dhd_get_psta_mode(dhd_pub); - bcopy(&int_val, arg, val_size); - break; - } - case IOV_SVAL(IOV_PSTA): { - if (int_val >= DHD_MODE_PSTA_DISABLED && int_val <= DHD_MODE_PSR) { - dhd_set_psta_mode(dhd_pub, int_val); - } else { - bcmerror = BCME_RANGE; - } - break; - } -#endif /* DHD_PSTA */ -#ifdef DHD_WET - case IOV_GVAL(IOV_WET): - int_val = dhd_get_wet_mode(dhd_pub); - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_WET): - if (int_val == 0 || int_val == 1) { - dhd_set_wet_mode(dhd_pub, int_val); - /* Delete the WET DB when disabled */ - if (!int_val) { - dhd_wet_sta_delete_list(dhd_pub); - } - } else { - bcmerror = BCME_RANGE; - } - break; - case IOV_SVAL(IOV_WET_HOST_IPV4): - dhd_set_wet_host_ipv4(dhd_pub, params, plen); - break; - case IOV_SVAL(IOV_WET_HOST_MAC): - dhd_set_wet_host_mac(dhd_pub, params, plen); - break; -#endif /* DHD_WET */ -#ifdef DHD_MCAST_REGEN - case IOV_GVAL(IOV_MCAST_REGEN_BSS_ENABLE): { - uint32 bssidx; - const char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: mcast_regen_bss_enable: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - - int_val = dhd_get_mcast_regen_bss_enable(dhd_pub, bssidx); - bcopy(&int_val, arg, val_size); - break; - } - - case IOV_SVAL(IOV_MCAST_REGEN_BSS_ENABLE): { - uint32 bssidx; - const char *val; - - if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) { - DHD_ERROR(("%s: mcast_regen_bss_enable: bad parameter\n", __FUNCTION__)); - bcmerror = BCME_BADARG; - break; - } - - ASSERT(val); - bcopy(val, &int_val, sizeof(uint32)); - dhd_set_mcast_regen_bss_enable(dhd_pub, bssidx, int_val); - break; - } -#endif /* DHD_MCAST_REGEN */ - - case IOV_GVAL(IOV_CFG80211_OPMODE): { - int_val = (int32)dhd_pub->op_mode; - bcopy(&int_val, arg, sizeof(int_val)); - break; - } - case IOV_SVAL(IOV_CFG80211_OPMODE): { - if (int_val <= 0) - bcmerror = BCME_BADARG; - else - dhd_pub->op_mode = int_val; - break; - } - - case IOV_GVAL(IOV_ASSERT_TYPE): - int_val = g_assert_type; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_ASSERT_TYPE): - g_assert_type = (uint32)int_val; - break; - - -#if !defined(MACOSX_DHD) - case IOV_GVAL(IOV_LMTEST): { - *(uint32 *)arg = (uint32)lmtest; - break; - } - - case IOV_SVAL(IOV_LMTEST): { - uint32 val = *(uint32 *)arg; - if (val > 50) - bcmerror = BCME_BADARG; - else { - lmtest = (uint)val; - DHD_ERROR(("%s: lmtest %s\n", - __FUNCTION__, (lmtest == FALSE)? "OFF" : "ON")); - } - break; - } -#endif - -#ifdef SHOW_LOGTRACE - case IOV_GVAL(IOV_DUMP_TRACE_LOG): { - trace_buf_info_t *trace_buf_info; - - trace_buf_info = (trace_buf_info_t *)MALLOC(dhd_pub->osh, - sizeof(trace_buf_info_t)); - if (trace_buf_info != NULL) { - dhd_get_read_buf_ptr(dhd_pub, trace_buf_info); - memcpy((void*)arg, (void*)trace_buf_info, sizeof(trace_buf_info_t)); - MFREE(dhd_pub->osh, trace_buf_info, sizeof(trace_buf_info_t)); - } else { - DHD_ERROR(("Memory allocation Failed\n")); - bcmerror = BCME_NOMEM; - } - break; - } -#endif /* SHOW_LOGTRACE */ -#ifdef REPORT_FATAL_TIMEOUTS - case IOV_GVAL(IOV_SCAN_TO): { - dhd_get_scan_to_val(dhd_pub, (uint32 *)&int_val); - bcopy(&int_val, arg, val_size); - break; - } - case IOV_SVAL(IOV_SCAN_TO): { - dhd_set_scan_to_val(dhd_pub, (uint32)int_val); - break; - } - case IOV_GVAL(IOV_JOIN_TO): { - dhd_get_join_to_val(dhd_pub, (uint32 *)&int_val); - bcopy(&int_val, arg, val_size); - break; - } - case IOV_SVAL(IOV_JOIN_TO): { - dhd_set_join_to_val(dhd_pub, (uint32)int_val); - break; - } - case IOV_GVAL(IOV_CMD_TO): { - dhd_get_cmd_to_val(dhd_pub, (uint32 *)&int_val); - bcopy(&int_val, arg, val_size); - break; - } - case IOV_SVAL(IOV_CMD_TO): { - dhd_set_cmd_to_val(dhd_pub, (uint32)int_val); - break; - } - case IOV_GVAL(IOV_OQS_TO): { - dhd_get_bus_to_val(dhd_pub, (uint32 *)&int_val); - bcopy(&int_val, arg, val_size); - break; - } - case IOV_SVAL(IOV_OQS_TO): { - dhd_set_bus_to_val(dhd_pub, (uint32)int_val); - break; - } -#endif /* REPORT_FATAL_TIMEOUTS */ -#ifdef DHD_DEBUG -#if defined(BCMSDIO) || defined(BCMPCIE) - case IOV_GVAL(IOV_DONGLE_TRAP_TYPE): { - if (dhd_pub->dongle_trap_occured) - int_val = ltoh32(dhd_pub->last_trap_info.type); - else - int_val = 0; - bcopy(&int_val, arg, val_size); - break; - } - - case IOV_GVAL(IOV_DONGLE_TRAP_INFO): { - struct bcmstrbuf strbuf; - bcm_binit(&strbuf, arg, len); - if (dhd_pub->dongle_trap_occured == FALSE) { - bcm_bprintf(&strbuf, "no trap recorded\n"); - break; - } - dhd_bus_dump_trap_info(dhd_pub->bus, &strbuf); - break; - } - - case IOV_GVAL(IOV_BPADDR): { - sdreg_t sdreg; - uint32 addr, size; - - memcpy(&sdreg, params, sizeof(sdreg)); - - addr = sdreg.offset; - size = sdreg.func; - - bcmerror = dhd_bus_readwrite_bp_addr(dhd_pub, addr, size, - (uint *)&int_val, TRUE); - - memcpy(arg, &int_val, sizeof(int32)); - - break; - } - - case IOV_SVAL(IOV_BPADDR): { - sdreg_t sdreg; - uint32 addr, size; - - memcpy(&sdreg, params, sizeof(sdreg)); - - addr = sdreg.offset; - size = sdreg.func; - - bcmerror = dhd_bus_readwrite_bp_addr(dhd_pub, addr, size, - (uint *)&sdreg.value, - FALSE); - - break; - } -#endif /* BCMSDIO || BCMPCIE */ - case IOV_SVAL(IOV_MEM_DEBUG): { - if (len > 0) { - bcmerror = dhd_mem_debug(dhd_pub, arg, len - 1); - } - break; - } -#endif /* DHD_DEBUG */ -#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) - case IOV_GVAL(IOV_LOG_CAPTURE_ENABLE): { - int_val = dhd_pub->log_capture_enable; - bcopy(&int_val, arg, val_size); - break; - } - - case IOV_SVAL(IOV_LOG_CAPTURE_ENABLE): { - dhd_pub->log_capture_enable = (uint8)int_val; - break; - } - - case IOV_GVAL(IOV_LOG_DUMP): { - dhd_prot_debug_info_print(dhd_pub); - dhd_bus_mem_dump(dhd_pub); - break; - } -#endif /* DHD_EFI && DHD_LOG_DUMP */ -#ifdef EVENT_DATA_HOSTWAKE -#ifdef SCHED_WAKE - case IOV_SVAL(IOV_HAL_REQ_SCHED_WAKE): { - dhd_pub->hal_req_sched_wake = (uint8)int_val; - DHD_ERROR(("HAL_REQ_SCHED_WAKE: %d\n", int_val)); - break; - } - - case IOV_SVAL(IOV_HOSTWAKE_EVT_SETUP): { - if (dhd_pub->pending_evt_data || dhd_pub->hal_req_sched_wake) { - bcmerror = dhd_sched_wake_setup(dhd_pub, SCHEDWAKE_RSN_EVTDATA); - } - break; - } -#endif /* SCHED_WAKE */ - case IOV_GVAL(IOV_EVT_DATA_SENDUP): { - int_val = dhd_pub->evt_data_sendup; - bcopy(&int_val, arg, val_size); - break; - } - - case IOV_SVAL(IOV_EVT_DATA_SENDUP): { - dhd_pub->evt_data_sendup = (uint8)int_val; - dhd_pub->pending_evt_data = FALSE; - DHD_ERROR(("Event and data sendup %d\n", int_val)); - break; - } -#endif /* EVENT_DATA_HOSTWAKE */ -#ifdef UART_HB_CONFIG - case IOV_GVAL(IOV_HEARTBEAT): { - int_val = dhd_pub->wowl_alive & WOWL_ALIVE_HB; - bcopy(&int_val, arg, val_size); - break; - } - - case IOV_SVAL(IOV_HEARTBEAT): { - int ret; - bool enable = (uint8)int_val; - if (enable) { - dhd_pub->wowl_alive |= WOWL_ALIVE_HB; - } else { - dhd_pub->wowl_alive &= ~WOWL_ALIVE_HB; - } - ret = dhd_wl_ioctl_set_intiovar(dhd_pub, "wowl_alive", - dhd_pub->wowl_alive, WLC_SET_VAR, TRUE, 0); - if (ret < 0) { - DHD_ERROR(("Failed to set wowl_alive to 0x%02x, ret=%d\n", - dhd_pub->wowl_alive, ret)); - } else { - DHD_ERROR(("successfully set wowl_alive to 0x%02x\n", - dhd_pub->wowl_alive)); - } - break; - } -#endif /* UART_HB_CONFIG */ -#ifdef BCOL_TCPKA_SYNC -#ifdef SCHED_WAKE - case IOV_SVAL(IOV_HOSTWAKE_TCPKA_SETUP): { - bcmerror = dhd_sched_wake_setup(dhd_pub, SCHEDWAKE_RSN_TCPKA_NOTRDY); - break; - } -#endif /* SCHED_WAKE */ - case IOV_SVAL(IOV_TCPKA_ACT_BUF): { - if (tcpka_sync.tcpka_act_buf) { - MFREE(dhd_pub->osh, tcpka_sync.tcpka_act_buf, - tcpka_sync.tcpka_act_buf_len); - tcpka_sync.tcpka_act_buf = NULL; - } - - if (tcpka_sync.tcpka_act_buf == NULL) - tcpka_sync.tcpka_act_buf_len = 0; - - if ((tcpka_sync.tcpka_act_buf = - (unsigned char *)MALLOCZ(dhd_pub->osh, plen)) != NULL) { - tcpka_sync.tcpka_act_buf_len = plen; - memcpy(tcpka_sync.tcpka_act_buf, params, plen); - DHD_ERROR(("Store tcpka actions successfully.\n")); - } else { - DHD_ERROR(("Failed to allocate memory %d bytes " - "for tcpka act buf\n", plen)); - } - break; - } - - case IOV_SVAL(IOV_TCPKA_NOTI_BUF): { - wifi_noti_payload_t *noti_buf = (wifi_noti_payload_t *)params; - uint payload_len = noti_buf->noti_len; - uint noti_buf_len = sizeof(wifi_noti_payload_t) + payload_len - 1; - if (tcpka_sync.tcpka_noti_buf) { - MFREE(dhd_pub->osh, tcpka_sync.tcpka_noti_buf, - tcpka_sync.tcpka_noti_buf_len); - tcpka_sync.tcpka_noti_buf = NULL; - } - - if (tcpka_sync.tcpka_noti_buf == NULL) - tcpka_sync.tcpka_noti_buf_len = 0; - - if ((tcpka_sync.tcpka_noti_buf = - (unsigned char *)MALLOCZ(dhd_pub->osh, noti_buf_len)) != NULL) { - tcpka_sync.tcpka_noti_buf_len = noti_buf_len; - memcpy(tcpka_sync.tcpka_noti_buf, noti_buf, noti_buf_len); - DHD_ERROR(("Store tcpka noti data successfully, buflen %d plen %d", - noti_buf_len, payload_len)); - } else { - DHD_ERROR(("Failed to allocate memory %d bytes " - "for tcpka noti buf\n", noti_buf_len)); - } - break; - } - - case IOV_SVAL(IOV_TCPKA_NOTI_CAPTURE): { - tcpka_noti_pkt_hold_t *nph = (tcpka_noti_pkt_hold_t *)params; - DHD_ERROR(("TCPKA_NOTI_CAPTURE: type %d min_len %d max_len %d\n", - nph->type, nph->min_len, nph->max_len)); - tcpka_sync.tcpka_noti_capture.type = nph->type; - tcpka_sync.tcpka_noti_capture.min_len = nph->min_len; - tcpka_sync.tcpka_noti_capture.max_len = nph->max_len; - break; - } - - case IOV_GVAL(IOV_TCPKA_GET_SYNC_INFO): { - bcol_tcpka_sync_info_t *info = (bcol_tcpka_sync_info_t *)arg; - - if (len < sizeof(bcol_tcpka_sync_info_t)) { - bcmerror = BCME_BUFTOOSHORT; - break; - } - - if (tcpka_sync.tcpka_sync_mode == 0) { - DHD_ERROR(("FW TCPKA is off\n")); - bcmerror = BCME_NOTUP; - break; - } - - if ((tcpka_sync.sess_type == 0 && !tcpka_sync.tcpka_conn) || - (tcpka_sync.sess_type == 1 && !tcpka_sync.tcpka6_conn)) { - DHD_ERROR(("FW %s TCPKA conn info not found\n", - tcpka_sync.sess_type ? "v6" : "v4")); - bcmerror = BCME_NOTFOUND; - break; - } - - info->sync_ip_type = tcpka_sync.sess_type; - info->sync_mode = tcpka_sync.tcpka_sync_mode; - - if (tcpka_sync.sess_type == 0) { //IPv4 - info->src_port = tcpka_sync.tcpka_conn->srcport; - info->dst_port = tcpka_sync.tcpka_conn->dstport; - } else { //IPv6 - info->src_port = tcpka_sync.tcpka6_conn->srcport; - info->dst_port = tcpka_sync.tcpka6_conn->dstport; - } - break; - } - - case IOV_SVAL(IOV_TCPKA_DROP): { - tcpka_sync.tcpka_drop = (uint8)int_val; - DHD_ERROR(("TCPKA_DROP: %d\n", int_val)); - break; - } - - case IOV_SVAL(IOV_TCPKA_REPAIR_BLOCK): { - tcpka_sync.tcpka_repair_block = int_val; - DHD_ERROR(("TCPKA_REPAIR_BLOCK: %d\n", int_val)); - break; - } -#endif /* BCOL_TCPKA_SYNC */ -#ifdef HAL_API - case IOV_SVAL(IOV_BLOCK_FW_CMD): { - dhd_pub->block_fw_cmd = (uint8)int_val; - DHD_ERROR(("BLOCK_FW_CMD: %d\n", int_val)); - break; - } - case IOV_GVAL(IOV_BLOCK_FW_CMD): { - int_val = dhd_pub->block_fw_cmd; - bcopy(&int_val, arg, val_size); - break; - } - case IOV_GVAL(IOV_CFG_ROAM_OFF): { - int_val = dhd_pub->conf->roam_off; - bcopy(&int_val, arg, val_size); - break; - } -#endif /* HAL_API */ - default: - bcmerror = BCME_UNSUPPORTED; - break; - } - -exit: - DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror)); - return bcmerror; -} - -/* Store the status of a connection attempt for later retrieval by an iovar */ -void -dhd_store_conn_status(uint32 event, uint32 status, uint32 reason) -{ - /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID - * because an encryption/rsn mismatch results in both events, and - * the important information is in the WLC_E_PRUNE. - */ - if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL && - dhd_conn_event == WLC_E_PRUNE)) { - dhd_conn_event = event; - dhd_conn_status = status; - dhd_conn_reason = reason; - } -} - -bool -dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) -{ - void *p; - int eprec = -1; /* precedence to evict from */ - bool discard_oldest; - - /* Fast case, precedence queue is not full and we are also not - * exceeding total queue length - */ - if (!pktq_pfull(q, prec) && !pktq_full(q)) { - pktq_penq(q, prec, pkt); - return TRUE; - } - - /* Determine precedence from which to evict packet, if any */ - if (pktq_pfull(q, prec)) - eprec = prec; - else if (pktq_full(q)) { - p = pktq_peek_tail(q, &eprec); - ASSERT(p); - if (eprec > prec || eprec < 0) - return FALSE; - } - - /* Evict if needed */ - if (eprec >= 0) { - /* Detect queueing to unconfigured precedence */ - ASSERT(!pktq_pempty(q, eprec)); - discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec); - if (eprec == prec && !discard_oldest) - return FALSE; /* refuse newer (incoming) packet */ - /* Evict packet according to discard policy */ - p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec); - ASSERT(p); -#ifdef DHDTCPACK_SUPPRESS - if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) { - DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n", - __FUNCTION__, __LINE__)); - dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF); - } -#endif /* DHDTCPACK_SUPPRESS */ - PKTFREE(dhdp->osh, p, TRUE); - } - - /* Enqueue */ - p = pktq_penq(q, prec, pkt); - ASSERT(p); - - return TRUE; -} - -/* - * Functions to drop proper pkts from queue: - * If one pkt in queue is non-fragmented, drop first non-fragmented pkt only - * If all pkts in queue are all fragmented, find and drop one whole set fragmented pkts - * If can't find pkts matching upper 2 cases, drop first pkt anyway - */ -bool -dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_droppkt_t fn) -{ - struct pktq_prec *q = NULL; - void *p, *prev = NULL, *next = NULL, *first = NULL, *last = NULL, *prev_first = NULL; - pkt_frag_t frag_info; - - ASSERT(dhdp && pq); - ASSERT(prec >= 0 && prec < pq->num_prec); - - q = &pq->q[prec]; - p = q->head; - - if (p == NULL) - return FALSE; - - while (p) { - frag_info = pkt_frag_info(dhdp->osh, p); - if (frag_info == DHD_PKT_FRAG_NONE) { - break; - } else if (frag_info == DHD_PKT_FRAG_FIRST) { - if (first) { - /* No last frag pkt, use prev as last */ - last = prev; - break; - } else { - first = p; - prev_first = prev; - } - } else if (frag_info == DHD_PKT_FRAG_LAST) { - if (first) { - last = p; - break; - } - } - - prev = p; - p = PKTLINK(p); - } - - if ((p == NULL) || ((frag_info != DHD_PKT_FRAG_NONE) && !(first && last))) { - /* Not found matching pkts, use oldest */ - prev = NULL; - p = q->head; - frag_info = 0; - } - - if (frag_info == DHD_PKT_FRAG_NONE) { - first = last = p; - prev_first = prev; - } - - p = first; - while (p) { - next = PKTLINK(p); - q->len--; - pq->len--; - - PKTSETLINK(p, NULL); - - if (fn) - fn(dhdp, prec, p, TRUE); - - if (p == last) - break; - - p = next; - } - - if (prev_first == NULL) { - if ((q->head = next) == NULL) - q->tail = NULL; - } else { - PKTSETLINK(prev_first, next); - if (!next) - q->tail = prev_first; - } - - return TRUE; -} - -static int -dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - int bcmerror = 0; - int val_size; - const bcm_iovar_t *vi = NULL; - uint32 actionid; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(name); - ASSERT(len >= 0); - - /* Get MUST have return space */ - ASSERT(set || (arg && len)); - - /* Set does NOT take qualifiers */ - ASSERT(!set || (!params && !plen)); - - if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) { - bcmerror = BCME_UNSUPPORTED; - goto exit; - } - - DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, - name, (set ? "set" : "get"), len, plen)); - - /* set up 'params' pointer in case this is a set command so that - * the convenience int and bool code can be common to set and get - */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - /* all other types are integer sized */ - val_size = sizeof(int); - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - - bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size); - -exit: - return bcmerror; -} - -int -dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen) -{ - int bcmerror = 0; - unsigned long flags; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!buf) { - return BCME_BADARG; - } - - dhd_os_dhdiovar_lock(dhd_pub); - switch (ioc->cmd) { - case DHD_GET_MAGIC: - if (buflen < sizeof(int)) - bcmerror = BCME_BUFTOOSHORT; - else - *(int*)buf = DHD_IOCTL_MAGIC; - break; - - case DHD_GET_VERSION: - if (buflen < sizeof(int)) - bcmerror = BCME_BUFTOOSHORT; - else - *(int*)buf = DHD_IOCTL_VERSION; - break; - - case DHD_GET_VAR: - case DHD_SET_VAR: - { - char *arg; - uint arglen; - - DHD_LINUX_GENERAL_LOCK(dhd_pub, flags); - if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd_pub)) { - /* In platforms like FC19, the FW download is done via IOCTL - * and should not return error for IOCTLs fired before FW - * Download is done - */ - if (dhd_fw_download_status(dhd_pub)) { - DHD_ERROR(("%s: returning as busstate=%d\n", - __FUNCTION__, dhd_pub->busstate)); - DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); - dhd_os_dhdiovar_unlock(dhd_pub); - return -ENODEV; - } - } - DHD_BUS_BUSY_SET_IN_DHD_IOVAR(dhd_pub); - DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); - -#ifdef DHD_PCIE_RUNTIMEPM - dhdpcie_runtime_bus_wake(dhd_pub, TRUE, dhd_ioctl); -#endif /* DHD_PCIE_RUNTIMEPM */ - - DHD_LINUX_GENERAL_LOCK(dhd_pub, flags); - if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhd_pub)) { - /* If Suspend/Resume is tested via pcie_suspend IOVAR - * then continue to execute the IOVAR, return from here for - * other IOVARs, also include pciecfgreg and devreset to go - * through. - */ -#ifdef DHD_EFI - if (bcmstricmp((char *)buf, "pcie_suspend") && - bcmstricmp((char *)buf, "pciecfgreg") && - bcmstricmp((char *)buf, "devreset") && - bcmstricmp((char *)buf, "sdio_suspend") && - bcmstricmp((char *)buf, "control_signal")) -#else - if (bcmstricmp((char *)buf, "pcie_suspend") && - bcmstricmp((char *)buf, "pciecfgreg") && - bcmstricmp((char *)buf, "devreset") && - bcmstricmp((char *)buf, "sdio_suspend")) -#endif /* DHD_EFI */ - { - DHD_ERROR(("%s: bus is in suspend(%d)" - "or suspending(0x%x) state\n", - __FUNCTION__, dhd_pub->busstate, - dhd_pub->dhd_bus_busy_state)); - DHD_BUS_BUSY_CLEAR_IN_DHD_IOVAR(dhd_pub); - dhd_os_busbusy_wake(dhd_pub); - DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); - dhd_os_dhdiovar_unlock(dhd_pub); - return -ENODEV; - } - } - /* During devreset ioctl, we call dhdpcie_advertise_bus_cleanup, - * which will wait for all the busy contexts to get over for - * particular time and call ASSERT if timeout happens. As during - * devreset ioctal, we made DHD_BUS_BUSY_SET_IN_DHD_IOVAR, - * to avoid ASSERT, clear the IOCTL busy state. "devreset" ioctl is - * not used in Production platforms but only used in FC19 setups. - */ - if (!bcmstricmp((char *)buf, "devreset")) { - DHD_BUS_BUSY_CLEAR_IN_DHD_IOVAR(dhd_pub); - } - DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); - - /* scan past the name to any arguments */ - for (arg = buf, arglen = buflen; arglen && *arg; arg++, arglen--) - ; - - if (arglen == 0) { - bcmerror = BCME_BUFTOOSHORT; - goto unlock_exit; - } - - /* account for the NUL terminator */ - arg++, arglen--; - /* call with the appropriate arguments */ - if (ioc->cmd == DHD_GET_VAR) { - bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen, - buf, buflen, IOV_GET); - } else { - bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, - arg, arglen, IOV_SET); - } - if (bcmerror != BCME_UNSUPPORTED) { - goto unlock_exit; - } - - /* not in generic table, try protocol module */ - if (ioc->cmd == DHD_GET_VAR) { - bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg, - arglen, buf, buflen, IOV_GET); - } else { - bcmerror = dhd_prot_iovar_op(dhd_pub, buf, - NULL, 0, arg, arglen, IOV_SET); - } - if (bcmerror != BCME_UNSUPPORTED) { - goto unlock_exit; - } - - /* if still not found, try bus module */ - if (ioc->cmd == DHD_GET_VAR) { - bcmerror = dhd_bus_iovar_op(dhd_pub, buf, - arg, arglen, buf, buflen, IOV_GET); - } else { - bcmerror = dhd_bus_iovar_op(dhd_pub, buf, - NULL, 0, arg, arglen, IOV_SET); - } - if (bcmerror != BCME_UNSUPPORTED) { - goto unlock_exit; - } - -#ifdef DHD_TIMESYNC - /* check TS module */ - if (ioc->cmd == DHD_GET_VAR) - bcmerror = dhd_timesync_iovar_op(dhd_pub->ts, buf, arg, - arglen, buf, buflen, IOV_GET); - else - bcmerror = dhd_timesync_iovar_op(dhd_pub->ts, buf, - NULL, 0, arg, arglen, IOV_SET); -#endif /* DHD_TIMESYNC */ - } - goto unlock_exit; - - default: - bcmerror = BCME_UNSUPPORTED; - } - dhd_os_dhdiovar_unlock(dhd_pub); - return bcmerror; - -unlock_exit: - DHD_LINUX_GENERAL_LOCK(dhd_pub, flags); - DHD_BUS_BUSY_CLEAR_IN_DHD_IOVAR(dhd_pub); - dhd_os_busbusy_wake(dhd_pub); - DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags); - dhd_os_dhdiovar_unlock(dhd_pub); - return bcmerror; -} - -#ifdef SHOW_EVENTS -void -wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data, - void *raw_event_ptr, char *eventmask) -{ - uint i, status, reason; - bool group = FALSE, flush_txq = FALSE, link = FALSE; - bool host_data = FALSE; /* prints event data after the case when set */ - const char *auth_str; - const char *event_name; - uchar *buf; - char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; - uint event_type, flags, auth_type, datalen; - - event_type = ntoh32(event->event_type); - flags = ntoh16(event->flags); - status = ntoh32(event->status); - reason = ntoh32(event->reason); - BCM_REFERENCE(reason); - auth_type = ntoh32(event->auth_type); - datalen = ntoh32(event->datalen); - -#ifdef SIMPLE_MAC_PRINT - /* debug dump of event messages */ - snprintf(eabuf, sizeof(eabuf), "%02x:XX:XX:XX:%02x:%02x", - (uchar)event->addr.octet[0]&0xff, - (uchar)event->addr.octet[4]&0xff, - (uchar)event->addr.octet[5]&0xff); - -#else - /* debug dump of event messages */ - snprintf(eabuf, sizeof(eabuf), "%02x:%02x:%02x:%02x:%02x:%02x", - (uchar)event->addr.octet[0]&0xff, - (uchar)event->addr.octet[1]&0xff, - (uchar)event->addr.octet[2]&0xff, - (uchar)event->addr.octet[3]&0xff, - (uchar)event->addr.octet[4]&0xff, - (uchar)event->addr.octet[5]&0xff); -#endif /* SIMPLE_MAC_PRINT */ - - event_name = bcmevent_get_name(event_type); - BCM_REFERENCE(event_name); - - if (flags & WLC_EVENT_MSG_LINK) - link = TRUE; - if (flags & WLC_EVENT_MSG_GROUP) - group = TRUE; - if (flags & WLC_EVENT_MSG_FLUSHTXQ) - flush_txq = TRUE; - - switch (event_type) { - case WLC_E_START: - case WLC_E_DEAUTH: - case WLC_E_DISASSOC: - DHD_ERROR(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - break; - - case WLC_E_ASSOC_IND: - case WLC_E_REASSOC_IND: - DHD_ERROR(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - break; - - case WLC_E_ASSOC: - case WLC_E_REASSOC: - if (status == WLC_E_STATUS_SUCCESS) { - DHD_ERROR(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf)); - } else if (status == WLC_E_STATUS_TIMEOUT) { - DHD_ERROR(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf)); - } else if (status == WLC_E_STATUS_FAIL) { - DHD_ERROR(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n", - event_name, eabuf, (int)reason)); - } else { - DHD_ERROR(("MACEVENT: %s, MAC %s, unexpected status %d\n", - event_name, eabuf, (int)status)); - } - break; - - case WLC_E_DEAUTH_IND: - case WLC_E_DISASSOC_IND: - DHD_ERROR(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason)); - break; - - case WLC_E_AUTH: - case WLC_E_AUTH_IND: - if (auth_type == DOT11_OPEN_SYSTEM) - auth_str = "Open System"; - else if (auth_type == DOT11_SHARED_KEY) - auth_str = "Shared Key"; - else { - snprintf(err_msg, sizeof(err_msg), "AUTH unknown: %d", (int)auth_type); - auth_str = err_msg; - } - - if (event_type == WLC_E_AUTH_IND) { - DHD_ERROR(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str)); - } else if (status == WLC_E_STATUS_SUCCESS) { - DHD_ERROR(("MACEVENT: %s, MAC %s, %s, SUCCESS\n", - event_name, eabuf, auth_str)); - } else if (status == WLC_E_STATUS_TIMEOUT) { - DHD_ERROR(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n", - event_name, eabuf, auth_str)); - } else if (status == WLC_E_STATUS_FAIL) { - DHD_ERROR(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n", - event_name, eabuf, auth_str, (int)reason)); - } - BCM_REFERENCE(auth_str); - - break; - - case WLC_E_JOIN: - case WLC_E_ROAM: - case WLC_E_SET_SSID: - if (status == WLC_E_STATUS_SUCCESS) { - DHD_ERROR(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); -#ifdef REPORT_FATAL_TIMEOUTS - dhd_clear_join_error(dhd_pub, WLC_SSID_MASK); -#endif /* REPORT_FATAL_TIMEOUTS */ - } else { -#ifdef REPORT_FATAL_TIMEOUTS - dhd_set_join_error(dhd_pub, WLC_SSID_MASK); -#endif /* REPORT_FATAL_TIMEOUTS */ - if (status == WLC_E_STATUS_FAIL) { - DHD_ERROR(("MACEVENT: %s, failed\n", event_name)); - } else if (status == WLC_E_STATUS_NO_NETWORKS) { - DHD_ERROR(("MACEVENT: %s, no networks found\n", event_name)); - } else { - DHD_ERROR(("MACEVENT: %s, unexpected status %d\n", - event_name, (int)status)); - } - } - break; - - case WLC_E_BEACON_RX: - if (status == WLC_E_STATUS_SUCCESS) { - DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name)); - } else if (status == WLC_E_STATUS_FAIL) { - DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name)); - } else { - DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status)); - } - break; - - case WLC_E_LINK: - DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN")); - BCM_REFERENCE(link); - break; - - case WLC_E_MIC_ERROR: - DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n", - event_name, eabuf, group, flush_txq)); - BCM_REFERENCE(group); - BCM_REFERENCE(flush_txq); - break; - - case WLC_E_ICV_ERROR: - case WLC_E_UNICAST_DECODE_ERROR: - case WLC_E_MULTICAST_DECODE_ERROR: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", - event_name, eabuf)); - break; - - case WLC_E_TXFAIL: - DHD_EVENT(("MACEVENT: %s, RA %s status %d\n", event_name, eabuf, status)); - break; - -#ifdef HAL_API - case WLC_E_DHCPC_EVENT: - case WLC_E_ONLINE_CHK_EVENT: - case WLC_E_ONLINE_CHK_HOSTWAKE: - DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n", - event_name, (int)status, (int)reason)); - break; - case WLC_E_TIMEOUT_EXHAUSTED: - DHD_ERROR(("MACEVENT: %s, type: %d\n", event_name, (int)status)); - break; -#endif /* HAL_API */ -#ifdef BCOL_TCPKA_SYNC - case WLC_E_TKO: - DHD_ERROR(("MACEVENT: %s, status %d, reason %d\n", - event_name, (int)status, (int)reason)); - break; -#endif /* BCOL_TCPKA_SYNC */ -#ifdef IDSUP_STATS - case WLC_E_ROAM_START: - DHD_ERROR(("MACEVENT: %s, status %d, reason %d\n", - event_name, (int)status, (int)reason)); - break; - - case WLC_E_BCNLOST_MSG: - DHD_ERROR(("MACEVENT: %s on %s\n", event_name, eabuf)); - break; - - case WLC_E_BSSTRANS: - DHD_ERROR(("MACEVENT: %s from %s\n", event_name, eabuf)); - if (datalen) { - prhex("BSSTRANS", event_data, datalen); - } - break; - - case WLC_E_ID_AUTH: - switch (status) { - case WLC_SUP_KEYXCHANGE_WAIT_M1: - DHD_ERROR(("MACEVENT: %s, EAPOL P-M1\n", event_name)); - break; - case WLC_SUP_KEYXCHANGE_PREP_M2: - DHD_ERROR(("MACEVENT: %s, EAPOL P-M2\n", event_name)); - break; - case WLC_SUP_KEYXCHANGE_WAIT_M3: - DHD_ERROR(("MACEVENT: %s, EAPOL P-M3\n", event_name)); - break; - case WLC_SUP_KEYXCHANGE_PREP_M4: - DHD_ERROR(("MACEVENT: %s, EAPOL P-M4\n", event_name)); - break; - case WLC_SUP_KEYXCHANGE_WAIT_G1: - DHD_ERROR(("MACEVENT: %s, EAPOL G-M1\n", event_name)); - break; - case WLC_SUP_KEYXCHANGE_PREP_G2: - DHD_ERROR(("MACEVENT: %s, EAPOL G-M2\n", event_name)); - break; - default: - DHD_ERROR(("MACEVENT: %s, UNKNOWN TYPE %d\n", event_name, status)); - break; - } - break; - - case WLC_E_AUTH_REQ: -#endif /* IDSUP_STATS */ - case WLC_E_ASSOC_REQ_IE: - case WLC_E_ASSOC_RESP_IE: - case WLC_E_PMKID_CACHE: - DHD_EVENT(("MACEVENT: %s\n", event_name)); - break; - - case WLC_E_SCAN_COMPLETE: - DHD_EVENT(("MACEVENT: %s\n", event_name)); -#ifdef REPORT_FATAL_TIMEOUTS - dhd_stop_scan_timer(dhd_pub); -#endif /* REPORT_FATAL_TIMEOUTS */ - break; - case WLC_E_RSSI_LQM: - case WLC_E_PFN_NET_FOUND: - case WLC_E_PFN_NET_LOST: - case WLC_E_PFN_SCAN_COMPLETE: - case WLC_E_PFN_SCAN_NONE: - case WLC_E_PFN_SCAN_ALLGONE: - case WLC_E_PFN_GSCAN_FULL_RESULT: - case WLC_E_PFN_SSID_EXT: - DHD_EVENT(("PNOEVENT: %s\n", event_name)); - break; - - case WLC_E_PSK_SUP: - case WLC_E_PRUNE: - DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n", - event_name, (int)status, (int)reason)); -#ifdef REPORT_FATAL_TIMEOUTS - if ((status == WLC_E_STATUS_SUCCESS || status == WLC_E_STATUS_UNSOLICITED) && - (reason == WLC_E_SUP_OTHER)) { - dhd_clear_join_error(dhd_pub, WLC_WPA_MASK); - } else { - dhd_set_join_error(dhd_pub, WLC_WPA_MASK); - } -#endif /* REPORT_FATAL_TIMEOUTS */ - break; - -#if defined(PKT_FILTER_SUPPORT) && defined(PF_HOSTWAKE) - case WLC_E_PKT_FILTER: - DHD_EVENT(("PKT_FILTER_EVENT: %s, status %d, reason %d\n", - event_name, (int)status, (int)reason)); - if (datalen && (status == WLC_E_STATUS_TIMEOUT)) { - uint32 *id = (uint32 *)event_data; - DHD_ERROR(("PKT_FILTER_EVENT: id %d TIMEOUT\n", *id)); - } - break; -#endif /* defined(PKT_FILTER_SUPPORT) && defined(PF_HOSTWAKE) */ - -#ifdef WIFI_ACT_FRAME - case WLC_E_ACTION_FRAME: - DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf)); - break; -#endif /* WIFI_ACT_FRAME */ - -#ifdef SHOW_LOGTRACE - case WLC_E_TRACE: - DHD_EVENT(("MACEVENT: %s Logtrace\n", event_name)); - dhd_dbg_trace_evnt_handler(dhd_pub, event_data, raw_event_ptr, datalen); - break; -#endif /* SHOW_LOGTRACE */ - - case WLC_E_RSSI: - DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data)))); - break; - - case WLC_E_SERVICE_FOUND: - case WLC_E_P2PO_ADD_DEVICE: - case WLC_E_P2PO_DEL_DEVICE: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - break; - -#ifdef BT_WIFI_HANDOBER - case WLC_E_BT_WIFI_HANDOVER_REQ: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - break; -#endif - - case WLC_E_CCA_CHAN_QUAL: - if (datalen) { - buf = (uchar *) event_data; - DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d, " - "channel 0x%02x \n", event_name, event_type, eabuf, (int)status, - (int)reason, (int)auth_type, *(buf + 4))); - } - break; - case WLC_E_ESCAN_RESULT: - { - DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d \n", - event_name, event_type, eabuf, (int)status)); - } - break; - case WLC_E_PSK_AUTH: - DHD_EVENT(("MACEVENT: %s, RA %s status %d Reason:%d\n", - event_name, eabuf, status, reason)); - break; - case WLC_E_IF: - { - struct wl_event_data_if *ifevent = (struct wl_event_data_if *)event_data; - BCM_REFERENCE(ifevent); - - DHD_EVENT(("MACEVENT: %s, opcode:0x%d ifidx:%d\n", - event_name, ifevent->opcode, ifevent->ifidx)); - break; - } - -#ifdef SHOW_LOGTRACE - case WLC_E_MSCH: - { - wl_mschdbg_event_handler(dhd_pub, raw_event_ptr, reason, event_data, datalen); - break; - } -#endif /* SHOW_LOGTRACE */ - -#ifdef EVENT_DATA_HOSTWAKE - case WLC_E_HOSTWAKE: - DHD_ERROR(("MACEVENT: %s, status %d, reason %d\n", - event_name, status, reason)); - break; -#endif /* EVENT_DATA_HOSTWAKE */ - - default: - DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n", - event_name, event_type, eabuf, (int)status, (int)reason, - (int)auth_type)); - break; - } - - /* show any appended data if message level is set to bytes or host_data is set */ - if ((DHD_BYTES_ON() || (host_data == TRUE)) && DHD_EVENT_ON() && datalen) { - buf = (uchar *) event_data; - BCM_REFERENCE(buf); - DHD_EVENT((" data (%d) : ", datalen)); - for (i = 0; i < datalen; i++) { - DHD_EVENT((" 0x%02x ", buf[i])); - } - DHD_EVENT(("\n")); - } -} -#endif /* SHOW_EVENTS */ - -#ifdef DNGL_EVENT_SUPPORT -/* Check whether packet is a BRCM dngl event pkt. If it is, process event data. */ -int -dngl_host_event(dhd_pub_t *dhdp, void *pktdata, bcm_dngl_event_msg_t *dngl_event, size_t pktlen) -{ - bcm_dngl_event_t *pvt_data = (bcm_dngl_event_t *)pktdata; - - dngl_host_event_process(dhdp, pvt_data, dngl_event, pktlen); - return BCME_OK; -} - -void -dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event, - bcm_dngl_event_msg_t *dngl_event, size_t pktlen) -{ - uint8 *p = (uint8 *)(event + 1); - uint16 type = ntoh16_ua((void *)&dngl_event->event_type); - uint16 datalen = ntoh16_ua((void *)&dngl_event->datalen); - uint16 version = ntoh16_ua((void *)&dngl_event->version); - - DHD_EVENT(("VERSION:%d, EVENT TYPE:%d, DATALEN:%d\n", version, type, datalen)); - if (datalen > (pktlen - sizeof(bcm_dngl_event_t) + ETHER_TYPE_LEN)) { - return; - } - if (version != BCM_DNGL_EVENT_MSG_VERSION) { - DHD_ERROR(("%s:version mismatch:%d:%d\n", __FUNCTION__, - version, BCM_DNGL_EVENT_MSG_VERSION)); - return; - } - switch (type) { - case DNGL_E_SOCRAM_IND: - { - bcm_dngl_socramind_t *socramind_ptr = (bcm_dngl_socramind_t *)p; - uint16 tag = ltoh32(socramind_ptr->tag); - uint16 taglen = ltoh32(socramind_ptr->length); - p = (uint8 *)socramind_ptr->value; - DHD_EVENT(("Tag:%d Len:%d Datalen:%d\n", tag, taglen, datalen)); - switch (tag) { - case SOCRAM_IND_ASSERT_TAG: - { - /* - * The payload consists of - - * null terminated function name padded till 32 bit boundary + - * Line number - (32 bits) - * Caller address (32 bits) - */ - char *fnname = (char *)p; - if (datalen < (ROUNDUP(strlen(fnname) + 1, sizeof(uint32)) + - sizeof(uint32) * 2)) { - DHD_ERROR(("Wrong length:%d\n", datalen)); - return; - } - DHD_EVENT(("ASSRT Function:%s ", p)); - p += ROUNDUP(strlen(p) + 1, sizeof(uint32)); - DHD_EVENT(("Line:%d ", *(uint32 *)p)); - p += sizeof(uint32); - DHD_EVENT(("Caller Addr:0x%x\n", *(uint32 *)p)); - break; - } - case SOCRAM_IND_TAG_HEALTH_CHECK: - { - bcm_dngl_healthcheck_t *dngl_hc = (bcm_dngl_healthcheck_t *)p; - DHD_EVENT(("SOCRAM_IND_HEALTHCHECK_TAG:%d Len:%d\n", - ltoh32(dngl_hc->top_module_tag), ltoh32(dngl_hc->top_module_len))); - if (DHD_EVENT_ON()) { - prhex("HEALTHCHECK", p, ltoh32(dngl_hc->top_module_len)); - } - p = (uint8 *)dngl_hc->value; - - switch (ltoh32(dngl_hc->top_module_tag)) { - case HEALTH_CHECK_TOP_LEVEL_MODULE_PCIEDEV_RTE: - { - bcm_dngl_pcie_hc_t *pcie_hc; - pcie_hc = (bcm_dngl_pcie_hc_t *)p; - BCM_REFERENCE(pcie_hc); - if (ltoh32(dngl_hc->top_module_len) < - sizeof(bcm_dngl_pcie_hc_t)) { - DHD_ERROR(("Wrong length:%d\n", - ltoh32(dngl_hc->top_module_len))); - return; - } - DHD_EVENT(("%d:PCIE HC error:%d flag:0x%x," - " control:0x%x\n", - ltoh32(pcie_hc->version), - ltoh32(pcie_hc->pcie_err_ind_type), - ltoh32(pcie_hc->pcie_flag), - ltoh32(pcie_hc->pcie_control_reg))); - break; - } - default: - DHD_ERROR(("%s:Unknown module TAG:%d\n", - __FUNCTION__, - ltoh32(dngl_hc->top_module_tag))); - break; - } - break; - } - default: - DHD_ERROR(("%s:Unknown TAG", __FUNCTION__)); - if (p && DHD_EVENT_ON()) { - prhex("SOCRAMIND", p, taglen); - } - break; - } - break; - } - default: - DHD_ERROR(("%s:Unknown DNGL Event Type:%d", __FUNCTION__, type)); - if (p && DHD_EVENT_ON()) { - prhex("SOCRAMIND", p, datalen); - } - break; - } -#ifdef DHD_FW_COREDUMP - dhdp->memdump_type = DUMP_TYPE_DONGLE_HOST_EVENT; -#endif /* DHD_FW_COREDUMP */ -#ifndef BCMDBUS - if (dhd_socram_dump(dhdp->bus)) { - DHD_ERROR(("%s: socram dump failed\n", __FUNCTION__)); - } else { - /* Notify framework */ - dhd_dbg_send_urgent_evt(dhdp, p, datalen); - } -#endif /* !BCMDBUS */ -} -#endif /* DNGL_EVENT_SUPPORT */ - -/* Stub for now. Will become real function as soon as shim - * is being integrated to Android, Linux etc. - */ -int -wl_event_process_default(wl_event_msg_t *event, struct wl_evt_pport *evt_pport) -{ - return BCME_OK; -} - -int -wl_event_process(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, - uint pktlen, void **data_ptr, void *raw_event) -{ - wl_evt_pport_t evt_pport; - wl_event_msg_t event; - bcm_event_msg_u_t evu; - int ret; - - /* make sure it is a BRCM event pkt and record event data */ - ret = wl_host_event_get_data(pktdata, pktlen, &evu); - if (ret != BCME_OK) { - return ret; - } - - memcpy(&event, &evu.event, sizeof(wl_event_msg_t)); - - /* convert event from network order to host order */ - wl_event_to_host_order(&event); - - /* record event params to evt_pport */ - evt_pport.dhd_pub = dhd_pub; - evt_pport.ifidx = ifidx; - evt_pport.pktdata = pktdata; - evt_pport.data_ptr = data_ptr; - evt_pport.raw_event = raw_event; - evt_pport.data_len = pktlen; - -#if defined(WL_WLC_SHIM) && defined(WL_WLC_SHIM_EVENTS) - { - struct wl_shim_node *shim = dhd_pub_shim(dhd_pub); - if (shim) { - ret = wl_shim_event_process(shim, &event, &evt_pport); - } else { - /* events can come even before shim is initialized - (when waiting for "wlc_ver" response) - * handle them in a non-shim way. - */ - DHD_ERROR(("%s: Events coming before shim initialization!\n", - __FUNCTION__)); - ret = wl_event_process_default(&event, &evt_pport); - } - } -#else - ret = wl_event_process_default(&event, &evt_pport); -#endif /* WL_WLC_SHIM && WL_WLC_SHIM_EVENTS */ - - return ret; -} - -/* Check whether packet is a BRCM event pkt. If it is, record event data. */ -int -wl_host_event_get_data(void *pktdata, uint pktlen, bcm_event_msg_u_t *evu) -{ - int ret; - - ret = is_wlc_event_frame(pktdata, pktlen, 0, evu); - if (ret != BCME_OK) { - DHD_ERROR(("%s: Invalid event frame, err = %d\n", - __FUNCTION__, ret)); - } - - return ret; -} - -int -wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen, - wl_event_msg_t *event, void **data_ptr, void *raw_event) -{ - bcm_event_t *pvt_data = (bcm_event_t *)pktdata; - bcm_event_msg_u_t evu; - uint8 *event_data; - uint32 type, status, datalen; - uint16 flags; - uint evlen; - int ret; - uint16 usr_subtype; - char macstr[ETHER_ADDR_STR_LEN]; - - BCM_REFERENCE(macstr); - - ret = wl_host_event_get_data(pktdata, pktlen, &evu); - if (ret != BCME_OK) { - return ret; - } - - usr_subtype = ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype); - switch (usr_subtype) { - case BCMILCP_BCM_SUBTYPE_EVENT: - memcpy(event, &evu.event, sizeof(wl_event_msg_t)); - *data_ptr = &pvt_data[1]; - break; - case BCMILCP_BCM_SUBTYPE_DNGLEVENT: -#ifdef DNGL_EVENT_SUPPORT - /* If it is a DNGL event process it first */ - if (dngl_host_event(dhd_pub, pktdata, &evu.dngl_event, pktlen) == BCME_OK) { - /* - * Return error purposely to prevent DNGL event being processed - * as BRCM event - */ - return BCME_ERROR; - } -#endif /* DNGL_EVENT_SUPPORT */ - return BCME_NOTFOUND; - default: - return BCME_NOTFOUND; - } - - /* start wl_event_msg process */ - event_data = *data_ptr; - type = ntoh32_ua((void *)&event->event_type); - flags = ntoh16_ua((void *)&event->flags); - status = ntoh32_ua((void *)&event->status); - datalen = ntoh32_ua((void *)&event->datalen); - evlen = datalen + sizeof(bcm_event_t); - - switch (type) { -#ifdef PROP_TXSTATUS - case WLC_E_FIFO_CREDIT_MAP: - dhd_wlfc_enable(dhd_pub); - dhd_wlfc_FIFOcreditmap_event(dhd_pub, event_data); - WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): " - "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1], - event_data[2], - event_data[3], event_data[4], event_data[5])); - break; - - case WLC_E_BCMC_CREDIT_SUPPORT: - dhd_wlfc_BCMCCredit_support_event(dhd_pub); - break; -#ifdef LIMIT_BORROW - case WLC_E_ALLOW_CREDIT_BORROW: - dhd_wlfc_disable_credit_borrow_event(dhd_pub, event_data); - break; -#endif /* LIMIT_BORROW */ -#endif /* PROP_TXSTATUS */ - - - case WLC_E_ULP: -#ifdef DHD_ULP - { - wl_ulp_event_t *ulp_evt = (wl_ulp_event_t *)event_data; - - /* Flush and disable console messages */ - if (ulp_evt->ulp_dongle_action == WL_ULP_DISABLE_CONSOLE) { -#ifdef DHD_ULP_NOT_USED - dhd_bus_ulp_disable_console(dhd_pub); -#endif /* DHD_ULP_NOT_USED */ - } - if (ulp_evt->ulp_dongle_action == WL_ULP_UCODE_DOWNLOAD) { - dhd_bus_ucode_download(dhd_pub->bus); - } - } -#endif /* DHD_ULP */ - break; - case WLC_E_TDLS_PEER_EVENT: -#if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) - { - dhd_tdls_event_handler(dhd_pub, event); - } -#endif - break; - - case WLC_E_IF: - { - struct wl_event_data_if *ifevent = (struct wl_event_data_if *)event_data; - - /* Ignore the event if NOIF is set */ - if (ifevent->reserved & WLC_E_IF_FLAGS_BSSCFG_NOIF) { - DHD_ERROR(("WLC_E_IF: NO_IF set, event Ignored\r\n")); - return (BCME_UNSUPPORTED); - } -#ifdef PCIE_FULL_DONGLE - dhd_update_interface_flow_info(dhd_pub, ifevent->ifidx, - ifevent->opcode, ifevent->role); -#endif -#ifdef PROP_TXSTATUS - { - uint8* ea = pvt_data->eth.ether_dhost; - WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, " - "[%02x:%02x:%02x:%02x:%02x:%02x]\n", - ifevent->ifidx, - ((ifevent->opcode == WLC_E_IF_ADD) ? "ADD":"DEL"), - ((ifevent->role == 0) ? "STA":"AP "), - ea[0], ea[1], ea[2], ea[3], ea[4], ea[5])); - (void)ea; - - if (ifevent->opcode == WLC_E_IF_CHANGE) - dhd_wlfc_interface_event(dhd_pub, - eWLFC_MAC_ENTRY_ACTION_UPDATE, - ifevent->ifidx, ifevent->role, ea); - else - dhd_wlfc_interface_event(dhd_pub, - ((ifevent->opcode == WLC_E_IF_ADD) ? - eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL), - ifevent->ifidx, ifevent->role, ea); - - /* dhd already has created an interface by default, for 0 */ - if (ifevent->ifidx == 0) - break; - } -#endif /* PROP_TXSTATUS */ - - if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) { - if (ifevent->opcode == WLC_E_IF_ADD) { - if (dhd_event_ifadd(dhd_pub->info, ifevent, event->ifname, - event->addr.octet)) { - - DHD_ERROR(("%s: dhd_event_ifadd failed ifidx: %d %s\n", - __FUNCTION__, ifevent->ifidx, event->ifname)); - return (BCME_ERROR); - } - } else if (ifevent->opcode == WLC_E_IF_DEL) { -#ifdef PCIE_FULL_DONGLE - /* Delete flowrings unconditionally for i/f delete */ - dhd_flow_rings_delete(dhd_pub, (uint8)dhd_ifname2idx(dhd_pub->info, - event->ifname)); -#endif /* PCIE_FULL_DONGLE */ - dhd_event_ifdel(dhd_pub->info, ifevent, event->ifname, - event->addr.octet); - /* Return ifidx (for vitual i/f, it will be > 0) - * so that no other operations on deleted interface - * are carried out - */ - ret = ifevent->ifidx; - goto exit; - } else if (ifevent->opcode == WLC_E_IF_CHANGE) { -#ifdef WL_CFG80211 - dhd_event_ifchange(dhd_pub->info, ifevent, event->ifname, - event->addr.octet); -#endif /* WL_CFG80211 */ - } - } else { -#if !defined(PROP_TXSTATUS) && !defined(PCIE_FULL_DONGLE) && defined(WL_CFG80211) - DHD_INFO(("%s: Invalid ifidx %d for %s\n", - __FUNCTION__, ifevent->ifidx, event->ifname)); -#endif /* !PROP_TXSTATUS && !PCIE_FULL_DONGLE && WL_CFG80211 */ - } - /* send up the if event: btamp user needs it */ - *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); - /* push up to external supp/auth */ - dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); - break; - } - -#ifdef WLMEDIA_HTSF - case WLC_E_HTSFSYNC: - htsf_update(dhd_pub->info, event_data); - break; -#endif /* WLMEDIA_HTSF */ - case WLC_E_NDIS_LINK: - break; - case WLC_E_PFN_NET_FOUND: - case WLC_E_PFN_SCAN_ALLGONE: /* share with WLC_E_PFN_BSSID_NET_LOST */ - case WLC_E_PFN_NET_LOST: - break; -#if defined(PNO_SUPPORT) - case WLC_E_PFN_BSSID_NET_FOUND: - case WLC_E_PFN_BEST_BATCHING: - dhd_pno_event_handler(dhd_pub, event, (void *)event_data); - break; -#endif -#if defined(RTT_SUPPORT) - case WLC_E_PROXD: - dhd_rtt_event_handler(dhd_pub, event, (void *)event_data); - break; -#endif /* RTT_SUPPORT */ - /* These are what external supplicant/authenticator wants */ - case WLC_E_ASSOC_IND: - case WLC_E_AUTH_IND: - case WLC_E_REASSOC_IND: - dhd_findadd_sta(dhd_pub, - dhd_ifname2idx(dhd_pub->info, event->ifname), - &event->addr.octet); - break; -#ifndef BCMDBUS -#if defined(DHD_FW_COREDUMP) - case WLC_E_PSM_WATCHDOG: - DHD_ERROR(("%s: WLC_E_PSM_WATCHDOG event received : \n", __FUNCTION__)); - if (dhd_socram_dump(dhd_pub->bus) != BCME_OK) { - DHD_ERROR(("%s: socram dump ERROR : \n", __FUNCTION__)); - } - break; -#endif -#endif /* !BCMDBUS */ -#ifdef DHD_WMF - case WLC_E_PSTA_PRIMARY_INTF_IND: - dhd_update_psta_interface_for_sta(dhd_pub, event->ifname, - (void *)(event->addr.octet), (void*) event_data); - break; -#endif - case WLC_E_LINK: -#ifdef PCIE_FULL_DONGLE - DHD_EVENT(("%s: Link event %d, flags %x, status %x\n", - __FUNCTION__, type, flags, status)); - if (dhd_update_interface_link_status(dhd_pub, (uint8)dhd_ifname2idx(dhd_pub->info, - event->ifname), (uint8)flags) != BCME_OK) { - DHD_ERROR(("%s: dhd_update_interface_link_status Failed.\n", - __FUNCTION__)); - break; - } - if (!flags) { - DHD_ERROR(("%s: Deleting all STA from assoc list and flowrings.\n", - __FUNCTION__)); - /* Delete all sta and flowrings */ - dhd_del_all_sta(dhd_pub, dhd_ifname2idx(dhd_pub->info, event->ifname)); - dhd_flow_rings_delete(dhd_pub, (uint8)dhd_ifname2idx(dhd_pub->info, - event->ifname)); - } - /* fall through */ -#endif /* PCIE_FULL_DONGLE */ - case WLC_E_DEAUTH: - case WLC_E_DEAUTH_IND: - case WLC_E_DISASSOC: - case WLC_E_DISASSOC_IND: -#ifdef PCIE_FULL_DONGLE - if (type != WLC_E_LINK) { - uint8 ifindex = (uint8)dhd_ifname2idx(dhd_pub->info, event->ifname); - uint8 role = dhd_flow_rings_ifindex2role(dhd_pub, ifindex); - uint8 del_sta = TRUE; -#ifdef WL_CFG80211 - if (role == WLC_E_IF_ROLE_STA && - !wl_cfg80211_is_roam_offload(dhd_idx2net(dhd_pub, ifindex)) && - !wl_cfg80211_is_event_from_connected_bssid( - dhd_idx2net(dhd_pub, ifindex), event, *ifidx)) { - del_sta = FALSE; - } -#endif /* WL_CFG80211 */ - DHD_EVENT(("%s: Link event %d, flags %x, status %x, role %d, del_sta %d\n", - __FUNCTION__, type, flags, status, role, del_sta)); - - if (del_sta) { - DHD_MAC_TO_STR((event->addr.octet), macstr); - DHD_EVENT(("%s: Deleting STA %s\n", __FUNCTION__, macstr)); - - dhd_del_sta(dhd_pub, dhd_ifname2idx(dhd_pub->info, - event->ifname), &event->addr.octet); - /* Delete all flowrings for STA and P2P Client */ - if (role == WLC_E_IF_ROLE_STA || role == WLC_E_IF_ROLE_P2P_CLIENT) { - dhd_flow_rings_delete(dhd_pub, ifindex); - } else { - dhd_flow_rings_delete_for_peer(dhd_pub, ifindex, - (char *)&event->addr.octet[0]); - } - } - } -#endif /* PCIE_FULL_DONGLE */ - /* fall through */ - - default: - *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); -#ifdef DHD_UPDATE_INTF_MAC - if ((WLC_E_LINK==type)&&(WLC_EVENT_MSG_LINK&flags)) { - dhd_event_ifchange(dhd_pub->info, - (struct wl_event_data_if *)event, - event->ifname, - event->addr.octet); - } -#endif /* DHD_UPDATE_INTF_MAC */ - /* push up to external supp/auth */ - dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); - DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n", - __FUNCTION__, type, flags, status)); - BCM_REFERENCE(flags); - BCM_REFERENCE(status); - - break; - } -#if defined(STBAP) - /* For routers, EAPD will be working on these events. - * Overwrite interface name to that event is pushed - * to host with its registered interface name - */ - memcpy(pvt_data->event.ifname, dhd_ifname(dhd_pub, *ifidx), IFNAMSIZ); -#endif - -exit: - -#ifdef SHOW_EVENTS - if (DHD_FWLOG_ON() || DHD_EVENT_ON()) { - wl_show_host_event(dhd_pub, event, - (void *)event_data, raw_event, dhd_pub->enable_log); - } -#endif /* SHOW_EVENTS */ - - return ret; -} - -int -wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen, - wl_event_msg_t *event, void **data_ptr, void *raw_event) -{ - return wl_process_host_event(dhd_pub, ifidx, pktdata, pktlen, event, data_ptr, - raw_event); -} - -void -dhd_print_buf(void *pbuf, int len, int bytes_per_line) -{ -#ifdef DHD_DEBUG - int i, j = 0; - unsigned char *buf = pbuf; - - if (bytes_per_line == 0) { - bytes_per_line = len; - } - - for (i = 0; i < len; i++) { - DHD_PRINT(("%2.2x", *buf++)); - j++; - if (j == bytes_per_line) { - DHD_PRINT(("\n")); - j = 0; - } else { - DHD_PRINT((":")); - } - } - DHD_PRINT(("\n")); -#endif /* DHD_DEBUG */ -} -#ifndef strtoul -#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) -#endif - -#if defined(PKT_FILTER_SUPPORT) || defined(DHD_PKT_LOGGING) -/* Convert user's input in hex pattern to byte-size mask */ -int -wl_pattern_atoh(char *src, char *dst) -{ - int i; - if (strncmp(src, "0x", 2) != 0 && - strncmp(src, "0X", 2) != 0) { - DHD_ERROR(("Mask invalid format. Needs to start with 0x\n")); - return -1; - } - src = src + 2; /* Skip past 0x */ - if (strlen(src) % 2 != 0) { - DHD_ERROR(("Mask invalid format. Needs to be of even length\n")); - return -1; - } - for (i = 0; *src != '\0'; i++) { - char num[3]; - bcm_strncpy_s(num, sizeof(num), src, 2); - num[2] = '\0'; - dst[i] = (uint8)strtoul(num, NULL, 16); - src += 2; - } - return i; -} -#endif /* PKT_FILTER_SUPPORT || DHD_PKT_LOGGING */ - -#ifdef PKT_FILTER_SUPPORT -void -dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode) -{ - char *argv[8]; - int i = 0; - const char *str; - int buf_len; - int str_len; - char *arg_save = 0, *arg_org = 0; - int rc; - char buf[32] = {0}; - wl_pkt_filter_enable_t enable_parm; - wl_pkt_filter_enable_t * pkt_filterp; - - if (!arg) - return; - - if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { - DHD_ERROR(("%s: malloc failed\n", __FUNCTION__)); - goto fail; - } - arg_org = arg_save; - memcpy(arg_save, arg, strlen(arg) + 1); - - argv[i] = bcmstrtok(&arg_save, " ", 0); - - i = 0; - if (argv[i] == NULL) { - DHD_ERROR(("No args provided\n")); - goto fail; - } - - str = "pkt_filter_enable"; - str_len = strlen(str); - bcm_strncpy_s(buf, sizeof(buf) - 1, str, sizeof(buf) - 1); - buf[ sizeof(buf) - 1 ] = '\0'; - buf_len = str_len + 1; - - pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1); - - /* Parse packet filter id. */ - enable_parm.id = htod32(strtoul(argv[i], NULL, 0)); - if (dhd_conf_del_pkt_filter(dhd, enable_parm.id)) - goto fail; - - /* Parse enable/disable value. */ - enable_parm.enable = htod32(enable); - - buf_len += sizeof(enable_parm); - memcpy((char *)pkt_filterp, - &enable_parm, - sizeof(enable_parm)); - - /* Enable/disable the specified filter. */ - rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); - rc = rc >= 0 ? 0 : rc; - if (rc) - DHD_ERROR(("%s: failed to %s pktfilter %s, retcode = %d\n", - __FUNCTION__, enable?"enable":"disable", arg, rc)); - else - DHD_TRACE(("%s: successfully %s pktfilter %s\n", - __FUNCTION__, enable?"enable":"disable", arg)); - - /* Contorl the master mode */ - rc = dhd_wl_ioctl_set_intiovar(dhd, "pkt_filter_mode", - master_mode, WLC_SET_VAR, TRUE, 0); - rc = rc >= 0 ? 0 : rc; - if (rc) - DHD_TRACE(("%s: failed to set pkt_filter_mode %d, retcode = %d\n", - __FUNCTION__, master_mode, rc)); - -fail: - if (arg_org) - MFREE(dhd->osh, arg_org, strlen(arg) + 1); -} - -/* Packet filter section: extended filters have named offsets, add table here */ -typedef struct { - char *name; - uint16 base; -} wl_pfbase_t; - -static wl_pfbase_t basenames[] = { WL_PKT_FILTER_BASE_NAMES }; - -static int -wl_pkt_filter_base_parse(char *name) -{ - uint i; - char *bname, *uname; - - for (i = 0; i < ARRAYSIZE(basenames); i++) { - bname = basenames[i].name; - for (uname = name; *uname; bname++, uname++) { - if (*bname != bcm_toupper(*uname)) { - break; - } - } - if (!*uname && !*bname) { - break; - } - } - - if (i < ARRAYSIZE(basenames)) { - return basenames[i].base; - } else { - return -1; - } -} - -void -dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) -{ - const char *str; - wl_pkt_filter_t pkt_filter; - wl_pkt_filter_t *pkt_filterp; - int buf_len; - int str_len; - int rc; - uint32 mask_size; - uint32 pattern_size; - char *argv[16], * buf = 0; - int i = 0; - char *arg_save = 0, *arg_org = 0; -#define BUF_SIZE 2048 - - if (!arg) - return; - - if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { - DHD_ERROR(("%s: malloc failed\n", __FUNCTION__)); - goto fail; - } - - arg_org = arg_save; - - if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) { - DHD_ERROR(("%s: malloc failed\n", __FUNCTION__)); - goto fail; - } - memset(buf, 0, BUF_SIZE); - memcpy(arg_save, arg, strlen(arg) + 1); - - if (strlen(arg) > BUF_SIZE) { - DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf))); - goto fail; - } - - argv[i] = bcmstrtok(&arg_save, " ", 0); - while (argv[i++]) - argv[i] = bcmstrtok(&arg_save, " ", 0); - - i = 0; - if (argv[i] == NULL) { - DHD_ERROR(("No args provided\n")); - goto fail; - } - - str = "pkt_filter_add"; - str_len = strlen(str); - bcm_strncpy_s(buf, BUF_SIZE, str, str_len); - buf[ str_len ] = '\0'; - buf_len = str_len + 1; - - pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); - - /* Parse packet filter id. */ - pkt_filter.id = htod32(strtoul(argv[i], NULL, 0)); - if (dhd_conf_del_pkt_filter(dhd, pkt_filter.id)) - goto fail; - - if (argv[++i] == NULL) { - DHD_ERROR(("Polarity not provided\n")); - goto fail; - } - - /* Parse filter polarity. */ - pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Filter type not provided\n")); - goto fail; - } - - /* Parse filter type. */ - pkt_filter.type = htod32(strtoul(argv[i], NULL, 0)); - - if ((pkt_filter.type == 0) || (pkt_filter.type == 1)) { - if (argv[++i] == NULL) { - DHD_ERROR(("Offset not provided\n")); - goto fail; - } - - /* Parse pattern filter offset. */ - pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Bitmask not provided\n")); - goto fail; - } - - /* Parse pattern filter mask. */ - mask_size = - htod32(wl_pattern_atoh(argv[i], - (char *) pkt_filterp->u.pattern.mask_and_pattern)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Pattern not provided\n")); - goto fail; - } - - /* Parse pattern filter pattern. */ - pattern_size = - htod32(wl_pattern_atoh(argv[i], - (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); - - if (mask_size != pattern_size) { - DHD_ERROR(("Mask and pattern not the same size\n")); - goto fail; - } - - pkt_filter.u.pattern.size_bytes = mask_size; - buf_len += WL_PKT_FILTER_FIXED_LEN; - buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); - - /* Keep-alive attributes are set in local variable (keep_alive_pkt), and - * then memcpy'ed into buffer (keep_alive_pktp) since there is no - * guarantee that the buffer is properly aligned. - */ - memcpy((char *)pkt_filterp, - &pkt_filter, - WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); - } else if ((pkt_filter.type == 2) || (pkt_filter.type == 6)) { - int list_cnt = 0; - char *endptr = NULL; - wl_pkt_filter_pattern_listel_t *pf_el = &pkt_filterp->u.patlist.patterns[0]; - - while (argv[++i] != NULL) { - /* Parse pattern filter base and offset. */ - if (bcm_isdigit(*argv[i])) { - /* Numeric base */ - rc = strtoul(argv[i], &endptr, 0); - } else { - endptr = strchr(argv[i], ':'); - if (endptr) { - *endptr = '\0'; - rc = wl_pkt_filter_base_parse(argv[i]); - if (rc == -1) { - DHD_ERROR(("Invalid base %s\n", argv[i])); - goto fail; - } - *endptr = ':'; - } else { - DHD_ERROR(("Invalid [base:]offset format: %s\n", argv[i])); - goto fail; - } - } - - if (*endptr == ':') { - pkt_filter.u.patlist.patterns[0].base_offs = htod16(rc); - rc = strtoul(endptr + 1, &endptr, 0); - } else { - /* Must have had a numeric offset only */ - pkt_filter.u.patlist.patterns[0].base_offs = htod16(0); - } - - if (*endptr) { - DHD_ERROR(("Invalid [base:]offset format: %s\n", argv[i])); - goto fail; - } - if (rc > 0x0000FFFF) { - DHD_ERROR(("Offset too large\n")); - goto fail; - } - pkt_filter.u.patlist.patterns[0].rel_offs = htod16(rc); - - /* Clear match_flag (may be set in parsing which follows) */ - pkt_filter.u.patlist.patterns[0].match_flags = htod16(0); - - /* Parse pattern filter mask and pattern directly into ioctl buffer */ - if (argv[++i] == NULL) { - DHD_ERROR(("Bitmask not provided\n")); - goto fail; - } - rc = wl_pattern_atoh(argv[i], (char*)pf_el->mask_and_data); - if (rc == -1) { - DHD_ERROR(("Rejecting: %s\n", argv[i])); - goto fail; - } - mask_size = htod16(rc); - - if (argv[++i] == NULL) { - DHD_ERROR(("Pattern not provided\n")); - goto fail; - } - - if (*argv[i] == '!') { - pkt_filter.u.patlist.patterns[0].match_flags = - htod16(WL_PKT_FILTER_MFLAG_NEG); - (argv[i])++; - } - if (*argv[i] == '\0') { - DHD_ERROR(("Pattern not provided\n")); - goto fail; - } - rc = wl_pattern_atoh(argv[i], (char*)&pf_el->mask_and_data[rc]); - if (rc == -1) { - DHD_ERROR(("Rejecting: %s\n", argv[i])); - goto fail; - } - pattern_size = htod16(rc); - - if (mask_size != pattern_size) { - DHD_ERROR(("Mask and pattern not the same size\n")); - goto fail; - } - - pkt_filter.u.patlist.patterns[0].size_bytes = mask_size; - - /* Account for the size of this pattern element */ - buf_len += WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN + 2 * rc; - - /* And the pattern element fields that were put in a local for - * alignment purposes now get copied to the ioctl buffer. - */ - memcpy((char*)pf_el, &pkt_filter.u.patlist.patterns[0], - WL_PKT_FILTER_PATTERN_FIXED_LEN); - - /* Move to next element location in ioctl buffer */ - pf_el = (wl_pkt_filter_pattern_listel_t*) - ((uint8*)pf_el + WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN + 2 * rc); - - /* Count list element */ - list_cnt++; - } - - /* Account for initial fixed size, and copy initial fixed fields */ - buf_len += WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN; - - /* Update list count and total size */ - pkt_filter.u.patlist.list_cnt = list_cnt; - pkt_filter.u.patlist.PAD1[0] = 0; - pkt_filter.u.patlist.totsize = buf + buf_len - (char*)pkt_filterp; - pkt_filter.u.patlist.totsize -= WL_PKT_FILTER_FIXED_LEN; - - memcpy((char *)pkt_filterp, &pkt_filter, - WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN); - } else { - DHD_ERROR(("Invalid filter type %d\n", pkt_filter.type)); - goto fail; - } - - rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); - rc = rc >= 0 ? 0 : rc; - - if (rc) - DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", - __FUNCTION__, arg, rc)); - else - DHD_TRACE(("%s: successfully added pktfilter %s\n", - __FUNCTION__, arg)); - -fail: - if (arg_org) - MFREE(dhd->osh, arg_org, strlen(arg) + 1); - - if (buf) - MFREE(dhd->osh, buf, BUF_SIZE); -} - -void -dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id) -{ - int ret; - - ret = dhd_wl_ioctl_set_intiovar(dhd, "pkt_filter_delete", - id, WLC_SET_VAR, TRUE, 0); - if (ret < 0) { - DHD_ERROR(("%s: Failed to delete filter ID:%d, ret=%d\n", - __FUNCTION__, id, ret)); - } - else - DHD_TRACE(("%s: successfully deleted pktfilter %d\n", - __FUNCTION__, id)); -} -#endif /* PKT_FILTER_SUPPORT */ - -/* ========================== */ -/* ==== ARP OFFLOAD SUPPORT = */ -/* ========================== */ -#ifdef ARP_OFFLOAD_SUPPORT -void -dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode) -{ - int retcode; - - retcode = dhd_wl_ioctl_set_intiovar(dhd, "arp_ol", - arp_mode, WLC_SET_VAR, TRUE, 0); - - retcode = retcode >= 0 ? 0 : retcode; - if (retcode) - DHD_ERROR(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n", - __FUNCTION__, arp_mode, retcode)); - else - DHD_ARPOE(("%s: successfully set ARP offload mode to 0x%x\n", - __FUNCTION__, arp_mode)); -} - -void -dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) -{ - int retcode; - - retcode = dhd_wl_ioctl_set_intiovar(dhd, "arpoe", - arp_enable, WLC_SET_VAR, TRUE, 0); - - retcode = retcode >= 0 ? 0 : retcode; - if (retcode) - DHD_ERROR(("%s: failed to enabe ARP offload to %d, retcode = %d\n", - __FUNCTION__, arp_enable, retcode)); - else - DHD_ARPOE(("%s: successfully enabed ARP offload to %d\n", - __FUNCTION__, arp_enable)); - if (arp_enable) { - uint32 version; - retcode = dhd_wl_ioctl_get_intiovar(dhd, "arp_version", - &version, WLC_GET_VAR, FALSE, 0); - if (retcode) { - DHD_INFO(("%s: fail to get version (maybe version 1:retcode = %d\n", - __FUNCTION__, retcode)); - dhd->arp_version = 1; - } - else { - DHD_INFO(("%s: ARP Version= %x\n", __FUNCTION__, version)); - dhd->arp_version = version; - } - } -} - -void -dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx) -{ - int ret = 0; - - if (dhd == NULL) return; - if (dhd->arp_version == 1) - idx = 0; - - ret = dhd_iovar(dhd, idx, "arp_table_clear", NULL, 0, NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); -} - -void -dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx) -{ - int ret = 0; - - if (dhd == NULL) return; - if (dhd->arp_version == 1) - idx = 0; - - ret = dhd_iovar(dhd, idx, "arp_hostip_clear", NULL, 0, NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); -} - -void -dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx) -{ - int ret; - - if (dhd == NULL) return; - if (dhd->arp_version == 1) - idx = 0; - - ret = dhd_iovar(dhd, idx, "arp_hostip", (char *)&ipaddr, sizeof(ipaddr), - NULL, 0, TRUE); - if (ret) - DHD_ERROR(("%s: ARP ip addr add failed, ret = %d\n", __FUNCTION__, ret)); - else - DHD_ARPOE(("%s: sARP H ipaddr entry added \n", - __FUNCTION__)); -} - -int -dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx) -{ - int ret, i; - uint32 *ptr32 = buf; - bool clr_bottom = FALSE; - - if (!buf) - return -1; - if (dhd == NULL) return -1; - if (dhd->arp_version == 1) - idx = 0; - - ret = dhd_iovar(dhd, idx, "arp_hostip", NULL, 0, (char *)buf, buflen, - FALSE); - if (ret) { - DHD_ERROR(("%s: ioctl WLC_GET_VAR error %d\n", - __FUNCTION__, ret)); - - return -1; - } - - /* clean up the buf, ascii reminder */ - for (i = 0; i < MAX_IPV4_ENTRIES; i++) { - if (!clr_bottom) { - if (*ptr32 == 0) - clr_bottom = TRUE; - } else { - *ptr32 = 0; - } - ptr32++; - } - - return 0; -} -#endif /* ARP_OFFLOAD_SUPPORT */ - -/* - * Neighbor Discovery Offload: enable NDO feature - * Called by ipv6 event handler when interface comes up/goes down - */ -int -dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable) -{ - int retcode; - - if (dhd == NULL) - return -1; - - retcode = dhd_wl_ioctl_set_intiovar(dhd, "ndoe", - ndo_enable, WLC_SET_VAR, TRUE, 0); - if (retcode) - DHD_ERROR(("%s: failed to enabe ndo to %d, retcode = %d\n", - __FUNCTION__, ndo_enable, retcode)); - else - DHD_TRACE(("%s: successfully enabed ndo offload to %d\n", - __FUNCTION__, ndo_enable)); - - return retcode; -} - -/* - * Neighbor Discover Offload: enable NDO feature - * Called by ipv6 event handler when interface comes up - */ -int -dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipv6addr, int idx) -{ - int iov_len = 0; - char iovbuf[DHD_IOVAR_BUF_SIZE] = {0}; - int retcode; - - if (dhd == NULL) - return -1; - - iov_len = bcm_mkiovar("nd_hostip", (char *)ipv6addr, - IPV6_ADDR_LEN, iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return -1; - } - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); - - if (retcode) - DHD_ERROR(("%s: ndo ip addr add failed, retcode = %d\n", - __FUNCTION__, retcode)); - else - DHD_TRACE(("%s: ndo ipaddr entry added \n", - __FUNCTION__)); - - return retcode; -} - -/* - * Neighbor Discover Offload: enable NDO feature - * Called by ipv6 event handler when interface goes down - */ -int -dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx) -{ - int iov_len = 0; - char iovbuf[DHD_IOVAR_BUF_SIZE] = {0}; - int retcode; - - if (dhd == NULL) - return -1; - - iov_len = bcm_mkiovar("nd_hostip_clear", NULL, - 0, iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return -1; - } - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); - - if (retcode) - DHD_ERROR(("%s: ndo ip addr remove failed, retcode = %d\n", - __FUNCTION__, retcode)); - else - DHD_TRACE(("%s: ndo ipaddr entry removed \n", - __FUNCTION__)); - - return retcode; -} - -/* Enhanced ND offload */ -uint16 -dhd_ndo_get_version(dhd_pub_t *dhdp) -{ - char iovbuf[DHD_IOVAR_BUF_SIZE]; - wl_nd_hostip_t ndo_get_ver; - int iov_len; - int retcode; - uint16 ver = 0; - - if (dhdp == NULL) { - return BCME_ERROR; - } - - memset(&iovbuf, 0, sizeof(iovbuf)); - ndo_get_ver.version = htod16(WL_ND_HOSTIP_IOV_VER); - ndo_get_ver.op_type = htod16(WL_ND_HOSTIP_OP_VER); - ndo_get_ver.length = htod32(WL_ND_HOSTIP_FIXED_LEN + sizeof(uint16)); - ndo_get_ver.u.version = 0; - iov_len = bcm_mkiovar("nd_hostip", (char *)&ndo_get_ver, - WL_ND_HOSTIP_FIXED_LEN + sizeof(uint16), iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return BCME_ERROR; - } - - retcode = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, iov_len, FALSE, 0); - if (retcode) { - DHD_ERROR(("%s: failed, retcode = %d\n", __FUNCTION__, retcode)); - /* ver iovar not supported. NDO version is 0 */ - ver = 0; - } else { - wl_nd_hostip_t *ndo_ver_ret = (wl_nd_hostip_t *)iovbuf; - - if ((dtoh16(ndo_ver_ret->version) == WL_ND_HOSTIP_IOV_VER) && - (dtoh16(ndo_ver_ret->op_type) == WL_ND_HOSTIP_OP_VER) && - (dtoh32(ndo_ver_ret->length) == WL_ND_HOSTIP_FIXED_LEN - + sizeof(uint16))) { - /* nd_hostip iovar version */ - ver = dtoh16(ndo_ver_ret->u.version); - } - - DHD_TRACE(("%s: successfully get version: %d\n", __FUNCTION__, ver)); - } - - return ver; -} - -int -dhd_ndo_add_ip_with_type(dhd_pub_t *dhdp, char *ipv6addr, uint8 type, int idx) -{ - char iovbuf[DHD_IOVAR_BUF_SIZE]; - wl_nd_hostip_t ndo_add_addr; - int iov_len; - int retcode; - - if (dhdp == NULL || ipv6addr == 0) { - return BCME_ERROR; - } - - /* wl_nd_hostip_t fixed param */ - ndo_add_addr.version = htod16(WL_ND_HOSTIP_IOV_VER); - ndo_add_addr.op_type = htod16(WL_ND_HOSTIP_OP_ADD); - ndo_add_addr.length = htod32(WL_ND_HOSTIP_WITH_ADDR_LEN); - /* wl_nd_host_ip_addr_t param for add */ - memcpy(&ndo_add_addr.u.host_ip.ip_addr, ipv6addr, IPV6_ADDR_LEN); - ndo_add_addr.u.host_ip.type = type; - - iov_len = bcm_mkiovar("nd_hostip", (char *)&ndo_add_addr, - WL_ND_HOSTIP_WITH_ADDR_LEN, iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return BCME_ERROR; - } - - retcode = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); - if (retcode) { - DHD_ERROR(("%s: failed, retcode = %d\n", __FUNCTION__, retcode)); -#ifdef NDO_CONFIG_SUPPORT - if (retcode == BCME_NORESOURCE) { - /* number of host ip addr exceeds FW capacity, Deactivate ND offload */ - DHD_INFO(("%s: Host IP count exceed device capacity," - "ND offload deactivated\n", __FUNCTION__)); - dhdp->ndo_host_ip_overflow = TRUE; - dhd_ndo_enable(dhdp, 0); - } -#endif /* NDO_CONFIG_SUPPORT */ - } else { - DHD_TRACE(("%s: successfully added: %d\n", __FUNCTION__, retcode)); - } - - return retcode; -} - -int -dhd_ndo_remove_ip_by_addr(dhd_pub_t *dhdp, char *ipv6addr, int idx) -{ - char iovbuf[DHD_IOVAR_BUF_SIZE]; - wl_nd_hostip_t ndo_del_addr; - int iov_len; - int retcode; - - if (dhdp == NULL || ipv6addr == 0) { - return BCME_ERROR; - } - - /* wl_nd_hostip_t fixed param */ - ndo_del_addr.version = htod16(WL_ND_HOSTIP_IOV_VER); - ndo_del_addr.op_type = htod16(WL_ND_HOSTIP_OP_DEL); - ndo_del_addr.length = htod32(WL_ND_HOSTIP_WITH_ADDR_LEN); - /* wl_nd_host_ip_addr_t param for del */ - memcpy(&ndo_del_addr.u.host_ip.ip_addr, ipv6addr, IPV6_ADDR_LEN); - ndo_del_addr.u.host_ip.type = 0; /* don't care */ - - iov_len = bcm_mkiovar("nd_hostip", (char *)&ndo_del_addr, - WL_ND_HOSTIP_WITH_ADDR_LEN, iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return BCME_ERROR; - } - - retcode = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); - if (retcode) { - DHD_ERROR(("%s: failed, retcode = %d\n", __FUNCTION__, retcode)); - } else { - DHD_TRACE(("%s: successfully removed: %d\n", __FUNCTION__, retcode)); - } - - return retcode; -} - -int -dhd_ndo_remove_ip_by_type(dhd_pub_t *dhdp, uint8 type, int idx) -{ - char iovbuf[DHD_IOVAR_BUF_SIZE]; - wl_nd_hostip_t ndo_del_addr; - int iov_len; - int retcode; - - if (dhdp == NULL) { - return BCME_ERROR; - } - - /* wl_nd_hostip_t fixed param */ - ndo_del_addr.version = htod16(WL_ND_HOSTIP_IOV_VER); - if (type == WL_ND_IPV6_ADDR_TYPE_UNICAST) { - ndo_del_addr.op_type = htod16(WL_ND_HOSTIP_OP_DEL_UC); - } else if (type == WL_ND_IPV6_ADDR_TYPE_ANYCAST) { - ndo_del_addr.op_type = htod16(WL_ND_HOSTIP_OP_DEL_AC); - } else { - return BCME_BADARG; - } - ndo_del_addr.length = htod32(WL_ND_HOSTIP_FIXED_LEN); - - iov_len = bcm_mkiovar("nd_hostip", (char *)&ndo_del_addr, WL_ND_HOSTIP_FIXED_LEN, - iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return BCME_ERROR; - } - - retcode = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx); - if (retcode) { - DHD_ERROR(("%s: failed, retcode = %d\n", __FUNCTION__, retcode)); - } else { - DHD_TRACE(("%s: successfully removed: %d\n", __FUNCTION__, retcode)); - } - - return retcode; -} - -int -dhd_ndo_unsolicited_na_filter_enable(dhd_pub_t *dhdp, int enable) -{ - char iovbuf[DHD_IOVAR_BUF_SIZE]; - int iov_len; - int retcode; - - if (dhdp == NULL) { - return BCME_ERROR; - } - - iov_len = bcm_mkiovar("nd_unsolicited_na_filter", (char *)&enable, sizeof(int), - iovbuf, sizeof(iovbuf)); - if (!iov_len) { - DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", - __FUNCTION__, sizeof(iovbuf))); - return BCME_ERROR; - } - retcode = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0); - if (retcode) - DHD_ERROR(("%s: failed to enable Unsolicited NA filter to %d, retcode = %d\n", - __FUNCTION__, enable, retcode)); - else { - DHD_TRACE(("%s: successfully enabled Unsolicited NA filter to %d\n", - __FUNCTION__, enable)); - } - - return retcode; -} - - -/* - * returns = TRUE if associated, FALSE if not associated - */ -bool dhd_is_associated(dhd_pub_t *dhd, uint8 ifidx, int *retval) -{ - char bssid[6], zbuf[6]; - int ret = -1; - - bzero(bssid, 6); - bzero(zbuf, 6); - - ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, - ETHER_ADDR_LEN, FALSE, ifidx); - DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret)); - - if (ret == BCME_NOTASSOCIATED) { - DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret)); - } - - if (retval) - *retval = ret; - - if (ret < 0) - return FALSE; - - if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) == 0)) { - DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__)); - return FALSE; - } - return TRUE; -} - -/* Function to estimate possible DTIM_SKIP value */ -#if defined(BCMPCIE) -int -dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd, int *dtim_period, int *bcn_interval) -{ - int bcn_li_dtim = 1; /* deafult no dtim skip setting */ - int ret = -1; - int allowed_skip_dtim_cnt = 0; - - /* Check if associated */ - if (dhd_is_associated(dhd, 0, NULL) == FALSE) { - DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret)); - return bcn_li_dtim; - } - - if (dtim_period == NULL || bcn_interval == NULL) - return bcn_li_dtim; - - /* read associated AP beacon interval */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD, - bcn_interval, sizeof(*bcn_interval), FALSE, 0)) < 0) { - DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret)); - return bcn_li_dtim; - } - - /* read associated AP dtim setup */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, - dtim_period, sizeof(*dtim_period), FALSE, 0)) < 0) { - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); - return bcn_li_dtim; - } - - /* if not assocated just return */ - if (*dtim_period == 0) { - return bcn_li_dtim; - } - - if (dhd->max_dtim_enable) { - bcn_li_dtim = - (int) (MAX_DTIM_ALLOWED_INTERVAL / ((*dtim_period) * (*bcn_interval))); - if (bcn_li_dtim == 0) { - bcn_li_dtim = 1; - } - } else { - /* attemp to use platform defined dtim skip interval */ - bcn_li_dtim = dhd->suspend_bcn_li_dtim; - - /* check if sta listen interval fits into AP dtim */ - if (*dtim_period > CUSTOM_LISTEN_INTERVAL) { - /* AP DTIM to big for our Listen Interval : no dtim skiping */ - bcn_li_dtim = NO_DTIM_SKIP; - DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", - __FUNCTION__, *dtim_period, CUSTOM_LISTEN_INTERVAL)); - return bcn_li_dtim; - } - - if (((*dtim_period) * (*bcn_interval) * bcn_li_dtim) > MAX_DTIM_ALLOWED_INTERVAL) { - allowed_skip_dtim_cnt = - MAX_DTIM_ALLOWED_INTERVAL / ((*dtim_period) * (*bcn_interval)); - bcn_li_dtim = - (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt : NO_DTIM_SKIP; - } - - if ((bcn_li_dtim * (*dtim_period)) > CUSTOM_LISTEN_INTERVAL) { - /* Round up dtim_skip to fit into STAs Listen Interval */ - bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / *dtim_period); - DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim)); - } - } - - DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n", - __FUNCTION__, *bcn_interval, bcn_li_dtim, *dtim_period, CUSTOM_LISTEN_INTERVAL)); - - return bcn_li_dtim; -} -#else /* OEM_ANDROID && BCMPCIE */ -int -dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd) -{ - int bcn_li_dtim = 1; /* deafult no dtim skip setting */ - int ret = -1; - int dtim_period = 0; - int ap_beacon = 0; - int allowed_skip_dtim_cnt = 0; - /* Check if associated */ - if (dhd_is_associated(dhd, 0, NULL) == FALSE) { - DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret)); - goto exit; - } - - /* read associated AP beacon interval */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD, - &ap_beacon, sizeof(ap_beacon), FALSE, 0)) < 0) { - DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret)); - goto exit; - } - - /* read associated ap's dtim setup */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, - &dtim_period, sizeof(dtim_period), FALSE, 0)) < 0) { - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); - goto exit; - } - - /* if not assocated just exit */ - if (dtim_period == 0) { - goto exit; - } - - if (dhd->max_dtim_enable) { - bcn_li_dtim = (int) (MAX_DTIM_ALLOWED_INTERVAL / (ap_beacon * dtim_period)); - if (bcn_li_dtim == 0) { - bcn_li_dtim = 1; - } - bcn_li_dtim = MAX(dhd->suspend_bcn_li_dtim, bcn_li_dtim); - } else { - /* attemp to use platform defined dtim skip interval */ - bcn_li_dtim = dhd->suspend_bcn_li_dtim; - - /* check if sta listen interval fits into AP dtim */ - if (dtim_period > CUSTOM_LISTEN_INTERVAL) { - /* AP DTIM to big for our Listen Interval : no dtim skiping */ - bcn_li_dtim = NO_DTIM_SKIP; - DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", - __FUNCTION__, dtim_period, CUSTOM_LISTEN_INTERVAL)); - goto exit; - } - - if ((dtim_period * ap_beacon * bcn_li_dtim) > MAX_DTIM_ALLOWED_INTERVAL) { - allowed_skip_dtim_cnt = - MAX_DTIM_ALLOWED_INTERVAL / (dtim_period * ap_beacon); - bcn_li_dtim = - (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt : NO_DTIM_SKIP; - } - - if ((bcn_li_dtim * dtim_period) > CUSTOM_LISTEN_INTERVAL) { - /* Round up dtim_skip to fit into STAs Listen Interval */ - bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / dtim_period); - DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim)); - } - } - - if (dhd->conf->suspend_bcn_li_dtim >= 0) - bcn_li_dtim = dhd->conf->suspend_bcn_li_dtim; - DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n", - __FUNCTION__, ap_beacon, bcn_li_dtim, dtim_period, CUSTOM_LISTEN_INTERVAL)); - -exit: - return bcn_li_dtim; -} -#endif /* OEM_ANDROID && BCMPCIE */ - -/* Check if the mode supports STA MODE */ -bool dhd_support_sta_mode(dhd_pub_t *dhd) -{ - -#ifdef WL_CFG80211 - if (!(dhd->op_mode & DHD_FLAG_STA_MODE)) - return FALSE; - else -#endif /* WL_CFG80211 */ - return TRUE; -} - -#if defined(KEEP_ALIVE) -int dhd_keep_alive_onoff(dhd_pub_t *dhd) -{ - char buf[32] = {0}; - const char *str; - wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0, 0, 0, 0, 0, {0}}; - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; - int buf_len; - int str_len; - int res = -1; - - if (!dhd_support_sta_mode(dhd)) - return res; - - DHD_TRACE(("%s execution\n", __FUNCTION__)); - - str = "mkeep_alive"; - str_len = strlen(str); - strncpy(buf, str, sizeof(buf) - 1); - buf[ sizeof(buf) - 1 ] = '\0'; - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1); - mkeep_alive_pkt.period_msec = dhd->conf->keep_alive_period; - buf_len = str_len + 1; - mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); - mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); - /* Setup keep alive zero for null packet generation */ - mkeep_alive_pkt.keep_alive_id = 0; - mkeep_alive_pkt.len_bytes = 0; - buf_len += WL_MKEEP_ALIVE_FIXED_LEN; - bzero(mkeep_alive_pkt.data, sizeof(mkeep_alive_pkt.data)); - /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and - * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no - * guarantee that the buffer is properly aligned. - */ - memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); - - res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); - - return res; -} -#endif /* defined(KEEP_ALIVE) */ - -#define CSCAN_TLV_TYPE_SSID_IE 'S' -/* - * SSIDs list parsing from cscan tlv list - */ -int -wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *bytes_left) -{ - char* str; - int idx = 0; - - if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { - DHD_ERROR(("%s error paramters\n", __FUNCTION__)); - return -1; - } - str = *list_str; - while (*bytes_left > 0) { - - if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { - *list_str = str; - DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); - return idx; - } - - /* Get proper CSCAN_TLV_TYPE_SSID_IE */ - *bytes_left -= 1; - str += 1; - ssid[idx].rssi_thresh = 0; - ssid[idx].flags = 0; - if (str[0] == 0) { - /* Broadcast SSID */ - ssid[idx].SSID_len = 0; - memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); - *bytes_left -= 1; - str += 1; - - DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left)); - } - else if (str[0] <= DOT11_MAX_SSID_LEN) { - /* Get proper SSID size */ - ssid[idx].SSID_len = str[0]; - *bytes_left -= 1; - str += 1; - - /* Get SSID */ - if (ssid[idx].SSID_len > *bytes_left) { - DHD_ERROR(("%s out of memory range len=%d but left=%d\n", - __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); - return -1; - } - - memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); - - *bytes_left -= ssid[idx].SSID_len; - str += ssid[idx].SSID_len; - ssid[idx].hidden = TRUE; - - DHD_TRACE(("%s :size=%d left=%d\n", - (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); - } - else { - DHD_ERROR(("### SSID size more that %d\n", str[0])); - return -1; - } - - if (idx++ > max) { - DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx)); - return -1; - } - } - - *list_str = str; - return idx; -} - -#if defined(WL_WIRELESS_EXT) -/* Android ComboSCAN support */ - -/* - * data parsing from ComboScan tlv list -*/ -int -wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, - int input_size, int *bytes_left) -{ - char* str; - uint16 short_temp; - uint32 int_temp; - - if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { - DHD_ERROR(("%s error paramters\n", __FUNCTION__)); - return -1; - } - str = *list_str; - - /* Clean all dest bytes */ - memset(dst, 0, dst_size); - while (*bytes_left > 0) { - - if (str[0] != token) { - DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n", - __FUNCTION__, token, str[0], *bytes_left)); - return -1; - } - - *bytes_left -= 1; - str += 1; - - if (input_size == 1) { - memcpy(dst, str, input_size); - } - else if (input_size == 2) { - memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)), - input_size); - } - else if (input_size == 4) { - memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)), - input_size); - } - - *bytes_left -= input_size; - str += input_size; - *list_str = str; - return 1; - } - return 1; -} - -/* - * channel list parsing from cscan tlv list -*/ -int -wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, - int channel_num, int *bytes_left) -{ - char* str; - int idx = 0; - - if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { - DHD_ERROR(("%s error paramters\n", __FUNCTION__)); - return -1; - } - str = *list_str; - - while (*bytes_left > 0) { - - if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) { - *list_str = str; - DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); - return idx; - } - /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */ - *bytes_left -= 1; - str += 1; - - if (str[0] == 0) { - /* All channels */ - channel_list[idx] = 0x0; - } - else { - channel_list[idx] = (uint16)str[0]; - DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx])); - } - *bytes_left -= 1; - str += 1; - - if (idx++ > 255) { - DHD_ERROR(("%s Too many channels \n", __FUNCTION__)); - return -1; - } - } - - *list_str = str; - return idx; -} - -/* Parse a comma-separated list from list_str into ssid array, starting - * at index idx. Max specifies size of the ssid array. Parses ssids - * and returns updated idx; if idx >= max not all fit, the excess have - * not been copied. Returns -1 on empty string, or on ssid too long. - */ -int -wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max) -{ - char* str, *ptr; - - if ((list_str == NULL) || (*list_str == NULL)) - return -1; - - for (str = *list_str; str != NULL; str = ptr) { - - /* check for next TAG */ - if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) { - *list_str = str + strlen(GET_CHANNEL); - return idx; - } - - if ((ptr = strchr(str, ',')) != NULL) { - *ptr++ = '\0'; - } - - if (strlen(str) > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN)); - return -1; - } - - if (strlen(str) == 0) - ssid[idx].SSID_len = 0; - - if (idx < max) { - bzero(ssid[idx].SSID, sizeof(ssid[idx].SSID)); - strncpy((char*)ssid[idx].SSID, str, sizeof(ssid[idx].SSID) - 1); - ssid[idx].SSID_len = strlen(str); - } - idx++; - } - return idx; -} - -/* - * Parse channel list from iwpriv CSCAN - */ -int -wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num) -{ - int num; - int val; - char* str; - char* endptr = NULL; - - if ((list_str == NULL)||(*list_str == NULL)) - return -1; - - str = *list_str; - num = 0; - while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) { - val = (int)strtoul(str, &endptr, 0); - if (endptr == str) { - DHD_ERROR(("could not parse channel number starting at" - " substring \"%s\" in list:\n%s\n", - str, *list_str)); - return -1; - } - str = endptr + strspn(endptr, " ,"); - - if (num == channel_num) { - DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n", - channel_num, *list_str)); - return -1; - } - - channel_list[num++] = (uint16)val; - } - *list_str = str; - return num; -} - -#endif - -#if defined(TRAFFIC_MGMT_DWM) -static int traffic_mgmt_add_dwm_filter(dhd_pub_t *dhd, - trf_mgmt_filter_list_t * trf_mgmt_filter_list, int len) -{ - int ret = 0; - uint32 i; - trf_mgmt_filter_t *trf_mgmt_filter; - uint8 dwm_tbl_entry; - uint32 dscp = 0; - uint16 dwm_filter_enabled = 0; - - - /* Check parameter length is adequate */ - if (len < (OFFSETOF(trf_mgmt_filter_list_t, filter) + - trf_mgmt_filter_list->num_filters * sizeof(trf_mgmt_filter_t))) { - ret = BCME_BUFTOOSHORT; - return ret; - } - - bzero(&dhd->dhd_tm_dwm_tbl, sizeof(dhd_trf_mgmt_dwm_tbl_t)); - - for (i = 0; i < trf_mgmt_filter_list->num_filters; i++) { - trf_mgmt_filter = &trf_mgmt_filter_list->filter[i]; - - dwm_filter_enabled = (trf_mgmt_filter->flags & TRF_FILTER_DWM); - - if (dwm_filter_enabled) { - dscp = trf_mgmt_filter->dscp; - if (dscp >= DHD_DWM_TBL_SIZE) { - ret = BCME_BADARG; - return ret; - } - } - - dhd->dhd_tm_dwm_tbl.dhd_dwm_enabled = 1; - /* set WMM AC bits */ - dwm_tbl_entry = (uint8) trf_mgmt_filter->priority; - DHD_TRF_MGMT_DWM_SET_FILTER(dwm_tbl_entry); - - /* set favored bits */ - if (trf_mgmt_filter->flags & TRF_FILTER_FAVORED) - DHD_TRF_MGMT_DWM_SET_FAVORED(dwm_tbl_entry); - - dhd->dhd_tm_dwm_tbl.dhd_dwm_tbl[dscp] = dwm_tbl_entry; - } - return ret; -} -#endif - -/* Given filename and download type, returns a buffer pointer and length - * for download to f/w. Type can be FW or NVRAM. - * - */ -int dhd_get_download_buffer(dhd_pub_t *dhd, char *file_path, download_type_t component, - char ** buffer, int *length) - -{ - int ret = BCME_ERROR; - int len = 0; - int file_len; - void *image = NULL; - uint8 *buf = NULL; - - /* Point to cache if available. */ -#ifdef CACHE_FW_IMAGES - if (component == FW) { - if (dhd->cached_fw_length) { - len = dhd->cached_fw_length; - buf = dhd->cached_fw; - } - } - else if (component == NVRAM) { - if (dhd->cached_nvram_length) { - len = dhd->cached_nvram_length; - buf = dhd->cached_nvram; - } - } - else if (component == CLM_BLOB) { - if (dhd->cached_clm_length) { - len = dhd->cached_clm_length; - buf = dhd->cached_clm; - } - } else { - return ret; - } -#endif /* CACHE_FW_IMAGES */ - /* No Valid cache found on this call */ - if (!len) { - file_len = *length; - *length = 0; - - if (file_path) { - image = dhd_os_open_image(file_path); - if (image == NULL) { - DHD_ERROR(("%s: Open image file failed %s\n", __FUNCTION__, file_path)); - goto err; - } - } - - buf = MALLOCZ(dhd->osh, file_len); - if (buf == NULL) { - DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", - __FUNCTION__, file_len)); - goto err; - } - - /* Download image */ -#if defined(BCMEMBEDIMAGE) && defined(DHD_EFI) - if (!image) { - memcpy(buf, nvram_arr, sizeof(nvram_arr)); - len = sizeof(nvram_arr); - } else { - len = dhd_os_get_image_block((char *)buf, file_len, image); - if ((len <= 0 || len > file_len)) { - MFREE(dhd->osh, buf, file_len); - goto err; - } - } -#else - len = dhd_os_get_image_block((char *)buf, file_len, image); - if ((len <= 0 || len > file_len)) { - MFREE(dhd->osh, buf, file_len); - goto err; - } -#endif /* DHD_EFI */ - } - - ret = BCME_OK; - *length = len; - *buffer = (char *)buf; - - /* Cache if first call. */ -#ifdef CACHE_FW_IMAGES - if (component == FW) { - if (!dhd->cached_fw_length) { - dhd->cached_fw = buf; - dhd->cached_fw_length = len; - } - } - else if (component == NVRAM) { - if (!dhd->cached_nvram_length) { - dhd->cached_nvram = buf; - dhd->cached_nvram_length = len; - } - } - else if (component == CLM_BLOB) { - if (!dhd->cached_clm_length) { - dhd->cached_clm = buf; - dhd->cached_clm_length = len; - } - } -#endif /* CACHE_FW_IMAGES */ - -err: - if (image) - dhd_os_close_image(image); - - return ret; -} - -int -dhd_download_2_dongle(dhd_pub_t *dhd, char *iovar, uint16 flag, uint16 dload_type, - unsigned char *dload_buf, int len) -{ - struct wl_dload_data *dload_ptr = (struct wl_dload_data *)dload_buf; - int err = 0; - int dload_data_offset; - static char iovar_buf[WLC_IOCTL_MEDLEN]; - int iovar_len; - - memset(iovar_buf, 0, sizeof(iovar_buf)); - - dload_data_offset = OFFSETOF(wl_dload_data_t, data); - dload_ptr->flag = (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT) | flag; - dload_ptr->dload_type = dload_type; - dload_ptr->len = htod32(len - dload_data_offset); - dload_ptr->crc = 0; - len = ROUNDUP(len, 8); - - iovar_len = bcm_mkiovar(iovar, (char *)dload_buf, - (uint)len, iovar_buf, sizeof(iovar_buf)); - if (iovar_len == 0) { - DHD_ERROR(("%s: insufficient buffer space passed to bcm_mkiovar for '%s' \n", - __FUNCTION__, iovar)); - return BCME_BUFTOOSHORT; - } - - err = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovar_buf, - iovar_len, IOV_SET, 0); - - return err; -} - -int -dhd_download_blob(dhd_pub_t *dhd, unsigned char *image, - uint32 len, char *iovar) -{ - int chunk_len; - int size2alloc; - unsigned char *new_buf; - int err = 0, data_offset; - uint16 dl_flag = DL_BEGIN; - - data_offset = OFFSETOF(wl_dload_data_t, data); - size2alloc = data_offset + MAX_CHUNK_LEN; - size2alloc = ROUNDUP(size2alloc, 8); - - if ((new_buf = (unsigned char *)MALLOCZ(dhd->osh, size2alloc)) != NULL) { - do { - chunk_len = dhd_os_get_image_block((char *)(new_buf + data_offset), - MAX_CHUNK_LEN, image); - if (chunk_len < 0) { - DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n", - __FUNCTION__, chunk_len)); - err = BCME_ERROR; - goto exit; - } - - if (len - chunk_len == 0) - dl_flag |= DL_END; - - err = dhd_download_2_dongle(dhd, iovar, dl_flag, DL_TYPE_CLM, - new_buf, data_offset + chunk_len); - - dl_flag &= ~DL_BEGIN; - - len = len - chunk_len; - } while ((len > 0) && (err == 0)); - } else { - err = BCME_NOMEM; - } -exit: - if (new_buf) { - MFREE(dhd->osh, new_buf, size2alloc); - } - - return err; -} - -int -dhd_check_current_clm_data(dhd_pub_t *dhd) -{ - char iovbuf[WLC_IOCTL_SMLEN] = {0}; - wl_country_t *cspec; - int err = BCME_OK; - - bcm_mkiovar("country", NULL, 0, iovbuf, sizeof(iovbuf)); - err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); - if (err) { - DHD_ERROR(("%s: country code get failed\n", __FUNCTION__)); - return err; - } - - cspec = (wl_country_t *)iovbuf; - if ((strncmp(cspec->ccode, WL_CCODE_NULL_COUNTRY, WLC_CNTRY_BUF_SZ)) == 0) { - DHD_ERROR(("%s: ----- This FW is not included CLM data -----\n", - __FUNCTION__)); - return FALSE; - } - DHD_ERROR(("%s: ----- This FW is included CLM data -----\n", - __FUNCTION__)); - return TRUE; -} - -int -dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path) -{ - char *clm_blob_path; - int len; - unsigned char *imgbuf = NULL; - int err = BCME_OK; - char iovbuf[WLC_IOCTL_SMLEN] = {0}; - int status = FALSE; - - if (clm_path && clm_path[0] != '\0') { - if (strlen(clm_path) > MOD_PARAM_PATHLEN) { - DHD_ERROR(("clm path exceeds max len\n")); - return BCME_ERROR; - } - clm_blob_path = clm_path; - DHD_TRACE(("clm path from module param:%s\n", clm_path)); - } else { - clm_blob_path = CONFIG_BCMDHD_CLM_PATH; - } - - /* If CLM blob file is found on the filesystem, download the file. - * After CLM file download or If the blob file is not present, - * validate the country code before proceeding with the initialization. - * If country code is not valid, fail the initialization. - */ - - imgbuf = dhd_os_open_image((char *)clm_blob_path); - if (imgbuf == NULL) { - DHD_ERROR(("%s: Ignore clm file %s\n", __FUNCTION__, clm_path)); -#if defined(DHD_BLOB_EXISTENCE_CHECK) - if (dhd->is_blob) { - err = BCME_ERROR; - } else { - status = dhd_check_current_clm_data(dhd); - if (status == TRUE) { - err = BCME_OK; - } else { - err = BCME_ERROR; - } - } -#endif /* DHD_BLOB_EXISTENCE_CHECK */ - goto exit; - } - - len = dhd_os_get_image_size(imgbuf); - - if ((len > 0) && (len < MAX_CLM_BUF_SIZE) && imgbuf) { - status = dhd_check_current_clm_data(dhd); - if (status == TRUE) { -#if defined(DHD_BLOB_EXISTENCE_CHECK) - if (dhd->op_mode != DHD_FLAG_MFG_MODE) { - if (dhd->is_blob) { - err = BCME_ERROR; - } - goto exit; - } -#else - DHD_ERROR(("%s: CLM already exist in F/W, " - "new CLM data will be added to the end of existing CLM data!\n", - __FUNCTION__)); -#endif /* DHD_BLOB_EXISTENCE_CHECK */ - } - - /* Found blob file. Download the file */ - DHD_ERROR(("clm file download from %s \n", clm_blob_path)); - err = dhd_download_blob(dhd, imgbuf, len, "clmload"); - if (err) { - DHD_ERROR(("%s: CLM download failed err=%d\n", __FUNCTION__, err)); - /* Retrieve clmload_status and print */ - bcm_mkiovar("clmload_status", NULL, 0, iovbuf, sizeof(iovbuf)); - err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0); - if (err) { - DHD_ERROR(("%s: clmload_status get failed err=%d \n", - __FUNCTION__, err)); - } else { - DHD_ERROR(("%s: clmload_status: %d \n", - __FUNCTION__, *((int *)iovbuf))); - if (*((int *)iovbuf) == CHIPID_MISMATCH) { - DHD_ERROR(("Chip ID mismatch error \n")); - } - } - err = BCME_ERROR; - goto exit; - } else { - DHD_INFO(("%s: CLM download succeeded \n", __FUNCTION__)); - } - } else { - DHD_INFO(("Skipping the clm download. len:%d memblk:%p \n", len, imgbuf)); - } - - /* Verify country code */ - status = dhd_check_current_clm_data(dhd); - - if (status != TRUE) { - /* Country code not initialized or CLM download not proper */ - DHD_ERROR(("country code not initialized\n")); - err = BCME_ERROR; - } -exit: - - if (imgbuf) { - dhd_os_close_image(imgbuf); - } - - return err; -} - -void dhd_free_download_buffer(dhd_pub_t *dhd, void *buffer, int length) -{ -#ifdef CACHE_FW_IMAGES - return; -#endif - MFREE(dhd->osh, buffer, length); -} - -#if defined(DHD_8021X_DUMP) -#define EAP_PRINT(str) \ - DHD_ERROR(("ETHER_TYPE_802_1X[%s] [%s]: " str "\n", \ - ifname, direction ? "TX" : "RX")); -/* Parse EAPOL 4 way handshake messages */ -void -dhd_dump_eapol_4way_message(char *ifname, char *dump_data, bool direction) -{ - unsigned char type; - int pair, ack, mic, kerr, req, sec, install; - unsigned short us_tmp; - - type = dump_data[15]; - if (type == 0) { - if ((dump_data[22] == 1) && (dump_data[18] == 1)) { - EAP_PRINT("EAP Packet, Request, Identity"); - } else if ((dump_data[22] == 1) && (dump_data[18] == 2)) { - EAP_PRINT("EAP Packet, Response, Identity"); - } else if (dump_data[22] == 254) { - if (dump_data[30] == 1) { - EAP_PRINT("EAP Packet, WSC Start"); - } else if (dump_data[30] == 4) { - if (dump_data[41] == 4) { - EAP_PRINT("EAP Packet, WPS M1"); - } else if (dump_data[41] == 5) { - EAP_PRINT("EAP Packet, WPS M2"); - } else if (dump_data[41] == 7) { - EAP_PRINT("EAP Packet, WPS M3"); - } else if (dump_data[41] == 8) { - EAP_PRINT("EAP Packet, WPS M4"); - } else if (dump_data[41] == 9) { - EAP_PRINT("EAP Packet, WPS M5"); - } else if (dump_data[41] == 10) { - EAP_PRINT("EAP Packet, WPS M6"); - } else if (dump_data[41] == 11) { - EAP_PRINT("EAP Packet, WPS M7"); - } else if (dump_data[41] == 12) { - EAP_PRINT("EAP Packet, WPS M8"); - } - } else if (dump_data[30] == 5) { - EAP_PRINT("EAP Packet, WSC Done"); - } - } else { - DHD_ERROR(("ETHER_TYPE_802_1X[%s] [%s]: ver %d, type %d, replay %d\n", - ifname, direction ? "TX" : "RX", - dump_data[14], dump_data[15], dump_data[30])); - } - } else if (type == 3 && dump_data[18] == 2) { - us_tmp = (dump_data[19] << 8) | dump_data[20]; - pair = 0 != (us_tmp & 0x08); - ack = 0 != (us_tmp & 0x80); - mic = 0 != (us_tmp & 0x100); - kerr = 0 != (us_tmp & 0x400); - req = 0 != (us_tmp & 0x800); - sec = 0 != (us_tmp & 0x200); - install = 0 != (us_tmp & 0x40); - - if (!sec && !mic && ack && !install && pair && !kerr && !req) { - EAP_PRINT("EAPOL Packet, 4-way handshake, M1"); - } else if (pair && !install && !ack && mic && !sec && !kerr && !req) { - EAP_PRINT("EAPOL Packet, 4-way handshake, M2"); - } else if (pair && ack && mic && sec && !kerr && !req) { - EAP_PRINT("EAPOL Packet, 4-way handshake, M3"); - } else if (pair && !install && !ack && mic && sec && !req && !kerr) { - EAP_PRINT("EAPOL Packet, 4-way handshake, M4"); - } else { - DHD_ERROR(("ETHER_TYPE_802_1X[%s] [%s]: ver %d, type %d, replay %d\n", - ifname, direction ? "TX" : "RX", - dump_data[14], dump_data[15], dump_data[30])); - } - } else { - DHD_ERROR(("ETHER_TYPE_802_1X[%s] [%s]: ver %d, type %d, replay %d\n", - ifname, direction ? "TX" : "RX", - dump_data[14], dump_data[15], dump_data[30])); - } -} -#endif /* DHD_8021X_DUMP */ - -#ifdef REPORT_FATAL_TIMEOUTS -void init_dhd_timeouts(dhd_pub_t *pub) -{ - pub->timeout_info = MALLOC(pub->osh, sizeof(timeout_info_t)); - if (pub->timeout_info == NULL) { - DHD_ERROR(("%s: Failed to alloc timeout_info\n", __FUNCTION__)); - } else { - DHD_INFO(("Initializing dhd_timeouts\n")); - pub->timeout_info->scan_timer_lock = dhd_os_spin_lock_init(pub->osh); - pub->timeout_info->join_timer_lock = dhd_os_spin_lock_init(pub->osh); - pub->timeout_info->bus_timer_lock = dhd_os_spin_lock_init(pub->osh); - pub->timeout_info->cmd_timer_lock = dhd_os_spin_lock_init(pub->osh); - pub->timeout_info->scan_timeout_val = SCAN_TIMEOUT_DEFAULT; - pub->timeout_info->join_timeout_val = JOIN_TIMEOUT_DEFAULT; - pub->timeout_info->cmd_timeout_val = CMD_TIMEOUT_DEFAULT; - pub->timeout_info->bus_timeout_val = BUS_TIMEOUT_DEFAULT; - pub->timeout_info->scan_timer_active = FALSE; - pub->timeout_info->join_timer_active = FALSE; - pub->timeout_info->cmd_timer_active = FALSE; - pub->timeout_info->bus_timer_active = FALSE; - pub->timeout_info->cmd_join_error = WLC_SSID_MASK; - pub->timeout_info->cmd_request_id = 0; - } -} - -void -deinit_dhd_timeouts(dhd_pub_t *pub) -{ - /* stop the join, scan bus, cmd timers - * as failing to do so may cause a kernel panic if - * an rmmod is done - */ - if (!pub->timeout_info) { - DHD_ERROR(("timeout_info pointer is NULL\n")); - ASSERT(0); - return; - } - if (dhd_stop_scan_timer(pub)) { - DHD_ERROR(("dhd_stop_scan_timer failed\n")); - ASSERT(0); - } - if (dhd_stop_bus_timer(pub)) { - DHD_ERROR(("dhd_stop_bus_timer failed\n")); - ASSERT(0); - } - if (dhd_stop_cmd_timer(pub)) { - DHD_ERROR(("dhd_stop_cmd_timer failed\n")); - ASSERT(0); - } - if (dhd_stop_join_timer(pub)) { - DHD_ERROR(("dhd_stop_join_timer failed\n")); - ASSERT(0); - } - - dhd_os_spin_lock_deinit(pub->osh, pub->timeout_info->scan_timer_lock); - dhd_os_spin_lock_deinit(pub->osh, pub->timeout_info->join_timer_lock); - dhd_os_spin_lock_deinit(pub->osh, pub->timeout_info->bus_timer_lock); - dhd_os_spin_lock_deinit(pub->osh, pub->timeout_info->cmd_timer_lock); - MFREE(pub->osh, pub->timeout_info, sizeof(timeout_info_t)); - pub->timeout_info = NULL; -} - -static void -dhd_cmd_timeout(void *ctx) -{ - dhd_pub_t *pub = (dhd_pub_t *)ctx; - unsigned long flags; - - if (!pub->timeout_info) { - DHD_ERROR(("DHD: timeout_info NULL\n")); - ASSERT(0); - return; - } - - DHD_TIMER_LOCK(pub->timeout_info->cmd_timer_lock, flags); - if (pub->timeout_info && pub->timeout_info->cmd_timer_active) { - DHD_ERROR(("\nERROR COMMAND TIMEOUT TO:%d\n", pub->timeout_info->cmd_timeout_val)); - DHD_TIMER_UNLOCK(pub->timeout_info->cmd_timer_lock, flags); -#ifdef PCIE_OOB - /* Assert device_wake so that UART_Rx is available */ - if (dhd_bus_set_device_wake(pub->bus, TRUE)) { - DHD_ERROR(("%s: dhd_bus_set_device_wake() failed\n", __FUNCTION__)); - ASSERT(0); - } -#endif /* PCIE_OOB */ - if (dhd_stop_cmd_timer(pub)) { - DHD_ERROR(("%s: dhd_stop_cmd_timer() failed\n", __FUNCTION__)); - ASSERT(0); - } - dhd_wakeup_ioctl_event(pub, IOCTL_RETURN_ON_ERROR); - if (!dhd_query_bus_erros(pub)) - dhd_send_trap_to_fw_for_timeout(pub, DHD_REASON_COMMAND_TO); - } else { - DHD_TIMER_UNLOCK(pub->timeout_info->cmd_timer_lock, flags); - } -} - -int -dhd_start_cmd_timer(dhd_pub_t *pub) -{ - int ret = BCME_OK; - unsigned long flags = 0; - uint32 cmd_to_ms; - - if (!pub->timeout_info) { - DHD_ERROR(("DHD: timeout_info NULL\n")); - ret = BCME_ERROR; - ASSERT(0); - goto exit_null; - } - DHD_TIMER_LOCK(pub->timeout_info->cmd_timer_lock, flags); - cmd_to_ms = pub->timeout_info->cmd_timeout_val; - - if (pub->timeout_info->cmd_timeout_val == 0) { - /* Disable Command timer timeout */ - DHD_INFO(("DHD: Command Timeout Disabled\n")); - goto exit; - } - if (pub->timeout_info->cmd_timer_active) { - DHD_ERROR(("%s:Timer already active\n", __FUNCTION__)); - ret = BCME_ERROR; - ASSERT(0); - } else { - pub->timeout_info->cmd_timer = osl_timer_init(pub->osh, - "cmd_timer", dhd_cmd_timeout, pub); - osl_timer_update(pub->osh, pub->timeout_info->cmd_timer, - cmd_to_ms, 0); - pub->timeout_info->cmd_timer_active = TRUE; - } - if (ret == BCME_OK) { - DHD_INFO(("%s Cmd Timer started\n", __FUNCTION__)); - } -exit: - DHD_TIMER_UNLOCK(pub->timeout_info->cmd_timer_lock, flags); -exit_null: - return ret; -} - -int -dhd_stop_cmd_timer(dhd_pub_t *pub) -{ - int ret = BCME_OK; - unsigned long flags = 0; - - if (!pub->timeout_info) { - DHD_ERROR(("DHD: timeout_info NULL\n")); - ret = BCME_ERROR; - ASSERT(0); - goto exit; - } - DHD_TIMER_LOCK(pub->timeout_info->cmd_timer_lock, flags); - - if (pub->timeout_info->cmd_timer_active) { - osl_timer_del(pub->osh, pub->timeout_info->cmd_timer); - pub->timeout_info->cmd_timer_active = FALSE; - } - else { - DHD_INFO(("DHD: CMD timer is not active\n")); - } - if (ret == BCME_OK) { - DHD_INFO(("%s Cmd Timer Stopped\n", __FUNCTION__)); - } - DHD_TIMER_UNLOCK(pub->timeout_info->cmd_timer_lock, flags); -exit: - return ret; -} - -static int -__dhd_stop_join_timer(dhd_pub_t *pub) -{ - int ret = BCME_OK; - if (!pub->timeout_info) { - DHD_ERROR(("DHD: timeout_info NULL\n")); - ASSERT(0); - return BCME_ERROR; - } - - if (pub->timeout_info->join_timer_active) { - osl_timer_del(pub->osh, pub->timeout_info->join_timer); - pub->timeout_info->join_timer_active = FALSE; - } else { - DHD_INFO(("DHD: JOIN timer is not active\n")); - } - if (ret == BCME_OK) { - DHD_INFO(("%s: Join Timer Stopped\n", __FUNCTION__)); - } - return ret; -} - -static void -dhd_join_timeout(void *ctx) -{ - dhd_pub_t *pub = (dhd_pub_t *)ctx; - unsigned long flags; - - if (!pub->timeout_info) { - DHD_ERROR(("DHD: timeout_info NULL\n")); - ASSERT(0); - return; - } - - DHD_TIMER_LOCK(pub->timeout_info->join_timer_lock, flags); - if (pub->timeout_info->join_timer_active) { - DHD_TIMER_UNLOCK(pub->timeout_info->join_timer_lock, flags); - if (dhd_stop_join_timer(pub)) { - DHD_ERROR(("%s: dhd_stop_join_timer() failed\n", __FUNCTION__)); - ASSERT(0); - } - if (pub->timeout_info->cmd_join_error) { - DHD_ERROR(("\nERROR JOIN TIMEOUT TO:%d:0x%x\n", - pub->timeout_info->join_timeout_val, - pub->timeout_info->cmd_join_error)); -#ifdef DHD_FW_COREDUMP - /* collect core dump and crash */ - pub->memdump_enabled = DUMP_MEMFILE_BUGON; - pub->memdump_type = DUMP_TYPE_JOIN_TIMEOUT; - dhd_bus_mem_dump(pub); -#endif /* DHD_FW_COREDUMP */ - - } - } else { - DHD_TIMER_UNLOCK(pub->timeout_info->join_timer_lock, flags); - } -} - -int -dhd_start_join_timer(dhd_pub_t *pub) -{ - int ret = BCME_OK; - unsigned long flags = 0; - uint32 join_to_ms; - - if (!pub->timeout_info) { - DHD_ERROR(("DHD: timeout_info NULL\n")); - ret = BCME_ERROR; - ASSERT(0); - goto exit; - } - - join_to_ms = pub->timeout_info->join_timeout_val; - DHD_TIMER_LOCK(pub->timeout_info->join_timer_lock, flags); - if (pub->timeout_info->join_timer_active) { - DHD_ERROR(("%s:Stoping active timer\n", __FUNCTION__)); - __dhd_stop_join_timer(pub); - } - if (pub->timeout_info->join_timeout_val == 0) { - /* Disable Join timer timeout */ - DHD_INFO(("DHD: Join Timeout Disabled\n")); - } else { - pub->timeout_info->join_timer = osl_timer_init(pub->osh, - "join_timer", dhd_join_timeout, pub); - osl_timer_update(pub->osh, pub->timeout_info->join_timer, join_to_ms, 0); - pub->timeout_info->join_timer_active = TRUE; - pub->timeout_info->cmd_join_error |= WLC_SSID_MASK; - } - if (ret == BCME_OK) { - DHD_INFO(("%s:Join Timer started 0x%x\n", __FUNCTION__, - pub->timeout_info->cmd_join_error)); - } - DHD_TIMER_UNLOCK(pub->timeout_info->join_timer_lock, flags); -exit: - return ret; -} - -int -dhd_stop_join_timer(dhd_pub_t *pub) -{ - int ret = BCME_OK; - unsigned long flags; - - DHD_TIMER_LOCK(pub->timeout_info->join_timer_lock, flags); - ret = __dhd_stop_join_timer(pub); - DHD_TIMER_UNLOCK(pub->timeout_info->join_timer_lock, flags); - return ret; -} - -static void -dhd_scan_timeout(void *ctx) -{ - dhd_pub_t *pub = (dhd_pub_t *)ctx; - unsigned long flags; - - if (pub->timeout_info == NULL) { - DHD_ERROR(("timeout_info pointer is NULL\n")); - ASSERT(0); - return; - } - - DHD_TIMER_LOCK(pub->timeout_info->scan_timer_lock, flags); - if (pub->timeout_info && pub->timeout_info->scan_timer_active) { - DHD_ERROR(("\nERROR SCAN TIMEOUT TO:%d\n", pub->timeout_info->scan_timeout_val)); - DHD_TIMER_UNLOCK(pub->timeout_info->scan_timer_lock, flags); - dhd_stop_scan_timer(pub); - if (!dhd_query_bus_erros(pub)) - dhd_send_trap_to_fw_for_timeout(pub, DHD_REASON_SCAN_TO); - } else { - DHD_TIMER_UNLOCK(pub->timeout_info->scan_timer_lock, flags); - } -} - -int -dhd_start_scan_timer(dhd_pub_t *pub) -{ - int ret = BCME_OK; - unsigned long flags = 0; - uint32 scan_to_ms; - - if (!pub->timeout_info) { - DHD_ERROR(("DHD: timeout_info NULL\n")); - ret = BCME_ERROR; - ASSERT(0); - goto exit_null; - } - DHD_TIMER_LOCK(pub->timeout_info->scan_timer_lock, flags); - scan_to_ms = pub->timeout_info->scan_timeout_val; - - if (pub->timeout_info->scan_timer_active) { - /* NOTE : New scan timeout value will be effective - * only once current scan is completed. - */ - DHD_ERROR(("%s:Timer already active\n", __FUNCTION__)); - ret = BCME_ERROR; - goto exit; - } - - if (pub->timeout_info->scan_timeout_val == 0) { - /* Disable Scan timer timeout */ - DHD_INFO(("DHD: Scan Timeout Disabled\n")); - } else { - pub->timeout_info->scan_timer = osl_timer_init(pub->osh, "scan_timer", - dhd_scan_timeout, pub); - pub->timeout_info->scan_timer_active = TRUE; - osl_timer_update(pub->osh, pub->timeout_info->scan_timer, scan_to_ms, 0); - } - if (ret == BCME_OK) { - DHD_INFO(("%s Scan Timer started\n", __FUNCTION__)); - } -exit: - DHD_TIMER_UNLOCK(pub->timeout_info->scan_timer_lock, flags); -exit_null: - return ret; -} - -int -dhd_stop_scan_timer(dhd_pub_t *pub) -{ - int ret = BCME_OK; - unsigned long flags = 0; - - if (!pub->timeout_info) { - DHD_ERROR(("DHD: timeout_info NULL\n")); - ret = BCME_ERROR; - ASSERT(0); - goto exit; - } - DHD_TIMER_LOCK(pub->timeout_info->scan_timer_lock, flags); - - if (pub->timeout_info->scan_timer_active) { - osl_timer_del(pub->osh, pub->timeout_info->scan_timer); - pub->timeout_info->scan_timer_active = FALSE; - } - else { - DHD_INFO(("DHD: SCAN timer is not active\n")); - } - - if (ret == BCME_OK) { - DHD_INFO(("%s Scan Timer Stopped\n", __FUNCTION__)); - } - DHD_TIMER_UNLOCK(pub->timeout_info->scan_timer_lock, flags); -exit: - return ret; -} - -static void -dhd_bus_timeout(void *ctx) -{ - dhd_pub_t *pub = (dhd_pub_t *)ctx; - unsigned long flags; - - if (pub->timeout_info == NULL) { - DHD_ERROR(("timeout_info pointer is NULL\n")); - ASSERT(0); - return; - } - - DHD_TIMER_LOCK(pub->timeout_info->bus_timer_lock, flags); - if (pub->timeout_info->bus_timer_active) { - DHD_ERROR(("\nERROR BUS TIMEOUT TO:%d\n", pub->timeout_info->bus_timeout_val)); - DHD_TIMER_UNLOCK(pub->timeout_info->bus_timer_lock, flags); -#ifdef PCIE_OOB - /* Assert device_wake so that UART_Rx is available */ - if (dhd_bus_set_device_wake(pub->bus, TRUE)) { - DHD_ERROR(("%s: dhd_bus_set_device_wake() failed\n", __FUNCTION__)); - ASSERT(0); - } -#endif /* PCIE_OOB */ - if (dhd_stop_bus_timer(pub)) { - DHD_ERROR(("%s: dhd_stop_bus_timer() failed\n", __FUNCTION__)); - ASSERT(0); - } - if (!dhd_query_bus_erros(pub)) - dhd_send_trap_to_fw_for_timeout(pub, DHD_REASON_OQS_TO); - } else { - DHD_TIMER_UNLOCK(pub->timeout_info->bus_timer_lock, flags); - } -} - -int -dhd_start_bus_timer(dhd_pub_t *pub) -{ - int ret = BCME_OK; - unsigned long flags = 0; - uint32 bus_to_ms; - - if (!pub->timeout_info) { - DHD_ERROR(("DHD: timeout_info NULL\n")); - ret = BCME_ERROR; - ASSERT(0); - goto exit_null; - } - DHD_TIMER_LOCK(pub->timeout_info->bus_timer_lock, flags); - bus_to_ms = pub->timeout_info->bus_timeout_val; - - if (pub->timeout_info->bus_timeout_val == 0) { - /* Disable Bus timer timeout */ - DHD_INFO(("DHD: Bus Timeout Disabled\n")); - goto exit; - } - if (pub->timeout_info->bus_timer_active) { - DHD_ERROR(("%s:Timer already active\n", __FUNCTION__)); - ret = BCME_ERROR; - ASSERT(0); - } else { - pub->timeout_info->bus_timer = osl_timer_init(pub->osh, - "bus_timer", dhd_bus_timeout, pub); - pub->timeout_info->bus_timer_active = TRUE; - osl_timer_update(pub->osh, pub->timeout_info->bus_timer, bus_to_ms, 0); - } - if (ret == BCME_OK) { - DHD_INFO(("%s: BUS Timer started\n", __FUNCTION__)); - } -exit: - DHD_TIMER_UNLOCK(pub->timeout_info->bus_timer_lock, flags); -exit_null: - return ret; -} - -int -dhd_stop_bus_timer(dhd_pub_t *pub) -{ - int ret = BCME_OK; - unsigned long flags = 0; - - if (!pub->timeout_info) { - DHD_ERROR(("DHD: timeout_info NULL\n")); - ret = BCME_ERROR; - ASSERT(0); - goto exit; - } - DHD_TIMER_LOCK(pub->timeout_info->bus_timer_lock, flags); - - if (pub->timeout_info->bus_timer_active) { - osl_timer_del(pub->osh, pub->timeout_info->bus_timer); - pub->timeout_info->bus_timer_active = FALSE; - } - else { - DHD_INFO(("DHD: BUS timer is not active\n")); - } - if (ret == BCME_OK) { - DHD_INFO(("%s: Bus Timer Stopped\n", __FUNCTION__)); - } - DHD_TIMER_UNLOCK(pub->timeout_info->bus_timer_lock, flags); -exit: - return ret; -} - -int -dhd_set_request_id(dhd_pub_t *pub, uint16 id, uint32 cmd) -{ - DHD_INFO(("%s: id:%d\n", __FUNCTION__, id)); - if (pub->timeout_info) { - pub->timeout_info->cmd_request_id = id; - pub->timeout_info->cmd = cmd; - return BCME_OK; - } else { - return BCME_ERROR; - } -} - -uint16 -dhd_get_request_id(dhd_pub_t *pub) -{ - if (pub->timeout_info) { - return (pub->timeout_info->cmd_request_id); - } else { - return 0; - } -} - -void -dhd_set_join_error(dhd_pub_t *pub, uint32 mask) -{ - DHD_INFO(("Setting join Error %d\n", mask)); - if (pub->timeout_info) { - pub->timeout_info->cmd_join_error |= mask; - } -} - -void -dhd_clear_join_error(dhd_pub_t *pub, uint32 mask) -{ - DHD_INFO(("clear join Error %d\n", mask)); - if (pub->timeout_info) { - pub->timeout_info->cmd_join_error &= ~mask; - } -} - -void -dhd_get_scan_to_val(dhd_pub_t *pub, uint32 *to_val) -{ - if (pub->timeout_info) { - *to_val = pub->timeout_info->scan_timeout_val; - } else { - *to_val = 0; - } -} - -void -dhd_set_scan_to_val(dhd_pub_t *pub, uint32 to_val) -{ - if (pub->timeout_info) { - DHD_INFO(("Setting TO val:%d\n", to_val)); - pub->timeout_info->scan_timeout_val = to_val; - } -} - -void -dhd_get_join_to_val(dhd_pub_t *pub, uint32 *to_val) -{ - if (pub->timeout_info) { - *to_val = pub->timeout_info->join_timeout_val; - } else { - *to_val = 0; - } -} - -void -dhd_set_join_to_val(dhd_pub_t *pub, uint32 to_val) -{ - if (pub->timeout_info) { - DHD_INFO(("Setting TO val:%d\n", to_val)); - pub->timeout_info->join_timeout_val = to_val; - } -} - -void -dhd_get_cmd_to_val(dhd_pub_t *pub, uint32 *to_val) -{ - if (pub->timeout_info) { - *to_val = pub->timeout_info->cmd_timeout_val; - } else { - *to_val = 0; - } -} - -void -dhd_set_cmd_to_val(dhd_pub_t *pub, uint32 to_val) -{ - if (pub->timeout_info) { - DHD_INFO(("Setting TO val:%d\n", to_val)); - pub->timeout_info->cmd_timeout_val = to_val; - } -} - -void -dhd_get_bus_to_val(dhd_pub_t *pub, uint32 *to_val) -{ - if (pub->timeout_info) { - *to_val = pub->timeout_info->bus_timeout_val; - } else { - *to_val = 0; - } -} - -void -dhd_set_bus_to_val(dhd_pub_t *pub, uint32 to_val) -{ - if (pub->timeout_info) { - DHD_INFO(("Setting TO val:%d\n", to_val)); - pub->timeout_info->bus_timeout_val = to_val; - } -} -#endif /* REPORT_FATAL_TIMEOUTS */ - -#ifdef SHOW_LOGTRACE -int -dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size, - dhd_event_log_t *event_log) -{ - logstr_header_t *hdr = NULL; - uint32 *lognums = NULL; - char *logstrs = NULL; - int ram_index = 0; - char **fmts; - int num_fmts = 0; - int32 i = 0; - - /* Remember header from the logstrs.bin file */ - hdr = (logstr_header_t *) (raw_fmts + logstrs_size - - sizeof(logstr_header_t)); - - if (hdr->log_magic == LOGSTRS_MAGIC) { - /* - * logstrs.bin start with header. - */ - num_fmts = hdr->rom_logstrs_offset / sizeof(uint32); - ram_index = (hdr->ram_lognums_offset - - hdr->rom_lognums_offset) / sizeof(uint32); - lognums = (uint32 *) &raw_fmts[hdr->rom_lognums_offset]; - logstrs = (char *) &raw_fmts[hdr->rom_logstrs_offset]; - } else { - /* - * Legacy logstrs.bin format without header. - */ - num_fmts = *((uint32 *) (raw_fmts)) / sizeof(uint32); - if (num_fmts == 0) { - /* Legacy ROM/RAM logstrs.bin format: - * - ROM 'lognums' section - * - RAM 'lognums' section - * - ROM 'logstrs' section. - * - RAM 'logstrs' section. - * - * 'lognums' is an array of indexes for the strings in the - * 'logstrs' section. The first uint32 is 0 (index of first - * string in ROM 'logstrs' section). - * - * The 4324b5 is the only ROM that uses this legacy format. Use the - * fixed number of ROM fmtnums to find the start of the RAM - * 'lognums' section. Use the fixed first ROM string ("Con\n") to - * find the ROM 'logstrs' section. - */ - #define NUM_4324B5_ROM_FMTS 186 - #define FIRST_4324B5_ROM_LOGSTR "Con\n" - ram_index = NUM_4324B5_ROM_FMTS; - lognums = (uint32 *) raw_fmts; - num_fmts = ram_index; - logstrs = (char *) &raw_fmts[num_fmts << 2]; - while (strncmp(FIRST_4324B5_ROM_LOGSTR, logstrs, 4)) { - num_fmts++; - logstrs = (char *) &raw_fmts[num_fmts << 2]; - } - } else { - /* Legacy RAM-only logstrs.bin format: - * - RAM 'lognums' section - * - RAM 'logstrs' section. - * - * 'lognums' is an array of indexes for the strings in the - * 'logstrs' section. The first uint32 is an index to the - * start of 'logstrs'. Therefore, if this index is divided - * by 'sizeof(uint32)' it provides the number of logstr - * entries. - */ - ram_index = 0; - lognums = (uint32 *) raw_fmts; - logstrs = (char *) &raw_fmts[num_fmts << 2]; - } - } - fmts = MALLOC(osh, num_fmts * sizeof(char *)); - if (fmts == NULL) { - DHD_ERROR(("%s: Failed to allocate fmts memory\n", __FUNCTION__)); - return BCME_ERROR; - } - event_log->fmts_size = num_fmts * sizeof(char *); - - for (i = 0; i < num_fmts; i++) { - /* ROM lognums index into logstrs using 'rom_logstrs_offset' as a base - * (they are 0-indexed relative to 'rom_logstrs_offset'). - * - * RAM lognums are already indexed to point to the correct RAM logstrs (they - * are 0-indexed relative to the start of the logstrs.bin file). - */ - if (i == ram_index) { - logstrs = raw_fmts; - } - fmts[i] = &logstrs[lognums[i]]; - } - event_log->fmts = fmts; - event_log->raw_fmts_size = logstrs_size; - event_log->raw_fmts = raw_fmts; - event_log->num_fmts = num_fmts; - - return BCME_OK; -} - -int dhd_parse_map_file(osl_t *osh, void *file, uint32 *ramstart, uint32 *rodata_start, - uint32 *rodata_end) -{ - char *raw_fmts = NULL; - uint32 read_size = READ_NUM_BYTES; - int error = 0; - char * cptr = NULL; - char c; - uint8 count = 0; - - *ramstart = 0; - *rodata_start = 0; - *rodata_end = 0; - - /* Allocate 1 byte more than read_size to terminate it with NULL */ - raw_fmts = MALLOC(osh, read_size + 1); - if (raw_fmts == NULL) { - DHD_ERROR(("%s: Failed to allocate raw_fmts memory \n", __FUNCTION__)); - goto fail; - } - - /* read ram start, rodata_start and rodata_end values from map file */ - while (count != ALL_MAP_VAL) - { - error = dhd_os_read_file(file, raw_fmts, read_size); - if (error < 0) { - DHD_ERROR(("%s: map file read failed err:%d \n", __FUNCTION__, - error)); - goto fail; - } - - /* End raw_fmts with NULL as strstr expects NULL terminated strings */ - raw_fmts[read_size] = '\0'; - - /* Get ramstart address */ - if ((cptr = strstr(raw_fmts, ramstart_str))) { - cptr = cptr - BYTES_AHEAD_NUM; - sscanf(cptr, "%x %c text_start", ramstart, &c); - count |= RAMSTART_BIT; - } - - /* Get ram rodata start address */ - if ((cptr = strstr(raw_fmts, rodata_start_str))) { - cptr = cptr - BYTES_AHEAD_NUM; - sscanf(cptr, "%x %c rodata_start", rodata_start, &c); - count |= RDSTART_BIT; - } - - /* Get ram rodata end address */ - if ((cptr = strstr(raw_fmts, rodata_end_str))) { - cptr = cptr - BYTES_AHEAD_NUM; - sscanf(cptr, "%x %c rodata_end", rodata_end, &c); - count |= RDEND_BIT; - } - - if (error < (int)read_size) { - /* - * since we reset file pos back to earlier pos by - * GO_BACK_FILE_POS_NUM_BYTES bytes we won't reach EOF. - * The reason for this is if string is spreaded across - * bytes, the read function should not miss it. - * So if ret value is less than read_size, reached EOF don't read further - */ - break; - } - memset(raw_fmts, 0, read_size); - /* - * go back to predefined NUM of bytes so that we won't miss - * the string and addr even if it comes as splited in next read. - */ - dhd_os_seek_file(file, -GO_BACK_FILE_POS_NUM_BYTES); - } - - -fail: - if (raw_fmts) { - MFREE(osh, raw_fmts, read_size + 1); - raw_fmts = NULL; - } - if (count == ALL_MAP_VAL) - return BCME_OK; - else { - DHD_ERROR(("%s: readmap error 0X%x \n", __FUNCTION__, - count)); - return BCME_ERROR; - } - -} - -#ifdef PCIE_FULL_DONGLE -int -dhd_event_logtrace_infobuf_pkt_process(dhd_pub_t *dhdp, void *pktbuf, - dhd_event_log_t *event_data) -{ - uint32 infobuf_version; - info_buf_payload_hdr_t *payload_hdr_ptr; - uint16 payload_hdr_type; - uint16 payload_hdr_length; - - DHD_TRACE(("%s:Enter\n", __FUNCTION__)); - - if (PKTLEN(dhdp->osh, pktbuf) < sizeof(uint32)) { - DHD_ERROR(("%s: infobuf too small for version field\n", - __FUNCTION__)); - goto exit; - } - infobuf_version = *((uint32 *)PKTDATA(dhdp->osh, pktbuf)); - PKTPULL(dhdp->osh, pktbuf, sizeof(uint32)); - if (infobuf_version != PCIE_INFOBUF_V1) { - DHD_ERROR(("%s: infobuf version %d is not PCIE_INFOBUF_V1\n", - __FUNCTION__, infobuf_version)); - goto exit; - } - - /* Version 1 infobuf has a single type/length (and then value) field */ - if (PKTLEN(dhdp->osh, pktbuf) < sizeof(info_buf_payload_hdr_t)) { - DHD_ERROR(("%s: infobuf too small for v1 type/length fields\n", - __FUNCTION__)); - goto exit; - } - /* Process/parse the common info payload header (type/length) */ - payload_hdr_ptr = (info_buf_payload_hdr_t *)PKTDATA(dhdp->osh, pktbuf); - payload_hdr_type = ltoh16(payload_hdr_ptr->type); - payload_hdr_length = ltoh16(payload_hdr_ptr->length); - if (payload_hdr_type != PCIE_INFOBUF_V1_TYPE_LOGTRACE) { - DHD_ERROR(("%s: payload_hdr_type %d is not V1_TYPE_LOGTRACE\n", - __FUNCTION__, payload_hdr_type)); - goto exit; - } - PKTPULL(dhdp->osh, pktbuf, sizeof(info_buf_payload_hdr_t)); - - /* Validate that the specified length isn't bigger than the - * provided data. - */ - if (payload_hdr_length > PKTLEN(dhdp->osh, pktbuf)) { - DHD_ERROR(("%s: infobuf logtrace length is bigger" - " than actual buffer data\n", __FUNCTION__)); - goto exit; - } - dhd_dbg_trace_evnt_handler(dhdp, PKTDATA(dhdp->osh, pktbuf), - event_data, payload_hdr_length); - - return BCME_OK; - -exit: - return BCME_ERROR; -} -#endif /* PCIE_FULL_DONGLE */ -#endif /* SHOW_LOGTRACE */ - -#if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) - -/* To handle the TDLS event in the dhd_common.c - */ -int dhd_tdls_event_handler(dhd_pub_t *dhd_pub, wl_event_msg_t *event) -{ - int ret = BCME_OK; -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - ret = dhd_tdls_update_peer_info(dhd_pub, event); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - return ret; -} - -int dhd_free_tdls_peer_list(dhd_pub_t *dhd_pub) -{ - tdls_peer_node_t *cur = NULL, *prev = NULL; - if (!dhd_pub) - return BCME_ERROR; - cur = dhd_pub->peer_tbl.node; - - if ((dhd_pub->peer_tbl.node == NULL) && !dhd_pub->peer_tbl.tdls_peer_count) - return BCME_ERROR; - - while (cur != NULL) { - prev = cur; - cur = cur->next; - MFREE(dhd_pub->osh, prev, sizeof(tdls_peer_node_t)); - } - dhd_pub->peer_tbl.tdls_peer_count = 0; - dhd_pub->peer_tbl.node = NULL; - return BCME_OK; -} -#endif /* #if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) */ - -#ifdef DUMP_IOCTL_IOV_LIST -void -dhd_iov_li_append(dhd_pub_t *dhd, dll_t *list_head, dll_t *node) -{ - dll_t *item; - dhd_iov_li_t *iov_li; - dhd->dump_iovlist_len++; - - if (dhd->dump_iovlist_len == IOV_LIST_MAX_LEN+1) { - item = dll_head_p(list_head); - iov_li = (dhd_iov_li_t *)CONTAINEROF(item, dhd_iov_li_t, list); - dll_delete(item); - MFREE(dhd->osh, iov_li, sizeof(*iov_li)); - dhd->dump_iovlist_len--; - } - dll_append(list_head, node); -} - -void -dhd_iov_li_print(dll_t *list_head) -{ - dhd_iov_li_t *iov_li; - dll_t *item, *next; - uint8 index = 0; - for (item = dll_head_p(list_head); !dll_end(list_head, item); item = next) { - next = dll_next_p(item); - iov_li = (dhd_iov_li_t *)CONTAINEROF(item, dhd_iov_li_t, list); - index++; - DHD_ERROR(("%d:cmd_name = %s, cmd = %d.\n", index, iov_li->buff, iov_li->cmd)); - } -} - -void -dhd_iov_li_delete(dhd_pub_t *dhd, dll_t *list_head) -{ - dll_t *item; - dhd_iov_li_t *iov_li; - while (!(dll_empty(list_head))) { - item = dll_head_p(list_head); - iov_li = (dhd_iov_li_t *)CONTAINEROF(item, dhd_iov_li_t, list); - dll_delete(item); - MFREE(dhd->osh, iov_li, sizeof(*iov_li)); - } -} -#endif /* DUMP_IOCTL_IOV_LIST */
diff --git a/bcmdhd.1.579.77.41.x/dhd_config.c b/bcmdhd.1.579.77.41.x/dhd_config.c deleted file mode 100644 index 9ba60e2..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_config.c +++ /dev/null
@@ -1,3330 +0,0 @@ -/* - * Wifi configuration file operation - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_config.c 591129 2015-10-07 05:22:14Z $ - */ - -#include <typedefs.h> -#include <osl.h> - -#include <bcmutils.h> -#include <hndsoc.h> -#include <bcmsdbus.h> -#if defined(HW_OOB) || defined(FORCE_WOWLAN) -#include <bcmdefs.h> -#include <bcmsdh.h> -#include <sdio.h> -#include <sbchipc.h> -#endif - -#include <dhd_config.h> -#include <dhd_dbg.h> - -/* message levels */ -#define CONFIG_ERROR_LEVEL 0x0001 -#define CONFIG_TRACE_LEVEL 0x0002 -#define CONFIG_INFO_LEVEL 0x0004 - -uint config_msg_level = CONFIG_ERROR_LEVEL; -#define PRINTCONF(fmt, args...) printk(KERN_CONT fmt, ##args) -#define CONFIG_ERROR(x) \ - do { \ - if (config_msg_level & CONFIG_ERROR_LEVEL) { \ - printk(KERN_ERR "[DHD] E/CONFIG) "); \ - PRINTCONF x; \ - } \ - } while (0) -#define CONFIG_TRACE(x) \ - do { \ - if (config_msg_level & CONFIG_TRACE_LEVEL) { \ - printk(KERN_ERR "[DHD] T/CONFIG) "); \ - PRINTCONF x; \ - } \ - } while (0) -#define CONFIG_INFO(x) \ - do { \ - if (config_msg_level & CONFIG_INFO_LEVEL) { \ - printk(KERN_ERR "[DHD] I/CONFIG) "); \ - PRINTCONF x; \ - } \ - } while (0) - -#define MAXSZ_BUF 1000 -#define MAXSZ_CONFIG 4096 - -#define htod32(i) i -#define htod16(i) i -#define dtoh32(i) i -#define dtoh16(i) i -#define htodchanspec(i) i -#define dtohchanspec(i) i - -typedef struct cihp_name_map_t { - uint chip; - uint chiprev; - uint ag_type; - bool clm; - char *chip_name; - char *module_name; -} cihp_name_map_t; - -/* Map of WLC_E events to connection failure strings */ -#define DONT_CARE 9999 -const cihp_name_map_t chip_name_map [] = { - /* ChipID Chiprev AG CLM ChipName ModuleName */ -#ifdef BCMSDIO - {BCM43362_CHIP_ID, 0, DONT_CARE, FALSE, "bcm40181a0", ""}, - {BCM43362_CHIP_ID, 1, DONT_CARE, FALSE, "bcm40181a2", ""}, - {BCM4330_CHIP_ID, 4, FW_TYPE_G, FALSE, "bcm40183b2", ""}, - {BCM4330_CHIP_ID, 4, FW_TYPE_AG, FALSE, "bcm40183b2_ag", ""}, - {BCM43430_CHIP_ID, 0, DONT_CARE, FALSE, "bcm43438a0", ""}, - {BCM43430_CHIP_ID, 1, DONT_CARE, FALSE, "bcm43438a1", ""}, - {BCM43430_CHIP_ID, 2, DONT_CARE, FALSE, "bcm43436b0", ""}, - {BCM43012_CHIP_ID, 1, DONT_CARE, TRUE, "bcm43013b0", ""}, - {BCM43012_CHIP_ID, 2, DONT_CARE, TRUE, "bcm43013c1", ""}, - {BCM4334_CHIP_ID, 3, DONT_CARE, FALSE, "bcm4334b1_ag", ""}, - {BCM43340_CHIP_ID, 2, DONT_CARE, FALSE, "bcm43341b0_ag", ""}, - {BCM43341_CHIP_ID, 2, DONT_CARE, FALSE, "bcm43341b0_ag", ""}, - {BCM4324_CHIP_ID, 5, DONT_CARE, FALSE, "bcm43241b4_ag", ""}, - {BCM4335_CHIP_ID, 2, DONT_CARE, FALSE, "bcm4339a0_ag", ""}, - {BCM4339_CHIP_ID, 1, DONT_CARE, FALSE, "bcm4339a0_ag", ""}, - {BCM4345_CHIP_ID, 6, DONT_CARE, FALSE, "bcm43455c0_ag", ""}, - {BCM43454_CHIP_ID, 6, DONT_CARE, FALSE, "bcm43455c0_ag", ""}, - {BCM4345_CHIP_ID, 9, DONT_CARE, FALSE, "bcm43456c5_ag", ""}, - {BCM43454_CHIP_ID, 9, DONT_CARE, FALSE, "bcm43456c5_ag", ""}, - {BCM4354_CHIP_ID, 1, DONT_CARE, FALSE, "bcm4354a1_ag", ""}, - {BCM4354_CHIP_ID, 2, DONT_CARE, FALSE, "bcm4356a2_ag", ""}, - {BCM4356_CHIP_ID, 2, DONT_CARE, FALSE, "bcm4356a2_ag", ""}, - {BCM4371_CHIP_ID, 2, DONT_CARE, FALSE, "bcm4356a2_ag", ""}, - {BCM43569_CHIP_ID, 3, DONT_CARE, FALSE, "bcm4358a3_ag", ""}, - {BCM4359_CHIP_ID, 5, DONT_CARE, FALSE, "bcm4359b1_ag", ""}, - {BCM4359_CHIP_ID, 9, DONT_CARE, FALSE, "bcm4359c0_ag", ""}, - {BCM4362_CHIP_ID, 0, DONT_CARE, TRUE, "bcm43752a0_ag", ""}, -#endif -#ifdef BCMPCIE - {BCM4354_CHIP_ID, 2, DONT_CARE, FALSE, "bcm4356a2_pcie_ag", ""}, - {BCM4356_CHIP_ID, 2, DONT_CARE, FALSE, "bcm4356a2_pcie_ag", ""}, - {BCM4359_CHIP_ID, 9, DONT_CARE, FALSE, "bcm4359c0_pcie_ag", ""}, - {BCM4362_CHIP_ID, 0, DONT_CARE, TRUE, "bcm43752a0_pcie_ag", ""}, -#endif -#ifdef BCMDBUS - {BCM43143_CHIP_ID, 2, DONT_CARE, FALSE, "bcm43143b0", ""}, - {BCM43242_CHIP_ID, 1, DONT_CARE, FALSE, "bcm43242a1_ag", ""}, - {BCM43569_CHIP_ID, 2, DONT_CARE, FALSE, "bcm4358u_ag", ""}, -#endif -}; - -#ifdef BCMSDIO -void -dhd_conf_free_mac_list(wl_mac_list_ctrl_t *mac_list) -{ - int i; - - CONFIG_TRACE(("%s called\n", __FUNCTION__)); - if (mac_list->m_mac_list_head) { - for (i=0; i<mac_list->count; i++) { - if (mac_list->m_mac_list_head[i].mac) { - CONFIG_TRACE(("%s Free mac %p\n", __FUNCTION__, mac_list->m_mac_list_head[i].mac)); - kfree(mac_list->m_mac_list_head[i].mac); - } - } - CONFIG_TRACE(("%s Free m_mac_list_head %p\n", __FUNCTION__, mac_list->m_mac_list_head)); - kfree(mac_list->m_mac_list_head); - } - mac_list->count = 0; -} - -void -dhd_conf_free_chip_nv_path_list(wl_chip_nv_path_list_ctrl_t *chip_nv_list) -{ - CONFIG_TRACE(("%s called\n", __FUNCTION__)); - - if (chip_nv_list->m_chip_nv_path_head) { - CONFIG_TRACE(("%s Free %p\n", __FUNCTION__, chip_nv_list->m_chip_nv_path_head)); - kfree(chip_nv_list->m_chip_nv_path_head); - } - chip_nv_list->count = 0; -} - -#if defined(HW_OOB) || defined(FORCE_WOWLAN) -void -dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, uint chip) -{ - uint32 gpiocontrol, addr; - - if (CHIPID(chip) == BCM43362_CHIP_ID) { - CONFIG_INFO(("%s: Enable HW OOB for 43362\n", __FUNCTION__)); - addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, gpiocontrol); - gpiocontrol = bcmsdh_reg_read(sdh, addr, 4); - gpiocontrol |= 0x2; - bcmsdh_reg_write(sdh, addr, 4, gpiocontrol); - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10005, 0xf, NULL); - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10006, 0x0, NULL); - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10007, 0x2, NULL); - } -} -#endif - -#define SBSDIO_CIS_SIZE_LIMIT 0x200 -#define F0_BLOCK_SIZE 32 -int -dhd_conf_set_blksize(bcmsdh_info_t *sdh) -{ - int err = 0; - uint fn, numfn; - int32 blksize = 0, cur_blksize = 0; - uint8 cisd; - - numfn = bcmsdh_query_iofnum(sdh); - - for (fn = 0; fn <= numfn; fn++) { - if (!fn) - blksize = F0_BLOCK_SIZE; - else { - bcmsdh_cisaddr_read(sdh, fn, &cisd, 24); - blksize = cisd; - bcmsdh_cisaddr_read(sdh, fn, &cisd, 25); - blksize |= cisd << 8; - } -#ifdef CUSTOM_SDIO_F2_BLKSIZE - if (fn == 2 && blksize > CUSTOM_SDIO_F2_BLKSIZE) { - blksize = CUSTOM_SDIO_F2_BLKSIZE; - } -#endif - bcmsdh_iovar_op(sdh, "sd_blocksize", &fn, sizeof(int32), - &cur_blksize, sizeof(int32), FALSE); - if (cur_blksize != blksize) { - CONFIG_INFO(("%s: fn=%d, blksize=%d, cur_blksize=%d\n", __FUNCTION__, - fn, blksize, cur_blksize)); - blksize |= (fn<<16); - if (bcmsdh_iovar_op(sdh, "sd_blocksize", NULL, 0, &blksize, - sizeof(blksize), TRUE) != BCME_OK) { - CONFIG_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize")); - err = -1; - } - } - } - - return err; -} - -int -dhd_conf_get_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, uint8 *mac) -{ - int i, err = -1; - uint8 *ptr = 0; - unsigned char tpl_code, tpl_link='\0'; - uint8 header[3] = {0x80, 0x07, 0x19}; - uint8 *cis; - - if (!(cis = MALLOC(dhd->osh, SBSDIO_CIS_SIZE_LIMIT))) { - CONFIG_ERROR(("%s: cis malloc failed\n", __FUNCTION__)); - return err; - } - bzero(cis, SBSDIO_CIS_SIZE_LIMIT); - - if ((err = bcmsdh_cis_read(sdh, 0, cis, SBSDIO_CIS_SIZE_LIMIT))) { - CONFIG_ERROR(("%s: cis read err %d\n", __FUNCTION__, err)); - MFREE(dhd->osh, cis, SBSDIO_CIS_SIZE_LIMIT); - return err; - } - err = -1; // reset err; - ptr = cis; - do { - /* 0xff means we're done */ - tpl_code = *ptr; - ptr++; - if (tpl_code == 0xff) - break; - - /* null entries have no link field or data */ - if (tpl_code == 0x00) - continue; - - tpl_link = *ptr; - ptr++; - /* a size of 0xff also means we're done */ - if (tpl_link == 0xff) - break; - if (config_msg_level & CONFIG_TRACE_LEVEL) { - CONFIG_INFO(("%s: tpl_code=0x%02x, tpl_link=0x%02x, tag=0x%02x\n", - __FUNCTION__, tpl_code, tpl_link, *ptr)); - CONFIG_INFO(("%s: value:", __FUNCTION__)); - for (i=0; i<tpl_link-1; i++) { - CONFIG_INFO(("%02x ", ptr[i+1])); - if ((i+1) % 16 == 0) - CONFIG_INFO(("\n")); - } - CONFIG_INFO(("\n")); - } - - if (tpl_code == 0x80 && tpl_link == 0x07 && *ptr == 0x19) - break; - - ptr += tpl_link; - } while (1); - - if (tpl_code == 0x80 && tpl_link == 0x07 && *ptr == 0x19) { - /* Normal OTP */ - memcpy(mac, ptr+1, 6); - err = 0; - } else { - ptr = cis; - /* Special OTP */ - if (bcmsdh_reg_read(sdh, SI_ENUM_BASE, 4) == 0x16044330) { - for (i=0; i<SBSDIO_CIS_SIZE_LIMIT; i++) { - if (!memcmp(header, ptr, 3)) { - memcpy(mac, ptr+3, 6); - err = 0; - break; - } - ptr++; - } - } - } - - ASSERT(cis); - MFREE(dhd->osh, cis, SBSDIO_CIS_SIZE_LIMIT); - - return err; -} - -void -dhd_conf_set_fw_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *fw_path) -{ - int i, j; - uint8 mac[6]={0}; - int fw_num=0, mac_num=0; - uint32 oui, nic; - wl_mac_list_t *mac_list; - wl_mac_range_t *mac_range; - int fw_type, fw_type_new; - char *name_ptr; - - mac_list = dhd->conf->fw_by_mac.m_mac_list_head; - fw_num = dhd->conf->fw_by_mac.count; - if (!mac_list || !fw_num) - return; - - if (dhd_conf_get_mac(dhd, sdh, mac)) { - CONFIG_ERROR(("%s: Can not read MAC address\n", __FUNCTION__)); - return; - } - oui = (mac[0] << 16) | (mac[1] << 8) | (mac[2]); - nic = (mac[3] << 16) | (mac[4] << 8) | (mac[5]); - - /* find out the last '/' */ - i = strlen(fw_path); - while (i > 0) { - if (fw_path[i] == '/') { - i++; - break; - } - i--; - } - name_ptr = &fw_path[i]; - - if (strstr(name_ptr, "_apsta")) - fw_type = FW_TYPE_APSTA; - else if (strstr(name_ptr, "_p2p")) - fw_type = FW_TYPE_P2P; - else if (strstr(name_ptr, "_mesh")) - fw_type = FW_TYPE_MESH; - else if (strstr(name_ptr, "_es")) - fw_type = FW_TYPE_ES; - else if (strstr(name_ptr, "_mfg")) - fw_type = FW_TYPE_MFG; - else - fw_type = FW_TYPE_STA; - - for (i=0; i<fw_num; i++) { - mac_num = mac_list[i].count; - mac_range = mac_list[i].mac; - if (strstr(mac_list[i].name, "_apsta")) - fw_type_new = FW_TYPE_APSTA; - else if (strstr(mac_list[i].name, "_p2p")) - fw_type_new = FW_TYPE_P2P; - else if (strstr(mac_list[i].name, "_mesh")) - fw_type_new = FW_TYPE_MESH; - else if (strstr(mac_list[i].name, "_es")) - fw_type_new = FW_TYPE_ES; - else if (strstr(mac_list[i].name, "_mfg")) - fw_type_new = FW_TYPE_MFG; - else - fw_type_new = FW_TYPE_STA; - if (fw_type != fw_type_new) { - CONFIG_INFO(("%s: fw_typ=%d != fw_type_new=%d\n", __FUNCTION__, fw_type, fw_type_new)); - continue; - } - for (j=0; j<mac_num; j++) { - if (oui == mac_range[j].oui) { - if (nic >= mac_range[j].nic_start && nic <= mac_range[j].nic_end) { - strcpy(name_ptr, mac_list[i].name); - CONFIG_INFO(("%s: matched oui=0x%06X, nic=0x%06X\n", - __FUNCTION__, oui, nic)); - CONFIG_INFO(("%s: fw_path=%s\n", __FUNCTION__, fw_path)); - return; - } - } - } - } -} - -void -dhd_conf_set_nv_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *nv_path) -{ - int i, j; - uint8 mac[6]={0}; - int nv_num=0, mac_num=0; - uint32 oui, nic; - wl_mac_list_t *mac_list; - wl_mac_range_t *mac_range; - char *pnv_name; - - mac_list = dhd->conf->nv_by_mac.m_mac_list_head; - nv_num = dhd->conf->nv_by_mac.count; - if (!mac_list || !nv_num) - return; - - if (dhd_conf_get_mac(dhd, sdh, mac)) { - CONFIG_ERROR(("%s: Can not read MAC address\n", __FUNCTION__)); - return; - } - oui = (mac[0] << 16) | (mac[1] << 8) | (mac[2]); - nic = (mac[3] << 16) | (mac[4] << 8) | (mac[5]); - - /* find out the last '/' */ - i = strlen(nv_path); - while (i > 0) { - if (nv_path[i] == '/') break; - i--; - } - pnv_name = &nv_path[i+1]; - - for (i=0; i<nv_num; i++) { - mac_num = mac_list[i].count; - mac_range = mac_list[i].mac; - for (j=0; j<mac_num; j++) { - if (oui == mac_range[j].oui) { - if (nic >= mac_range[j].nic_start && nic <= mac_range[j].nic_end) { - strcpy(pnv_name, mac_list[i].name); - CONFIG_INFO(("%s: matched oui=0x%06X, nic=0x%06X\n", - __FUNCTION__, oui, nic)); - CONFIG_INFO(("%s: nv_path=%s\n", __FUNCTION__, nv_path)); - return; - } - } - } - } -} -#endif - -void -dhd_conf_free_country_list(conf_country_list_t *country_list) -{ - int i; - - CONFIG_TRACE(("%s called\n", __FUNCTION__)); - for (i=0; i<country_list->count; i++) { - if (country_list->cspec[i]) { - CONFIG_TRACE(("%s Free cspec %p\n", __FUNCTION__, country_list->cspec[i])); - kfree(country_list->cspec[i]); - } - } - country_list->count = 0; -} - -void -dhd_conf_set_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path) -{ - int fw_type, ag_type; - uint chip, chiprev; - int i; - char *name_ptr; - - chip = dhd->conf->chip; - chiprev = dhd->conf->chiprev; - - if (fw_path[0] == '\0') { -#ifdef CONFIG_BCMDHD_FW_PATH - bcm_strncpy_s(fw_path, MOD_PARAM_PATHLEN-1, CONFIG_BCMDHD_FW_PATH, MOD_PARAM_PATHLEN-1); - if (fw_path[0] == '\0') -#endif - { - CONFIG_ERROR(("firmware path is null\n")); - return; - } - } -#ifndef FW_PATH_AUTO_SELECT - return; -#endif - - /* find out the last '/' */ - i = strlen(fw_path); - while (i > 0) { - if (fw_path[i] == '/') { - i++; - break; - } - i--; - } - name_ptr = &fw_path[i]; -#ifdef BAND_AG - ag_type = FW_TYPE_AG; -#else - ag_type = strstr(name_ptr, "_ag") ? FW_TYPE_AG : FW_TYPE_G; -#endif - if (strstr(name_ptr, "_apsta")) - fw_type = FW_TYPE_APSTA; - else if (strstr(name_ptr, "_p2p")) - fw_type = FW_TYPE_P2P; - else if (strstr(name_ptr, "_mesh")) - fw_type = FW_TYPE_MESH; - else if (strstr(name_ptr, "_es")) - fw_type = FW_TYPE_ES; - else if (strstr(name_ptr, "_mfg")) - fw_type = FW_TYPE_MFG; - else - fw_type = FW_TYPE_STA; - - for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) { - const cihp_name_map_t* row = &chip_name_map[i]; - if (row->chip == chip && row->chiprev == chiprev && - (row->ag_type == ag_type || row->ag_type == DONT_CARE)) { - strcpy(name_ptr, "fw_"); - strcat(fw_path, row->chip_name); - if (fw_type == FW_TYPE_APSTA) - strcat(fw_path, "_apsta.bin"); - else if (fw_type == FW_TYPE_P2P) - strcat(fw_path, "_p2p.bin"); - else if (fw_type == FW_TYPE_MESH) - strcat(fw_path, "_mesh.bin"); - else if (fw_type == FW_TYPE_ES) - strcat(fw_path, "_es.bin"); - else if (fw_type == FW_TYPE_MFG) - strcat(fw_path, "_mfg.bin"); - else - strcat(fw_path, ".bin"); - } - } - - dhd->conf->fw_type = fw_type; - - CONFIG_TRACE(("%s: firmware_path=%s\n", __FUNCTION__, fw_path)); -} - -void -dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path) -{ - uint chip, chiprev; - int i; - char *name_ptr; - - chip = dhd->conf->chip; - chiprev = dhd->conf->chiprev; - CONFIG_INFO(("Check clm_path %s\n",clm_path)); - if (clm_path[0] == '\0') { - CONFIG_ERROR(("clm path is null\n")); - return; - } - - /* find out the last '/' */ - i = strlen(clm_path); - while (i > 0) { - if (clm_path[i] == '/') { - i++; - break; - } - i--; - } - name_ptr = &clm_path[i]; - - for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) { - const cihp_name_map_t* row = &chip_name_map[i]; - if (row->chip == chip && row->chiprev == chiprev && row->clm) { - strcpy(name_ptr, "clm_"); - strcat(clm_path, row->chip_name); - strcat(clm_path, ".blob"); - } - } - - CONFIG_TRACE(("%s: clm_path=%s\n", __FUNCTION__, clm_path)); -} - -void -dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path) -{ - uint chip, chiprev; - int i; - char *name_ptr; - - chip = dhd->conf->chip; - chiprev = dhd->conf->chiprev; - - if (nv_path[0] == '\0') { -#ifdef CONFIG_BCMDHD_NVRAM_PATH - bcm_strncpy_s(nv_path, MOD_PARAM_PATHLEN-1, CONFIG_BCMDHD_NVRAM_PATH, MOD_PARAM_PATHLEN-1); - if (nv_path[0] == '\0') -#endif - { - CONFIG_ERROR(("nvram path is null\n")); - return; - } - } - - /* find out the last '/' */ - i = strlen(nv_path); - while (i > 0) { - if (nv_path[i] == '/') { - i++; - break; - } - i--; - } - name_ptr = &nv_path[i]; - - for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) { - const cihp_name_map_t* row = &chip_name_map[i]; - if (row->chip == chip && row->chiprev == chiprev) { - strcpy(name_ptr, "nvram_"); - strcat(nv_path, row->chip_name); - strcat(nv_path, ".txt"); - } - } - - CONFIG_TRACE(("%s: nvram_path=%s\n", __FUNCTION__, nv_path)); -} - -void -dhd_conf_set_path(dhd_pub_t *dhd, char *dst_name, char *dst_path, char *src_path) -{ - int i; - - if (src_path[0] == '\0') { - CONFIG_ERROR(("src_path is null\n")); - return; - } else - strcpy(dst_path, src_path); - - /* find out the last '/' */ - i = strlen(dst_path); - while (i > 0) { - if (dst_path[i] == '/') { - i++; - break; - } - i--; - } - strcpy(&dst_path[i], dst_name); - - CONFIG_TRACE(("%s: dst_path=%s\n", __FUNCTION__, dst_path)); -} - -#ifdef CONFIG_PATH_AUTO_SELECT -void -dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path) -{ - uint chip, chiprev; - int i; - char *name_ptr; - - chip = dhd->conf->chip; - chiprev = dhd->conf->chiprev; - - if (conf_path[0] == '\0') { - CONFIG_ERROR(("config path is null\n")); - return; - } - - /* find out the last '/' */ - i = strlen(conf_path); - while (i > 0) { - if (conf_path[i] == '/') { - i++; - break; - } - i--; - } - name_ptr = &conf_path[i]; - - for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) { - const cihp_name_map_t* row = &chip_name_map[i]; - if (row->chip == chip && row->chiprev == chiprev) { - strcpy(name_ptr, "config_"); - strcat(conf_path, row->chip_name); - strcat(conf_path, ".txt"); - } - } - - CONFIG_TRACE(("%s: config_path=%s\n", __FUNCTION__, conf_path)); -} - -void -dhd_conf_set_reg_name_by_chip(dhd_pub_t *dhd, char *reg_path) -{ - uint chip, chiprev; - int i; - char *name_ptr; - - chip = dhd->conf->chip; - chiprev = dhd->conf->chiprev; - - if (reg_path[0] == '\0') { - CONFIG_ERROR(("reg path is null\n")); - return; - } - - /* find out the last '/' */ - i = strlen(reg_path); - while (i > 0) { - if (reg_path[i] == '/') { - i++; - break; - } - i--; - } - name_ptr = ®_path[i]; - - for (i = 0; i < sizeof(chip_name_map)/sizeof(chip_name_map[0]); i++) { - const cihp_name_map_t* row = &chip_name_map[i]; - if (row->chip == chip && row->chiprev == chiprev) { - strcpy(name_ptr, "reg_"); - strcat(reg_path, row->chip_name); - strcat(reg_path, ".txt"); - } - } - - CONFIG_TRACE(("%s: reg_path=%s\n", __FUNCTION__, reg_path)); -} -#endif - -int -dhd_conf_set_intiovar(dhd_pub_t *dhd, uint cmd, char *name, int val, - int def, bool down) -{ - int ret = -1; - char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ - - if (val >= def) { - if (down) { - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0)) < 0) - CONFIG_ERROR(("%s: WLC_DOWN setting failed %d\n", __FUNCTION__, ret)); - } - if (cmd == WLC_SET_VAR) { - CONFIG_TRACE(("%s: set %s %d\n", __FUNCTION__, name, val)); - bcm_mkiovar(name, (char *)&val, sizeof(val), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) - CONFIG_ERROR(("%s: %s setting failed %d\n", __FUNCTION__, name, ret)); - } else { - CONFIG_TRACE(("%s: set %s %d %d\n", __FUNCTION__, name, cmd, val)); - if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, &val, sizeof(val), TRUE, 0)) < 0) - CONFIG_ERROR(("%s: %s setting failed %d\n", __FUNCTION__, name, ret)); - } - } - - return ret; -} - -int -dhd_conf_set_bufiovar(dhd_pub_t *dhd, uint cmd, char *name, char *buf, - int len, bool down) -{ - char iovbuf[WLC_IOCTL_SMLEN]; - int ret = -1; - - if (down) { - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, NULL, 0, TRUE, 0)) < 0) - CONFIG_ERROR(("%s: WLC_DOWN setting failed %d\n", __FUNCTION__, ret)); - } - - if (cmd == WLC_SET_VAR) { - bcm_mkiovar(name, buf, len, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) - CONFIG_ERROR(("%s: %s setting failed %d\n", __FUNCTION__, name, ret)); - } else { - if ((ret = dhd_wl_ioctl_cmd(dhd, cmd, buf, len, TRUE, 0)) < 0) - CONFIG_ERROR(("%s: %s setting failed %d\n", __FUNCTION__, name, ret)); - } - - return ret; -} - -int -dhd_conf_get_iovar(dhd_pub_t *dhd, int cmd, char *name, char *buf, int len, int ifidx) -{ - char iovbuf[WLC_IOCTL_SMLEN]; - int ret = -1; - - if (cmd == WLC_GET_VAR) { - if (bcm_mkiovar(name, NULL, 0, iovbuf, sizeof(iovbuf))) { - ret = dhd_wl_ioctl_cmd(dhd, cmd, iovbuf, sizeof(iovbuf), FALSE, ifidx); - if (!ret) { - memcpy(buf, iovbuf, len); - } else { - CONFIG_ERROR(("%s: get iovar %s failed %d\n", __FUNCTION__, name, ret)); - } - } else { - CONFIG_ERROR(("%s: mkiovar %s failed\n", __FUNCTION__, name)); - } - } else { - ret = dhd_wl_ioctl_cmd(dhd, cmd, buf, len, FALSE, 0); - if (ret < 0) - CONFIG_ERROR(("%s: get iovar %s failed %d\n", __FUNCTION__, name, ret)); - } - - return ret; -} - -uint -dhd_conf_get_band(dhd_pub_t *dhd) -{ - int band = -1; - - if (dhd && dhd->conf) - band = dhd->conf->band; - else - CONFIG_ERROR(("%s: dhd or conf is NULL\n", __FUNCTION__)); - - return band; -} - -int -dhd_conf_get_country(dhd_pub_t *dhd, wl_country_t *cspec) -{ - int bcmerror = -1; - - memset(cspec, 0, sizeof(wl_country_t)); - bcm_mkiovar("country", NULL, 0, (char*)cspec, sizeof(wl_country_t)); - if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cspec, sizeof(wl_country_t), FALSE, 0)) < 0) - CONFIG_ERROR(("%s: country code getting failed %d\n", __FUNCTION__, bcmerror)); - - return bcmerror; -} - -int -dhd_conf_map_country_list(dhd_pub_t *dhd, wl_country_t *cspec, int nodfs, int location) -{ - int bcmerror = -1, i; - struct dhd_conf *conf = dhd->conf; - int regrev = -1; - conf_country_list_t *country_list; - - if ((nodfs > 0 || dhd->op_mode & DHD_FLAG_HOSTAP_MODE) && - conf->country_list_nodfs.count > 0) { - country_list = &conf->country_list_nodfs; - } else { - country_list = &conf->country_list; - } - - // set default location rev - if (conf->default_reg_location == REG_LOCATION_INDOOR) - regrev = conf->indoor_regrev; - else if (conf->default_reg_location == REG_LOCATION_OUTDOOR) - regrev = conf->outdoor_regrev; - - // change to target location rev - if (location == REG_LOCATION_INDOOR) { - regrev = conf->indoor_regrev; - } else if (location == REG_LOCATION_OUTDOOR) { - regrev = conf->outdoor_regrev; - } - - for (i = 0; i < country_list->count; i++) { - if (!strncmp(cspec->country_abbrev, country_list->cspec[i]->country_abbrev, 2)) { - if (location != REG_LOCATION_UNKNOWN && - regrev != country_list->cspec[i]->rev) - continue; - - if (location == REG_LOCATION_UNKNOWN && - regrev >= 0 && - regrev != country_list->cspec[i]->rev) - continue; - - memcpy(cspec->ccode, country_list->cspec[i]->ccode, WLC_CNTRY_BUF_SZ); - cspec->rev = country_list->cspec[i]->rev; - CONFIG_INFO(("%s: %s/%d\n", __FUNCTION__, cspec->ccode, cspec->rev)); - return 0; - } - } - - return bcmerror; -} - -int -dhd_conf_set_country(dhd_pub_t *dhd, wl_country_t *cspec) -{ - int bcmerror = -1; - - memset(&dhd->dhd_cspec, 0, sizeof(wl_country_t)); - - CONFIG_INFO(("%s: set country %s, revision %d\n", __FUNCTION__, cspec->ccode, cspec->rev)); - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "country", (char *)cspec, sizeof(wl_country_t), FALSE); - dhd_conf_get_country(dhd, cspec); - CONFIG_INFO(("Country code: %s (%s/%d)\n", cspec->country_abbrev, cspec->ccode, cspec->rev)); - - return bcmerror; -} - -int -dhd_conf_fix_country(dhd_pub_t *dhd) -{ - int bcmerror = -1; - uint band; - wl_uint32_list_t *list; - u8 valid_chan_list[sizeof(u32)*(WL_NUMCHANNELS + 1)]; - wl_country_t cspec; - - if (!(dhd && dhd->conf)) { - return bcmerror; - } - - memset(valid_chan_list, 0, sizeof(valid_chan_list)); - list = (wl_uint32_list_t *)(void *) valid_chan_list; - list->count = htod32(WL_NUMCHANNELS); - if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VALID_CHANNELS, valid_chan_list, sizeof(valid_chan_list), FALSE, 0)) < 0) { - CONFIG_ERROR(("%s: get channels failed with %d\n", __FUNCTION__, bcmerror)); - } - - band = dhd_conf_get_band(dhd); - - if (bcmerror || ((band==WLC_BAND_AUTO || band==WLC_BAND_2G) && - dtoh32(list->count)<11)) { - CONFIG_ERROR(("%s: bcmerror=%d, # of channels %d\n", - __FUNCTION__, bcmerror, dtoh32(list->count))); - dhd_conf_map_country_list(dhd, &dhd->conf->cspec, 0, -1); - if ((bcmerror = dhd_conf_set_country(dhd, &dhd->conf->cspec)) < 0) { - strcpy(cspec.country_abbrev, "US"); - cspec.rev = 0; - strcpy(cspec.ccode, "US"); - dhd_conf_map_country_list(dhd, &cspec, 0, -1); - dhd_conf_set_country(dhd, &cspec); - } - } - - return bcmerror; -} - -bool -dhd_conf_match_channel(dhd_pub_t *dhd, uint32 channel) -{ - int i; - bool match = false; - - if (dhd && dhd->conf) { - if (dhd->conf->channels.count == 0) - return true; - for (i=0; i<dhd->conf->channels.count; i++) { - if (channel == dhd->conf->channels.channel[i]) - match = true; - } - } else { - match = true; - CONFIG_ERROR(("%s: dhd or conf is NULL\n", __FUNCTION__)); - } - - return match; -} - -int -dhd_conf_set_roam(dhd_pub_t *dhd) -{ - int bcmerror = -1; - struct dhd_conf *conf = dhd->conf; - - dhd_roam_disable = conf->roam_off; - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "roam_off", dhd->conf->roam_off, 0, FALSE); - - if (!conf->roam_off || !conf->roam_off_suspend) { - CONFIG_INFO(("%s: set roam_trigger %d\n", __FUNCTION__, conf->roam_trigger[0])); - dhd_conf_set_bufiovar(dhd, WLC_SET_ROAM_TRIGGER, "WLC_SET_ROAM_TRIGGER", - (char *)conf->roam_trigger, sizeof(conf->roam_trigger), FALSE); - - CONFIG_INFO(("%s: set roam_scan_period %d\n", __FUNCTION__, conf->roam_scan_period[0])); - dhd_conf_set_bufiovar(dhd, WLC_SET_ROAM_SCAN_PERIOD, "WLC_SET_ROAM_SCAN_PERIOD", - (char *)conf->roam_scan_period, sizeof(conf->roam_scan_period), FALSE); - - CONFIG_INFO(("%s: set roam_delta %d\n", __FUNCTION__, conf->roam_delta[0])); - dhd_conf_set_bufiovar(dhd, WLC_SET_ROAM_DELTA, "WLC_SET_ROAM_DELTA", - (char *)conf->roam_delta, sizeof(conf->roam_delta), FALSE); - - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "fullroamperiod", dhd->conf->fullroamperiod, 1, FALSE); - } - - return bcmerror; -} - -void -dhd_conf_set_bw_cap(dhd_pub_t *dhd) -{ - struct { - u32 band; - u32 bw_cap; - } param = {0, 0}; - - if (dhd->conf->bw_cap[0] >= 0) { - memset(¶m, 0, sizeof(param)); - param.band = WLC_BAND_2G; - param.bw_cap = (uint)dhd->conf->bw_cap[0]; - CONFIG_INFO(("%s: set bw_cap 2g 0x%x\n", __FUNCTION__, param.bw_cap)); - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "bw_cap", (char *)¶m, sizeof(param), TRUE); - } - - if (dhd->conf->bw_cap[1] >= 0) { - memset(¶m, 0, sizeof(param)); - param.band = WLC_BAND_5G; - param.bw_cap = (uint)dhd->conf->bw_cap[1]; - CONFIG_INFO(("%s: set bw_cap 5g 0x%x\n", __FUNCTION__, param.bw_cap)); - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "bw_cap", (char *)¶m, sizeof(param), TRUE); - } -} - -void -dhd_conf_get_wme(dhd_pub_t *dhd, int mode, edcf_acparam_t *acp) -{ - int bcmerror = -1; - char iovbuf[WLC_IOCTL_SMLEN]; - edcf_acparam_t *acparam; - - bzero(iovbuf, sizeof(iovbuf)); - - /* - * Get current acparams, using buf as an input buffer. - * Return data is array of 4 ACs of wme params. - */ - if (mode == 0) - bcm_mkiovar("wme_ac_sta", NULL, 0, iovbuf, sizeof(iovbuf)); - else - bcm_mkiovar("wme_ac_ap", NULL, 0, iovbuf, sizeof(iovbuf)); - if ((bcmerror = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) { - CONFIG_ERROR(("%s: wme_ac_sta getting failed %d\n", __FUNCTION__, bcmerror)); - return; - } - memcpy((char*)acp, iovbuf, sizeof(edcf_acparam_t)*AC_COUNT); - - acparam = &acp[AC_BK]; - CONFIG_TRACE(("%s: BK: aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n", - __FUNCTION__, - acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK, - acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT, - acparam->TXOP)); - acparam = &acp[AC_BE]; - CONFIG_TRACE(("%s: BE: aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n", - __FUNCTION__, - acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK, - acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT, - acparam->TXOP)); - acparam = &acp[AC_VI]; - CONFIG_TRACE(("%s: VI: aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n", - __FUNCTION__, - acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK, - acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT, - acparam->TXOP)); - acparam = &acp[AC_VO]; - CONFIG_TRACE(("%s: VO: aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n", - __FUNCTION__, - acparam->ACI, acparam->ACI&EDCF_AIFSN_MASK, - acparam->ECW&EDCF_ECWMIN_MASK, (acparam->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT, - acparam->TXOP)); - - return; -} - -void -dhd_conf_update_wme(dhd_pub_t *dhd, int mode, edcf_acparam_t *acparam_cur, int aci) -{ - int aifsn, ecwmin, ecwmax, txop; - edcf_acparam_t *acp; - struct dhd_conf *conf = dhd->conf; - wme_param_t *wme; - - if (mode == 0) - wme = &conf->wme_sta; - else - wme = &conf->wme_ap; - - /* Default value */ - aifsn = acparam_cur->ACI&EDCF_AIFSN_MASK; - ecwmin = acparam_cur->ECW&EDCF_ECWMIN_MASK; - ecwmax = (acparam_cur->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT; - txop = acparam_cur->TXOP; - - /* Modified value */ - if (wme->aifsn[aci] > 0) - aifsn = wme->aifsn[aci]; - if (wme->ecwmin[aci] > 0) - ecwmin = wme->ecwmin[aci]; - if (wme->ecwmax[aci] > 0) - ecwmax = wme->ecwmax[aci]; - if (wme->txop[aci] > 0) - txop = wme->txop[aci]; - - if (!(wme->aifsn[aci] || wme->ecwmin[aci] || - wme->ecwmax[aci] || wme->txop[aci])) - return; - - /* Update */ - acp = acparam_cur; - acp->ACI = (acp->ACI & ~EDCF_AIFSN_MASK) | (aifsn & EDCF_AIFSN_MASK); - acp->ECW = ((ecwmax << EDCF_ECWMAX_SHIFT) & EDCF_ECWMAX_MASK) | (acp->ECW & EDCF_ECWMIN_MASK); - acp->ECW = ((acp->ECW & EDCF_ECWMAX_MASK) | (ecwmin & EDCF_ECWMIN_MASK)); - acp->TXOP = txop; - - CONFIG_INFO(("%s: wme_ac %s aci %d aifsn %d ecwmin %d ecwmax %d txop 0x%x\n", - __FUNCTION__, mode?"ap":"sta", - acp->ACI, acp->ACI&EDCF_AIFSN_MASK, - acp->ECW&EDCF_ECWMIN_MASK, (acp->ECW&EDCF_ECWMAX_MASK)>>EDCF_ECWMAX_SHIFT, - acp->TXOP)); - - /* - * Now use buf as an output buffer. - * Put WME acparams after "wme_ac\0" in buf. - * NOTE: only one of the four ACs can be set at a time. - */ - if (mode == 0) - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "wme_ac_sta", (char *)acp, sizeof(edcf_acparam_t), FALSE); - else - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "wme_ac_ap", (char *)acp, sizeof(edcf_acparam_t), FALSE); - -} - -void -dhd_conf_set_wme(dhd_pub_t *dhd, int mode) -{ - edcf_acparam_t acparam_cur[AC_COUNT]; - - if (dhd && dhd->conf) { - if (!dhd->conf->force_wme_ac) { - CONFIG_TRACE(("%s: force_wme_ac is not enabled %d\n", - __FUNCTION__, dhd->conf->force_wme_ac)); - return; - } - - CONFIG_TRACE(("%s: Before change:\n", __FUNCTION__)); - dhd_conf_get_wme(dhd, mode, acparam_cur); - - dhd_conf_update_wme(dhd, mode, &acparam_cur[AC_BK], AC_BK); - dhd_conf_update_wme(dhd, mode, &acparam_cur[AC_BE], AC_BE); - dhd_conf_update_wme(dhd, mode, &acparam_cur[AC_VI], AC_VI); - dhd_conf_update_wme(dhd, mode, &acparam_cur[AC_VO], AC_VO); - - CONFIG_TRACE(("%s: After change:\n", __FUNCTION__)); - dhd_conf_get_wme(dhd, mode, acparam_cur); - } else { - CONFIG_ERROR(("%s: dhd or conf is NULL\n", __FUNCTION__)); - } - - return; -} - -void -dhd_conf_set_mchan_bw(dhd_pub_t *dhd, int p2p_mode, int miracast_mode) -{ - int i; - struct dhd_conf *conf = dhd->conf; - bool set = true; - - for (i=0; i<MCHAN_MAX_NUM; i++) { - set = true; - set &= (conf->mchan[i].bw >= 0); - set &= ((conf->mchan[i].p2p_mode == -1) | (conf->mchan[i].p2p_mode == p2p_mode)); - set &= ((conf->mchan[i].miracast_mode == -1) | (conf->mchan[i].miracast_mode == miracast_mode)); - if (set) { - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "mchan_bw", conf->mchan[i].bw, 0, FALSE); - } - } - - return; -} - -#ifdef PKT_FILTER_SUPPORT -void -dhd_conf_add_pkt_filter(dhd_pub_t *dhd) -{ - int i, j; - char str[16]; -#define MACS "%02x%02x%02x%02x%02x%02x" - - /* - * Filter in less pkt: ARP(0x0806, ID is 105), BRCM(0x886C), 802.1X(0x888E) - * 1) dhd_master_mode=1 - * 2) pkt_filter_del=100, 102, 103, 104, 105 - * 3) pkt_filter_add=131 0 0 12 0xFFFF 0x886C, 132 0 0 12 0xFFFF 0x888E - * 4) magic_pkt_filter_add=141 0 1 12 - */ - for(i=0; i<dhd->conf->pkt_filter_add.count; i++) { - dhd->pktfilter[i+dhd->pktfilter_count] = dhd->conf->pkt_filter_add.filter[i]; - CONFIG_INFO(("%s: %s\n", __FUNCTION__, dhd->pktfilter[i+dhd->pktfilter_count])); - } - dhd->pktfilter_count += i; - - if (dhd->conf->magic_pkt_filter_add) { - strcat(dhd->conf->magic_pkt_filter_add, " 0x"); - strcat(dhd->conf->magic_pkt_filter_add, "FFFFFFFFFFFF"); - for (j=0; j<16; j++) - strcat(dhd->conf->magic_pkt_filter_add, "FFFFFFFFFFFF"); - strcat(dhd->conf->magic_pkt_filter_add, " 0x"); - strcat(dhd->conf->magic_pkt_filter_add, "FFFFFFFFFFFF"); - sprintf(str, MACS, MAC2STRDBGFULL(dhd->mac.octet)); - for (j=0; j<16; j++) - strncat(dhd->conf->magic_pkt_filter_add, str, 12); - dhd->pktfilter[dhd->pktfilter_count] = dhd->conf->magic_pkt_filter_add; - dhd->pktfilter_count += 1; - } -} - -bool -dhd_conf_del_pkt_filter(dhd_pub_t *dhd, uint32 id) -{ - int i; - - if (dhd && dhd->conf) { - for (i=0; i<dhd->conf->pkt_filter_del.count; i++) { - if (id == dhd->conf->pkt_filter_del.id[i]) { - CONFIG_INFO(("%s: %d\n", __FUNCTION__, dhd->conf->pkt_filter_del.id[i])); - return true; - } - } - return false; - } - return false; -} - -void -dhd_conf_discard_pkt_filter(dhd_pub_t *dhd) -{ - dhd->pktfilter_count = 6; - dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = NULL; - dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF"; - dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = "102 0 0 0 0xFFFFFF 0x01005E"; - dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = "103 0 0 0 0xFFFF 0x3333"; - dhd->pktfilter[DHD_MDNS_FILTER_NUM] = NULL; - /* Do not enable ARP to pkt filter if dhd_master_mode is false.*/ - dhd->pktfilter[DHD_ARP_FILTER_NUM] = NULL; - - /* IPv4 broadcast address XXX.XXX.XXX.255 */ - dhd->pktfilter[dhd->pktfilter_count] = "110 0 0 12 0xFFFF00000000000000000000000000000000000000FF 0x080000000000000000000000000000000000000000FF"; - dhd->pktfilter_count++; - /* discard IPv4 multicast address 224.0.0.0/4 */ - dhd->pktfilter[dhd->pktfilter_count] = "111 0 0 12 0xFFFF00000000000000000000000000000000F0 0x080000000000000000000000000000000000E0"; - dhd->pktfilter_count++; - /* discard IPv6 multicast address FF00::/8 */ - dhd->pktfilter[dhd->pktfilter_count] = "112 0 0 12 0xFFFF000000000000000000000000000000000000000000000000FF 0x86DD000000000000000000000000000000000000000000000000FF"; - dhd->pktfilter_count++; - /* discard Netbios pkt */ - dhd->pktfilter[dhd->pktfilter_count] = "121 0 0 12 0xFFFF000000000000000000FF000000000000000000000000FFFF 0x0800000000000000000000110000000000000000000000000089"; - dhd->pktfilter_count++; - -} -#endif /* PKT_FILTER_SUPPORT */ - -int -dhd_conf_get_pm(dhd_pub_t *dhd) -{ - if (dhd && dhd->conf) { - if (dhd->conf->fw_type == FW_TYPE_MESH) - return PM_OFF; - else - return dhd->conf->pm; - } - return -1; -} - -#define AP_IN_SUSPEND 1 -#define AP_DOWN_IN_SUSPEND 2 -int -dhd_conf_get_ap_mode_in_suspend(dhd_pub_t *dhd) -{ - int mode = 0; - - /* returned ap_in_suspend value: - * 0: nothing - * 1: ap enabled in suspend - * 2: ap enabled, but down in suspend - */ - if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { - mode = dhd->conf->ap_in_suspend; - } - - return mode; -} - -int -dhd_conf_set_ap_in_suspend(dhd_pub_t *dhd, int suspend) -{ - int mode = 0; - uint wl_down = 1; - - mode = dhd_conf_get_ap_mode_in_suspend(dhd); - if (mode) - CONFIG_INFO(("%s: suspend %d, mode %d\n", __FUNCTION__, suspend, mode)); - if (suspend) { - if (mode == AP_IN_SUSPEND) { -#ifdef SUSPEND_EVENT - if (dhd->conf->suspend_eventmask_enable) { - char *eventmask = dhd->conf->suspend_eventmask; - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "event_msgs", eventmask, sizeof(eventmask), TRUE); - } -#endif - } else if (mode == AP_DOWN_IN_SUSPEND) - dhd_wl_ioctl_cmd(dhd, WLC_DOWN, (char *)&wl_down, sizeof(wl_down), TRUE, 0); - } else { - if (mode == AP_IN_SUSPEND) { -#ifdef SUSPEND_EVENT - if (dhd->conf->suspend_eventmask_enable) { - char *eventmask = dhd->conf->resume_eventmask; - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "event_msgs", eventmask, sizeof(eventmask), TRUE); - } -#endif - } else if (mode == AP_DOWN_IN_SUSPEND) { - wl_down = 0; - dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&wl_down, sizeof(wl_down), TRUE, 0); - } - } - - return mode; -} - -#ifdef PROP_TXSTATUS -int -dhd_conf_get_disable_proptx(dhd_pub_t *dhd) -{ - struct dhd_conf *conf = dhd->conf; - int disable_proptx = -1; - int fw_proptx = 0; - - /* check fw proptx priority: - * 1st: check fw support by wl cap - * 2nd: 4334/43340/43341/43241 support proptx but not show in wl cap, so enable it by default - * if you would like to disable it, please set disable_proptx=1 in config.txt - * 3th: disable when proptxstatus not support in wl cap - */ - if (FW_SUPPORTED(dhd, proptxstatus)) { - fw_proptx = 1; - } else if (conf->chip == BCM4334_CHIP_ID || conf->chip == BCM43340_CHIP_ID || - dhd->conf->chip == BCM43340_CHIP_ID || conf->chip == BCM4324_CHIP_ID) { - fw_proptx = 1; - } else { - fw_proptx = 0; - } - - /* returned disable_proptx value: - * -1: disable in STA and enable in P2P(follow original dhd settings when PROP_TXSTATUS_VSDB enabled) - * 0: depend on fw support - * 1: always disable proptx - */ - if (conf->disable_proptx == 0) { - // check fw support as well - if (fw_proptx) - disable_proptx = 0; - else - disable_proptx = 1; - } else if (conf->disable_proptx >= 1) { - disable_proptx = 1; - } else { - // check fw support as well - if (fw_proptx) - disable_proptx = -1; - else - disable_proptx = 1; - } - - CONFIG_INFO(("%s: fw_proptx=%d, disable_proptx=%d\n", __FUNCTION__, fw_proptx, disable_proptx)); - - return disable_proptx; -} -#endif - -uint -pick_config_vars(char *varbuf, uint len, uint start_pos, char *pickbuf) -{ - bool findNewline, changenewline=FALSE, pick=FALSE; - int column; - uint n, pick_column=0; - - findNewline = FALSE; - column = 0; - - if (start_pos >= len) { - CONFIG_ERROR(("%s: wrong start pos\n", __FUNCTION__)); - return 0; - } - - for (n = start_pos; n < len; n++) { - if (varbuf[n] == '\r') - continue; - if ((findNewline || changenewline) && varbuf[n] != '\n') - continue; - findNewline = FALSE; - if (varbuf[n] == '#') { - findNewline = TRUE; - continue; - } - if (varbuf[n] == '\\') { - changenewline = TRUE; - continue; - } - if (!changenewline && varbuf[n] == '\n') { - if (column == 0) - continue; - column = 0; - continue; - } - if (changenewline && varbuf[n] == '\n') { - changenewline = FALSE; - continue; - } - - if (column==0 && !pick) { // start to pick - pick = TRUE; - column++; - pick_column = 0; - } else { - if (pick && column==0) { // stop to pick - pick = FALSE; - break; - } else - column++; - } - if (pick) { - if (varbuf[n] == 0x9) - continue; - pickbuf[pick_column] = varbuf[n]; - pick_column++; - } - } - - return n; // return current position -} - -bool -dhd_conf_read_log_level(dhd_pub_t *dhd, char *full_param, uint len_param) -{ - char *data = full_param+len_param; - - if (!strncmp("dhd_msg_level=", full_param, len_param)) { - dhd_msg_level = (int)simple_strtol(data, NULL, 0); - CONFIG_INFO(("%s: dhd_msg_level = 0x%X\n", __FUNCTION__, dhd_msg_level)); - } -#ifdef BCMSDIO - else if (!strncmp("sd_msglevel=", full_param, len_param)) { - sd_msglevel = (int)simple_strtol(data, NULL, 0); - CONFIG_INFO(("%s: sd_msglevel = 0x%X\n", __FUNCTION__, sd_msglevel)); - } -#endif -#ifdef BCMDBUS - else if (!strncmp("dbus_msglevel=", full_param, len_param)) { - dbus_msglevel = (int)simple_strtol(data, NULL, 0); - CONFIG_INFO(("%s: dbus_msglevel = 0x%X\n", __FUNCTION__, dbus_msglevel)); - } -#endif - else if (!strncmp("android_msg_level=", full_param, len_param)) { - android_msg_level = (int)simple_strtol(data, NULL, 0); - CONFIG_INFO(("%s: android_msg_level = 0x%X\n", __FUNCTION__, android_msg_level)); - } - else if (!strncmp("config_msg_level=", full_param, len_param)) { - config_msg_level = (int)simple_strtol(data, NULL, 0); - CONFIG_INFO(("%s: config_msg_level = 0x%X\n", __FUNCTION__, config_msg_level)); - } -#ifdef WL_CFG80211 - else if (!strncmp("wl_dbg_level=", full_param, len_param)) { - wl_dbg_level = (int)simple_strtol(data, NULL, 0); - CONFIG_INFO(("%s: wl_dbg_level = 0x%X\n", __FUNCTION__, wl_dbg_level)); - } -#endif -#if defined(WL_WIRELESS_EXT) - else if (!strncmp("iw_msg_level=", full_param, len_param)) { - iw_msg_level = (int)simple_strtol(data, NULL, 0); - CONFIG_INFO(("%s: iw_msg_level = 0x%X\n", __FUNCTION__, iw_msg_level)); - } -#endif -#if defined(DHD_DEBUG) - else if (!strncmp("dhd_console_ms=", full_param, len_param)) { - dhd_console_ms = (int)simple_strtol(data, NULL, 0); - CONFIG_INFO(("%s: dhd_console_ms = 0x%X\n", __FUNCTION__, dhd_console_ms)); - } -#endif - else - return false; - - return true; -} - -void -dhd_conf_read_wme_ac_value(wme_param_t *wme, char *pick, int ac_val) -{ - char *pick_tmp, *pch; - - pick_tmp = pick; - pch = bcmstrstr(pick_tmp, "aifsn "); - if (pch) { - wme->aifsn[ac_val] = (int)simple_strtol(pch+strlen("aifsn "), NULL, 0); - DHD_PRINT(("%s: ac_val=%d, aifsn=%d\n", __FUNCTION__, ac_val, wme->aifsn[ac_val])); - } - pick_tmp = pick; - pch = bcmstrstr(pick_tmp, "ecwmin "); - if (pch) { - wme->ecwmin[ac_val] = (int)simple_strtol(pch+strlen("ecwmin "), NULL, 0); - DHD_PRINT(("%s: ac_val=%d, ecwmin=%d\n", __FUNCTION__, ac_val, wme->ecwmin[ac_val])); - } - pick_tmp = pick; - pch = bcmstrstr(pick_tmp, "ecwmax "); - if (pch) { - wme->ecwmax[ac_val] = (int)simple_strtol(pch+strlen("ecwmax "), NULL, 0); - DHD_PRINT(("%s: ac_val=%d, ecwmax=%d\n", __FUNCTION__, ac_val, wme->ecwmax[ac_val])); - } - pick_tmp = pick; - pch = bcmstrstr(pick_tmp, "txop "); - if (pch) { - wme->txop[ac_val] = (int)simple_strtol(pch+strlen("txop "), NULL, 0); - DHD_PRINT(("%s: ac_val=%d, txop=0x%x\n", __FUNCTION__, ac_val, wme->txop[ac_val])); - } - -} - -bool -dhd_conf_read_wme_ac_params(dhd_pub_t *dhd, char *full_param, uint len_param) -{ - struct dhd_conf *conf = dhd->conf; - char *data = full_param+len_param; - - // wme_ac_sta_be=aifsn 1 ecwmin 2 ecwmax 3 txop 0x5e - // wme_ac_sta_vo=aifsn 1 ecwmin 1 ecwmax 1 txop 0x5e - - if (!strncmp("force_wme_ac=", full_param, len_param)) { - conf->force_wme_ac = (int)simple_strtol(data, NULL, 10); - DHD_PRINT(("%s: force_wme_ac = %d\n", __FUNCTION__, conf->force_wme_ac)); - } - else if (!strncmp("wme_ac_sta_be=", full_param, len_param)) { - dhd_conf_read_wme_ac_value(&conf->wme_sta, data, AC_BE); - } - else if (!strncmp("wme_ac_sta_bk=", full_param, len_param)) { - dhd_conf_read_wme_ac_value(&conf->wme_sta, data, AC_BK); - } - else if (!strncmp("wme_ac_sta_vi=", full_param, len_param)) { - dhd_conf_read_wme_ac_value(&conf->wme_sta, data, AC_VI); - } - else if (!strncmp("wme_ac_sta_vo=", full_param, len_param)) { - dhd_conf_read_wme_ac_value(&conf->wme_sta, data, AC_VO); - } - else if (!strncmp("wme_ac_ap_be=", full_param, len_param)) { - dhd_conf_read_wme_ac_value(&conf->wme_ap, data, AC_BE); - } - else if (!strncmp("wme_ac_ap_bk=", full_param, len_param)) { - dhd_conf_read_wme_ac_value(&conf->wme_ap, data, AC_BK); - } - else if (!strncmp("wme_ac_ap_vi=", full_param, len_param)) { - dhd_conf_read_wme_ac_value(&conf->wme_ap, data, AC_VI); - } - else if (!strncmp("wme_ac_ap_vo=", full_param, len_param)) { - dhd_conf_read_wme_ac_value(&conf->wme_ap, data, AC_VO); - } - else - return false; - - return true; -} - -bool -dhd_conf_read_fw_by_mac(dhd_pub_t *dhd, char *full_param, uint len_param) -{ - int i, j; - char *pch, *pick_tmp; - wl_mac_list_t *mac_list; - wl_mac_range_t *mac_range; - struct dhd_conf *conf = dhd->conf; - char *data = full_param+len_param; - - /* Process fw_by_mac: - * fw_by_mac=[fw_mac_num] \ - * [fw_name1] [mac_num1] [oui1-1] [nic_start1-1] [nic_end1-1] \ - * [oui1-1] [nic_start1-1] [nic_end1-1]... \ - * [oui1-n] [nic_start1-n] [nic_end1-n] \ - * [fw_name2] [mac_num2] [oui2-1] [nic_start2-1] [nic_end2-1] \ - * [oui2-1] [nic_start2-1] [nic_end2-1]... \ - * [oui2-n] [nic_start2-n] [nic_end2-n] \ - * Ex: fw_by_mac=2 \ - * fw_bcmdhd1.bin 2 0x0022F4 0xE85408 0xE8549D 0x983B16 0x3557A9 0x35582A \ - * fw_bcmdhd2.bin 3 0x0022F4 0xE85408 0xE8549D 0x983B16 0x3557A9 0x35582A \ - * 0x983B16 0x916157 0x916487 - */ - - if (!strncmp("fw_by_mac=", full_param, len_param)) { - pick_tmp = data; - pch = bcmstrtok(&pick_tmp, " ", 0); - conf->fw_by_mac.count = (uint32)simple_strtol(pch, NULL, 0); - if (!(mac_list = kmalloc(sizeof(wl_mac_list_t)*conf->fw_by_mac.count, GFP_KERNEL))) { - conf->fw_by_mac.count = 0; - CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - } - CONFIG_INFO(("%s: fw_count=%d\n", __FUNCTION__, conf->fw_by_mac.count)); - conf->fw_by_mac.m_mac_list_head = mac_list; - for (i=0; i<conf->fw_by_mac.count; i++) { - pch = bcmstrtok(&pick_tmp, " ", 0); - strcpy(mac_list[i].name, pch); - pch = bcmstrtok(&pick_tmp, " ", 0); - mac_list[i].count = (uint32)simple_strtol(pch, NULL, 0); - CONFIG_INFO(("%s: name=%s, mac_count=%d\n", __FUNCTION__, - mac_list[i].name, mac_list[i].count)); - if (!(mac_range = kmalloc(sizeof(wl_mac_range_t)*mac_list[i].count, GFP_KERNEL))) { - mac_list[i].count = 0; - CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - break; - } - mac_list[i].mac = mac_range; - for (j=0; j<mac_list[i].count; j++) { - pch = bcmstrtok(&pick_tmp, " ", 0); - mac_range[j].oui = (uint32)simple_strtol(pch, NULL, 0); - pch = bcmstrtok(&pick_tmp, " ", 0); - mac_range[j].nic_start = (uint32)simple_strtol(pch, NULL, 0); - pch = bcmstrtok(&pick_tmp, " ", 0); - mac_range[j].nic_end = (uint32)simple_strtol(pch, NULL, 0); - CONFIG_INFO(("%s: oui=0x%06X, nic_start=0x%06X, nic_end=0x%06X\n", - __FUNCTION__, mac_range[j].oui, - mac_range[j].nic_start, mac_range[j].nic_end)); - } - } - } - else - return false; - - return true; -} - -bool -dhd_conf_read_nv_by_mac(dhd_pub_t *dhd, char *full_param, uint len_param) -{ - int i, j; - char *pch, *pick_tmp; - wl_mac_list_t *mac_list; - wl_mac_range_t *mac_range; - struct dhd_conf *conf = dhd->conf; - char *data = full_param+len_param; - - /* Process nv_by_mac: - * [nv_by_mac]: The same format as fw_by_mac - */ - if (!strncmp("nv_by_mac=", full_param, len_param)) { - pick_tmp = data; - pch = bcmstrtok(&pick_tmp, " ", 0); - conf->nv_by_mac.count = (uint32)simple_strtol(pch, NULL, 0); - if (!(mac_list = kmalloc(sizeof(wl_mac_list_t)*conf->nv_by_mac.count, GFP_KERNEL))) { - conf->nv_by_mac.count = 0; - CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - } - CONFIG_INFO(("%s: nv_count=%d\n", __FUNCTION__, conf->nv_by_mac.count)); - conf->nv_by_mac.m_mac_list_head = mac_list; - for (i=0; i<conf->nv_by_mac.count; i++) { - pch = bcmstrtok(&pick_tmp, " ", 0); - strcpy(mac_list[i].name, pch); - pch = bcmstrtok(&pick_tmp, " ", 0); - mac_list[i].count = (uint32)simple_strtol(pch, NULL, 0); - CONFIG_INFO(("%s: name=%s, mac_count=%d\n", __FUNCTION__, - mac_list[i].name, mac_list[i].count)); - if (!(mac_range = kmalloc(sizeof(wl_mac_range_t)*mac_list[i].count, GFP_KERNEL))) { - mac_list[i].count = 0; - CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - break; - } - mac_list[i].mac = mac_range; - for (j=0; j<mac_list[i].count; j++) { - pch = bcmstrtok(&pick_tmp, " ", 0); - mac_range[j].oui = (uint32)simple_strtol(pch, NULL, 0); - pch = bcmstrtok(&pick_tmp, " ", 0); - mac_range[j].nic_start = (uint32)simple_strtol(pch, NULL, 0); - pch = bcmstrtok(&pick_tmp, " ", 0); - mac_range[j].nic_end = (uint32)simple_strtol(pch, NULL, 0); - CONFIG_INFO(("%s: oui=0x%06X, nic_start=0x%06X, nic_end=0x%06X\n", - __FUNCTION__, mac_range[j].oui, - mac_range[j].nic_start, mac_range[j].nic_end)); - } - } - } - else - return false; - - return true; -} - -bool -dhd_conf_read_nv_by_chip(dhd_pub_t *dhd, char *full_param, uint len_param) -{ - int i; - char *pch, *pick_tmp; - wl_chip_nv_path_t *chip_nv_path; - struct dhd_conf *conf = dhd->conf; - char *data = full_param+len_param; - - /* Process nv_by_chip: - * nv_by_chip=[nv_chip_num] \ - * [chip1] [chiprev1] [nv_name1] [chip2] [chiprev2] [nv_name2] \ - * Ex: nv_by_chip=2 \ - * 43430 0 nvram_ap6212.txt 43430 1 nvram_ap6212a.txt \ - */ - if (!strncmp("nv_by_chip=", full_param, len_param)) { - pick_tmp = data; - pch = bcmstrtok(&pick_tmp, " ", 0); - conf->nv_by_chip.count = (uint32)simple_strtol(pch, NULL, 0); - if (!(chip_nv_path = kmalloc(sizeof(wl_mac_list_t)*conf->nv_by_chip.count, GFP_KERNEL))) { - conf->nv_by_chip.count = 0; - CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - } - CONFIG_INFO(("%s: nv_by_chip_count=%d\n", __FUNCTION__, conf->nv_by_chip.count)); - conf->nv_by_chip.m_chip_nv_path_head = chip_nv_path; - for (i=0; i<conf->nv_by_chip.count; i++) { - pch = bcmstrtok(&pick_tmp, " ", 0); - chip_nv_path[i].chip = (uint32)simple_strtol(pch, NULL, 0); - pch = bcmstrtok(&pick_tmp, " ", 0); - chip_nv_path[i].chiprev = (uint32)simple_strtol(pch, NULL, 0); - pch = bcmstrtok(&pick_tmp, " ", 0); - strcpy(chip_nv_path[i].name, pch); - CONFIG_INFO(("%s: chip=0x%x, chiprev=%d, name=%s\n", __FUNCTION__, - chip_nv_path[i].chip, chip_nv_path[i].chiprev, chip_nv_path[i].name)); - } - } - else - return false; - - return true; -} - -bool -dhd_conf_read_roam_params(dhd_pub_t *dhd, char *full_param, uint len_param) -{ - struct dhd_conf *conf = dhd->conf; - char *data = full_param+len_param; - - if (!strncmp("roam_off=", full_param, len_param)) { - if (!strncmp(data, "0", 1)) - conf->roam_off = 0; - else - conf->roam_off = 1; - CONFIG_INFO(("%s: roam_off = %d\n", __FUNCTION__, conf->roam_off)); - } - else if (!strncmp("roam_off_suspend=", full_param, len_param)) { - if (!strncmp(data, "0", 1)) - conf->roam_off_suspend = 0; - else - conf->roam_off_suspend = 1; - CONFIG_INFO(("%s: roam_off_suspend = %d\n", __FUNCTION__, conf->roam_off_suspend)); - } - else if (!strncmp("roam_trigger=", full_param, len_param)) { - conf->roam_trigger[0] = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: roam_trigger = %d\n", __FUNCTION__, - conf->roam_trigger[0])); - } - else if (!strncmp("roam_scan_period=", full_param, len_param)) { - conf->roam_scan_period[0] = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: roam_scan_period = %d\n", __FUNCTION__, - conf->roam_scan_period[0])); - } - else if (!strncmp("roam_delta=", full_param, len_param)) { - conf->roam_delta[0] = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: roam_delta = %d\n", __FUNCTION__, conf->roam_delta[0])); - } - else if (!strncmp("fullroamperiod=", full_param, len_param)) { - conf->fullroamperiod = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: fullroamperiod = %d\n", __FUNCTION__, - conf->fullroamperiod)); - } else - return false; - - return true; -} - -bool -dhd_conf_read_country_list(dhd_pub_t *dhd, char *full_param, uint len_param) -{ - int i; - char *pch, *pick_tmp, *pick_tmp2; - struct dhd_conf *conf = dhd->conf; - char *data = full_param+len_param; - wl_country_t *cspec; - conf_country_list_t *country_list = NULL; - - /* Process country_list: - * country_list=[country1]:[ccode1]/[regrev1], - * [country2]:[ccode2]/[regrev2] \ - * Ex: country_list=US:US/0, TW:TW/1 - */ - if (!strncmp("country_list=", full_param, len_param)) { - country_list = &dhd->conf->country_list; - } else if (!strncmp("country_list_nodfs=", full_param, len_param)) { - country_list = &dhd->conf->country_list_nodfs; - } - if (country_list) { - pick_tmp = data; - for (i=0; i<CONFIG_COUNTRY_LIST_SIZE; i++) { - pick_tmp2 = bcmstrtok(&pick_tmp, ", ", 0); - if (!pick_tmp2) - break; - pch = bcmstrtok(&pick_tmp2, ":", 0); - if (!pch) - break; - cspec = NULL; - if (!(cspec = kmalloc(sizeof(wl_country_t), GFP_KERNEL))) { - CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - break; - } - memset(cspec, 0, sizeof(wl_country_t)); - - strcpy(cspec->country_abbrev, pch); - pch = bcmstrtok(&pick_tmp2, "/", 0); - if (!pch) { - kfree(cspec); - break; - } - memcpy(cspec->ccode, pch, 2); - pch = bcmstrtok(&pick_tmp2, "/", 0); - if (!pch) { - kfree(cspec); - break; - } - cspec->rev = (int32)simple_strtol(pch, NULL, 10); - country_list->count++; - country_list->cspec[i] = cspec; - CONFIG_TRACE(("%s: country_list abbrev=%s, ccode=%s, regrev=%d\n", __FUNCTION__, - cspec->country_abbrev, cspec->ccode, cspec->rev)); - } - if (!strncmp("country_list=", full_param, len_param)) { - CONFIG_INFO(("%s: %d country in list\n", __FUNCTION__, conf->country_list.count)); - } else if (!strncmp("country_list_nodfs=", full_param, len_param)) { - CONFIG_INFO(("%s: %d nodfs country in list\n", __FUNCTION__, conf->country_list.count)); - } - } - else - return false; - - return true; -} - -bool -dhd_conf_read_mchan_params(dhd_pub_t *dhd, char *full_param, uint len_param) -{ - int i; - char *pch, *pick_tmp, *pick_tmp2; - struct dhd_conf *conf = dhd->conf; - char *data = full_param+len_param; - - /* Process mchan_bw: - * mchan_bw=[val]/[any/go/gc]/[any/source/sink] - * Ex: mchan_bw=80/go/source, 30/gc/sink - */ - if (!strncmp("mchan_bw=", full_param, len_param)) { - pick_tmp = data; - for (i=0; i<MCHAN_MAX_NUM; i++) { - pick_tmp2 = bcmstrtok(&pick_tmp, ", ", 0); - if (!pick_tmp2) - break; - pch = bcmstrtok(&pick_tmp2, "/", 0); - if (!pch) { - break; - } else { - conf->mchan[i].bw = (int)simple_strtol(pch, NULL, 0); - if (conf->mchan[i].bw < 0 || conf->mchan[i].bw > 100) { - CONFIG_ERROR(("%s: wrong bw %d\n", __FUNCTION__, conf->mchan[i].bw)); - conf->mchan[i].bw = 0; - break; - } - } - pch = bcmstrtok(&pick_tmp2, "/", 0); - if (!pch) { - break; - } else { - if (bcmstrstr(pch, "any")) { - conf->mchan[i].p2p_mode = -1; - } else if (bcmstrstr(pch, "go")) { - conf->mchan[i].p2p_mode = WL_P2P_IF_GO; - } else if (bcmstrstr(pch, "gc")) { - conf->mchan[i].p2p_mode = WL_P2P_IF_CLIENT; - } - } - pch = bcmstrtok(&pick_tmp2, "/", 0); - if (!pch) { - break; - } else { - if (bcmstrstr(pch, "any")) { - conf->mchan[i].miracast_mode = -1; - } else if (bcmstrstr(pch, "source")) { - conf->mchan[i].miracast_mode = MIRACAST_SOURCE; - } else if (bcmstrstr(pch, "sink")) { - conf->mchan[i].miracast_mode = MIRACAST_SINK; - } - } - } - for (i=0; i<MCHAN_MAX_NUM; i++) { - if (conf->mchan[i].bw >= 0) - CONFIG_INFO(("%s: mchan_bw=%d/%d/%d\n", __FUNCTION__, - conf->mchan[i].bw, conf->mchan[i].p2p_mode, conf->mchan[i].miracast_mode)); - } - } - else - return false; - - return true; -} - -#ifdef PKT_FILTER_SUPPORT -bool -dhd_conf_read_pkt_filter(dhd_pub_t *dhd, char *full_param, uint len_param) -{ - struct dhd_conf *conf = dhd->conf; - char *data = full_param+len_param; - char *pch, *pick_tmp; - int i; - - /* Process pkt filter: - * 1) pkt_filter_add=99 0 0 0 0x000000000000 0x000000000000 - * 2) pkt_filter_del=100, 102, 103, 104, 105 - * 3) magic_pkt_filter_add=141 0 1 12 - */ - if (!strncmp("dhd_master_mode=", full_param, len_param)) { - if (!strncmp(data, "0", 1)) - dhd_master_mode = FALSE; - else - dhd_master_mode = TRUE; - CONFIG_INFO(("%s: dhd_master_mode = %d\n", __FUNCTION__, dhd_master_mode)); - } - else if (!strncmp("pkt_filter_add=", full_param, len_param)) { - pick_tmp = data; - pch = bcmstrtok(&pick_tmp, ",.-", 0); - i=0; - while (pch != NULL && i<DHD_CONF_FILTER_MAX) { - strcpy(&conf->pkt_filter_add.filter[i][0], pch); - CONFIG_INFO(("%s: pkt_filter_add[%d][] = %s\n", __FUNCTION__, i, &conf->pkt_filter_add.filter[i][0])); - pch = bcmstrtok(&pick_tmp, ",.-", 0); - i++; - } - conf->pkt_filter_add.count = i; - } - else if (!strncmp("pkt_filter_del=", full_param, len_param)) { - pick_tmp = data; - pch = bcmstrtok(&pick_tmp, " ,.-", 0); - i=0; - while (pch != NULL && i<DHD_CONF_FILTER_MAX) { - conf->pkt_filter_del.id[i] = (uint32)simple_strtol(pch, NULL, 10); - pch = bcmstrtok(&pick_tmp, " ,.-", 0); - i++; - } - conf->pkt_filter_del.count = i; - CONFIG_INFO(("%s: pkt_filter_del id = ", __FUNCTION__)); - for (i=0; i<conf->pkt_filter_del.count; i++) - CONFIG_INFO(("%d ", conf->pkt_filter_del.id[i])); - CONFIG_INFO(("\n")); - } - else if (!strncmp("magic_pkt_filter_add=", full_param, len_param)) { - if (!(conf->magic_pkt_filter_add = kmalloc(MAGIC_PKT_FILTER_LEN, GFP_KERNEL))) { - CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - } else { - memset(conf->magic_pkt_filter_add, 0, MAGIC_PKT_FILTER_LEN); - strcpy(conf->magic_pkt_filter_add, data); - CONFIG_INFO(("%s: magic_pkt_filter_add = %s\n", __FUNCTION__, conf->magic_pkt_filter_add)); - } - } - else - return false; - - return true; -} -#endif - -#ifdef IAPSTA_PREINIT -/* - * iapsta_init=mode [sta|ap|apsta|dualap] vifname [wlan1] - * iapsta_config=ifname [wlan0|wlan1] ssid [xxx] chan [x] - hidden [y|n] maxassoc [x] - amode [open|shared|wpapsk|wpa2psk|wpawpa2psk] - emode [none|wep|tkip|aes|tkipaes] - key [xxxxx] - * iapsta_enable=ifname [wlan0|wlan1] -*/ -bool -dhd_conf_read_iapsta(dhd_pub_t *dhd, char *full_param, uint len_param) -{ - struct dhd_conf *conf = dhd->conf; - char *data = full_param+len_param; - - if (!strncmp("iapsta_init=", full_param, len_param)) { - sprintf(conf->iapsta_init, "iapsta_init %s", data); - CONFIG_INFO(("%s: iapsta_init=%s\n", __FUNCTION__, conf->iapsta_init)); - } - else if (!strncmp("iapsta_config=", full_param, len_param)) { - sprintf(conf->iapsta_config, "iapsta_config %s", data); - CONFIG_INFO(("%s: iapsta_config=%s\n", __FUNCTION__, conf->iapsta_config)); - } - else if (!strncmp("iapsta_enable=", full_param, len_param)) { - sprintf(conf->iapsta_enable, "iapsta_enable %s", data); - CONFIG_INFO(("%s: iapsta_enable=%s\n", __FUNCTION__, conf->iapsta_enable)); - } - else - return false; - - return true; -} -#endif - -#ifdef IDHCP -bool -dhd_conf_read_dhcp_params(dhd_pub_t *dhd, char *full_param, uint len_param) -{ - struct dhd_conf *conf = dhd->conf; - char *data = full_param+len_param; - struct ipv4_addr ipa_set; - - if (!strncmp("dhcpc_enable=", full_param, len_param)) { - conf->dhcpc_enable = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: dhcpc_enable = %d\n", __FUNCTION__, conf->dhcpc_enable)); - } - else if (!strncmp("dhcpd_enable=", full_param, len_param)) { - conf->dhcpd_enable = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: dhcpd_enable = %d\n", __FUNCTION__, conf->dhcpd_enable)); - } - else if (!strncmp("dhcpd_ip_addr=", full_param, len_param)) { - if (!bcm_atoipv4(data, &ipa_set)) - CONFIG_ERROR(("%s : dhcpd_ip_addr adress setting failed.\n", __FUNCTION__)); - conf->dhcpd_ip_addr = ipa_set; - CONFIG_INFO(("%s: dhcpd_ip_addr = %s\n",__FUNCTION__, data)); - } - else if (!strncmp("dhcpd_ip_mask=", full_param, len_param)) { - if (!bcm_atoipv4(data, &ipa_set)) - CONFIG_ERROR(("%s : dhcpd_ip_mask adress setting failed.\n", __FUNCTION__)); - conf->dhcpd_ip_mask = ipa_set; - CONFIG_INFO(("%s: dhcpd_ip_mask = %s\n",__FUNCTION__, data)); - } - else if (!strncmp("dhcpd_ip_start=", full_param, len_param)) { - if (!bcm_atoipv4(data, &ipa_set)) - CONFIG_ERROR(("%s : dhcpd_ip_start adress setting failed.\n", __FUNCTION__)); - conf->dhcpd_ip_start = ipa_set; - CONFIG_INFO(("%s: dhcpd_ip_start = %s\n",__FUNCTION__, data)); - } - else if (!strncmp("dhcpd_ip_end=", full_param, len_param)) { - if (!bcm_atoipv4(data, &ipa_set)) - CONFIG_ERROR(("%s : dhcpd_ip_end adress setting failed.\n", __FUNCTION__)); - conf->dhcpd_ip_end = ipa_set; - CONFIG_INFO(("%s: dhcpd_ip_end = %s\n",__FUNCTION__, data)); - } - else - return false; - - return true; -} -#endif - -#ifdef BCMSDIO -bool -dhd_conf_read_sdio_params(dhd_pub_t *dhd, char *full_param, uint len_param) -{ - struct dhd_conf *conf = dhd->conf; - char *data = full_param+len_param; - - if (!strncmp("dhd_doflow=", full_param, len_param)) { - if (!strncmp(data, "0", 1)) - dhd_doflow = FALSE; - else - dhd_doflow = TRUE; - CONFIG_INFO(("%s: dhd_doflow = %d\n", __FUNCTION__, dhd_doflow)); - } - else if (!strncmp("dhd_slpauto=", full_param, len_param) || - !strncmp("kso_enable=", full_param, len_param)) { - if (!strncmp(data, "0", 1)) - dhd_slpauto = FALSE; - else - dhd_slpauto = TRUE; - CONFIG_INFO(("%s: dhd_slpauto = %d\n", __FUNCTION__, dhd_slpauto)); - } - else if (!strncmp("use_rxchain=", full_param, len_param)) { - conf->use_rxchain = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: use_rxchain = %d\n", __FUNCTION__, conf->use_rxchain)); - } - else if (!strncmp("dhd_txminmax=", full_param, len_param)) { - conf->dhd_txminmax = (uint)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: dhd_txminmax = %d\n", __FUNCTION__, conf->dhd_txminmax)); - } - else if (!strncmp("txinrx_thres=", full_param, len_param)) { - conf->txinrx_thres = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: txinrx_thres = %d\n", __FUNCTION__, conf->txinrx_thres)); - } - else if (!strncmp("sd_f2_blocksize=", full_param, len_param)) { - conf->sd_f2_blocksize = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: sd_f2_blocksize = %d\n", __FUNCTION__, conf->sd_f2_blocksize)); - } - else if (!strncmp("oob_enabled_later=", full_param, len_param)) { - if (!strncmp(data, "0", 1)) - conf->oob_enabled_later = FALSE; - else - conf->oob_enabled_later = TRUE; - CONFIG_INFO(("%s: oob_enabled_later = %d\n", __FUNCTION__, conf->oob_enabled_later)); - } - else if (!strncmp("dpc_cpucore=", full_param, len_param)) { - conf->dpc_cpucore = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: dpc_cpucore = %d\n", __FUNCTION__, conf->dpc_cpucore)); - } - else if (!strncmp("rxf_cpucore=", full_param, len_param)) { - conf->rxf_cpucore = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: rxf_cpucore = %d\n", __FUNCTION__, conf->rxf_cpucore)); - } - else if (!strncmp("orphan_move=", full_param, len_param)) { - conf->orphan_move = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: orphan_move = %d\n", __FUNCTION__, conf->orphan_move)); - } -#if defined(BCMSDIOH_TXGLOM) - else if (!strncmp("txglomsize=", full_param, len_param)) { - conf->txglomsize = (uint)simple_strtol(data, NULL, 10); - if (conf->txglomsize > SDPCM_MAXGLOM_SIZE) - conf->txglomsize = SDPCM_MAXGLOM_SIZE; - CONFIG_INFO(("%s: txglomsize = %d\n", __FUNCTION__, conf->txglomsize)); - } - else if (!strncmp("txglom_ext=", full_param, len_param)) { - if (!strncmp(data, "0", 1)) - conf->txglom_ext = FALSE; - else - conf->txglom_ext = TRUE; - CONFIG_INFO(("%s: txglom_ext = %d\n", __FUNCTION__, conf->txglom_ext)); - if (conf->txglom_ext) { - if ((conf->chip == BCM43362_CHIP_ID) || (conf->chip == BCM4330_CHIP_ID)) - conf->txglom_bucket_size = 1680; - else if (conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID || - conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID) - conf->txglom_bucket_size = 1684; - } - CONFIG_INFO(("%s: txglom_bucket_size = %d\n", __FUNCTION__, conf->txglom_bucket_size)); - } - else if (!strncmp("bus:rxglom=", full_param, len_param)) { - if (!strncmp(data, "0", 1)) - conf->bus_rxglom = FALSE; - else - conf->bus_rxglom= TRUE; - CONFIG_INFO(("%s: bus:rxglom = %d\n", __FUNCTION__, conf->bus_rxglom)); - } - else if (!strncmp("deferred_tx_len=", full_param, len_param)) { - conf->deferred_tx_len = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: deferred_tx_len = %d\n", __FUNCTION__, conf->deferred_tx_len)); - } - else if (!strncmp("txctl_tmo_fix=", full_param, len_param)) { - conf->txctl_tmo_fix = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: txctl_tmo_fix = %d\n", __FUNCTION__, conf->txctl_tmo_fix)); - } - else if (!strncmp("tx_in_rx=", full_param, len_param)) { - if (!strncmp(data, "0", 1)) - conf->tx_in_rx = FALSE; - else - conf->tx_in_rx = TRUE; - CONFIG_INFO(("%s: tx_in_rx = %d\n", __FUNCTION__, conf->tx_in_rx)); - } - else if (!strncmp("tx_max_offset=", full_param, len_param)) { - conf->tx_max_offset = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: tx_max_offset = %d\n", __FUNCTION__, conf->tx_max_offset)); - } - else if (!strncmp("txglom_mode=", full_param, len_param)) { - if (!strncmp(data, "0", 1)) - conf->txglom_mode = FALSE; - else - conf->txglom_mode = TRUE; - CONFIG_INFO(("%s: txglom_mode = %d\n", __FUNCTION__, conf->txglom_mode)); - } -#endif - else if (!strncmp("dhd_idletime=", full_param, len_param)) { - dhd_idletime = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: dhd_idletime = %d\n", __FUNCTION__, dhd_idletime)); - } - else - return false; - - return true; -} -#endif - -#ifdef BCMPCIE -bool -dhd_conf_read_pcie_params(dhd_pub_t *dhd, char *full_param, uint len_param) -{ - struct dhd_conf *conf = dhd->conf; - char *data = full_param+len_param; - - if (!strncmp("bus:deepsleep_disable=", full_param, len_param)) { - if (!strncmp(data, "0", 1)) - conf->bus_deepsleep_disable = 0; - else - conf->bus_deepsleep_disable = 1; - CONFIG_INFO(("%s: bus:deepsleep_disable = %d\n", __FUNCTION__, conf->bus_deepsleep_disable)); - } - else - return false; - - return true; -} -#endif - -bool -dhd_conf_read_pm_params(dhd_pub_t *dhd, char *full_param, uint len_param) -{ - struct dhd_conf *conf = dhd->conf; - char *data = full_param+len_param; - - if (!strncmp("deepsleep=", full_param, len_param)) { - if (!strncmp(data, "1", 1)) - conf->deepsleep = TRUE; - else - conf->deepsleep = FALSE; - CONFIG_INFO(("%s: deepsleep = %d\n", __FUNCTION__, conf->deepsleep)); - } - else if (!strncmp("PM=", full_param, len_param)) { - conf->pm = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: PM = %d\n", __FUNCTION__, conf->pm)); - } - else if (!strncmp("pm_in_suspend=", full_param, len_param)) { - conf->pm_in_suspend = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: pm_in_suspend = %d\n", __FUNCTION__, conf->pm_in_suspend)); - } - else if (!strncmp("pm2_sleep_ret_in_suspend=", full_param, len_param)) { - conf->pm2_sleep_ret_in_suspend = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: pm2_sleep_ret_in_suspend = %d\n", __FUNCTION__, conf->pm2_sleep_ret_in_suspend)); - } - else if (!strncmp("pm2_sleep_ret_in_resume=", full_param, len_param)) { - conf->pm2_sleep_ret_in_resume = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: pm2_sleep_ret_in_resume = %d\n", __FUNCTION__, conf->pm2_sleep_ret_in_resume)); - } - else if (!strncmp("suspend_bcn_li_dtim=", full_param, len_param)) { - conf->suspend_bcn_li_dtim = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: suspend_bcn_li_dtim = %d\n", __FUNCTION__, conf->suspend_bcn_li_dtim)); - } - else if (!strncmp("xmit_in_suspend=", full_param, len_param)) { - if (!strncmp(data, "1", 1)) - conf->xmit_in_suspend = TRUE; - else - conf->xmit_in_suspend = FALSE; - CONFIG_INFO(("%s: xmit_in_suspend = %d\n", __FUNCTION__, conf->xmit_in_suspend)); - } - else if (!strncmp("ap_in_suspend=", full_param, len_param)) { - conf->ap_in_suspend = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: ap_in_suspend = %d\n", __FUNCTION__, conf->ap_in_suspend)); - } -#ifdef SUSPEND_EVENT - else if (!strncmp("suspend_eventmask_enable=", full_param, len_param)) { - if (!strncmp(data, "1", 1)) - conf->suspend_eventmask_enable = TRUE; - else - conf->suspend_eventmask_enable = FALSE; - CONFIG_INFO(("%s: suspend_eventmask_enable = %d\n", __FUNCTION__, conf->suspend_eventmask_enable)); - } -#endif - else - return false; - - return true; -} - -bool -dhd_conf_read_others(dhd_pub_t *dhd, char *full_param, uint len_param) -{ - struct dhd_conf *conf = dhd->conf; - char *data = full_param+len_param; - uint len_data = strlen(data); - char *pch, *pick_tmp; - int i; - - if (!strncmp("dhd_poll=", full_param, len_param)) { - if (!strncmp(data, "0", 1)) - conf->dhd_poll = 0; - else - conf->dhd_poll = 1; - CONFIG_INFO(("%s: dhd_poll = %d\n", __FUNCTION__, conf->dhd_poll)); - } - else if (!strncmp("dhd_watchdog_ms=", full_param, len_param)) { - dhd_watchdog_ms = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: dhd_watchdog_ms = %d\n", __FUNCTION__, dhd_watchdog_ms)); - } - else if (!strncmp("band=", full_param, len_param)) { - /* Process band: - * band=a for 5GHz only and band=b for 2.4GHz only - */ - if (!strcmp(data, "b")) - conf->band = WLC_BAND_2G; - else if (!strcmp(data, "a")) - conf->band = WLC_BAND_5G; - else - conf->band = WLC_BAND_AUTO; - CONFIG_INFO(("%s: band = %d\n", __FUNCTION__, conf->band)); - } - else if (!strncmp("bw_cap_2g=", full_param, len_param)) { - conf->bw_cap[0] = (uint)simple_strtol(data, NULL, 0); - CONFIG_INFO(("%s: bw_cap_2g = %d\n", __FUNCTION__, conf->bw_cap[0])); - } - else if (!strncmp("bw_cap_5g=", full_param, len_param)) { - conf->bw_cap[1] = (uint)simple_strtol(data, NULL, 0); - CONFIG_INFO(("%s: bw_cap_5g = %d\n", __FUNCTION__, conf->bw_cap[1])); - } - else if (!strncmp("bw_cap=", full_param, len_param)) { - pick_tmp = data; - pch = bcmstrtok(&pick_tmp, " ,.-", 0); - if (pch != NULL) { - conf->bw_cap[0] = (uint32)simple_strtol(pch, NULL, 0); - CONFIG_INFO(("%s: bw_cap 2g = %d\n", __FUNCTION__, conf->bw_cap[0])); - } - pch = bcmstrtok(&pick_tmp, " ,.-", 0); - if (pch != NULL) { - conf->bw_cap[1] = (uint32)simple_strtol(pch, NULL, 0); - CONFIG_INFO(("%s: bw_cap 5g = %d\n", __FUNCTION__, conf->bw_cap[1])); - } - } - else if (!strncmp("ccode=", full_param, len_param)) { - memset(&conf->cspec, 0, sizeof(wl_country_t)); - memcpy(conf->cspec.country_abbrev, data, len_data); - memcpy(conf->cspec.ccode, data, len_data); - CONFIG_INFO(("%s: ccode = %s\n", __FUNCTION__, conf->cspec.ccode)); - } - else if (!strncmp("regrev=", full_param, len_param)) { - conf->cspec.rev = (int32)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: regrev = %d\n", __FUNCTION__, conf->cspec.rev)); - } - else if (!strncmp("channels=", full_param, len_param)) { - pick_tmp = data; - pch = bcmstrtok(&pick_tmp, " ,.-", 0); - i=0; - while (pch != NULL && i<WL_NUMCHANNELS) { - conf->channels.channel[i] = (uint32)simple_strtol(pch, NULL, 10); - pch = bcmstrtok(&pick_tmp, " ,.-", 0); - i++; - } - conf->channels.count = i; - CONFIG_INFO(("%s: channels = ", __FUNCTION__)); - for (i=0; i<conf->channels.count; i++) - CONFIG_INFO(("%d ", conf->channels.channel[i])); - CONFIG_INFO(("\n")); - } - else if (!strncmp("keep_alive_period=", full_param, len_param)) { - conf->keep_alive_period = (uint)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: keep_alive_period = %d\n", __FUNCTION__, - conf->keep_alive_period)); - } - else if (!strncmp("phy_oclscdenable=", full_param, len_param)) { - conf->phy_oclscdenable = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: phy_oclscdenable = %d\n", __FUNCTION__, conf->phy_oclscdenable)); - } - else if (!strncmp("srl=", full_param, len_param)) { - conf->srl = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: srl = %d\n", __FUNCTION__, conf->srl)); - } - else if (!strncmp("lrl=", full_param, len_param)) { - conf->lrl = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: lrl = %d\n", __FUNCTION__, conf->lrl)); - } - else if (!strncmp("bcn_timeout=", full_param, len_param)) { - conf->bcn_timeout= (uint)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: bcn_timeout = %d\n", __FUNCTION__, conf->bcn_timeout)); - } - else if (!strncmp("txbf=", full_param, len_param)) { - conf->txbf = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: txbf = %d\n", __FUNCTION__, conf->txbf)); - } - else if (!strncmp("frameburst=", full_param, len_param)) { - conf->frameburst = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: frameburst = %d\n", __FUNCTION__, conf->frameburst)); - } - else if (!strncmp("disable_proptx=", full_param, len_param)) { - conf->disable_proptx = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: disable_proptx = %d\n", __FUNCTION__, conf->disable_proptx)); - } -#ifdef DHDTCPACK_SUPPRESS - else if (!strncmp("tcpack_sup_mode=", full_param, len_param)) { - conf->tcpack_sup_mode = (uint)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: tcpack_sup_mode = %d\n", __FUNCTION__, conf->tcpack_sup_mode)); - } -#endif - else if (!strncmp("pktprio8021x=", full_param, len_param)) { - conf->pktprio8021x = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: pktprio8021x = %d\n", __FUNCTION__, conf->pktprio8021x)); - } -#if defined(BCMSDIO) || defined(BCMPCIE) - else if (!strncmp("dhd_txbound=", full_param, len_param)) { - dhd_txbound = (uint)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: dhd_txbound = %d\n", __FUNCTION__, dhd_txbound)); - } - else if (!strncmp("dhd_rxbound=", full_param, len_param)) { - dhd_rxbound = (uint)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: dhd_rxbound = %d\n", __FUNCTION__, dhd_rxbound)); - } -#endif - else if (!strncmp("num_different_channels=", full_param, len_param)) { - conf->num_different_channels = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: num_different_channels = %d\n", __FUNCTION__, conf->num_different_channels)); - } - else if (!strncmp("tsq=", full_param, len_param)) { - conf->tsq = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: tsq = %d\n", __FUNCTION__, conf->tsq)); - } - else if (!strncmp("ctrl_resched=", full_param, len_param)) { - conf->ctrl_resched = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: ctrl_resched = %d\n", __FUNCTION__, conf->ctrl_resched)); - } - else if (!strncmp("dhd_ioctl_timeout_msec=", full_param, len_param)) { - conf->dhd_ioctl_timeout_msec = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: dhd_ioctl_timeout_msec = %d\n", __FUNCTION__, conf->dhd_ioctl_timeout_msec)); - } - else if (!strncmp("wl_preinit=", full_param, len_param)) { - if (!(conf->wl_preinit = kmalloc(len_param, GFP_KERNEL))) { - CONFIG_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - } else { - memset(conf->wl_preinit, 0, len_param); - strcpy(conf->wl_preinit, data); - CONFIG_INFO(("%s: wl_preinit = %s\n", __FUNCTION__, conf->wl_preinit)); - } - } - else if (!strncmp("hostwake_evt_timeout=", full_param, len_param)) { - conf->hostwake_evt_timeout = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: hostwake_evt_timeout = %d\n", __FUNCTION__, conf->hostwake_evt_timeout)); - } - else if (!strncmp("roam_btm_exclude=", full_param, len_param)) { - if (!strncmp(data, "1", 1)) - conf->roam_btm_exclude = TRUE; - else - conf->roam_btm_exclude = FALSE; - CONFIG_INFO(("%s: roam_btm_exclude = %d\n", __FUNCTION__, conf->roam_btm_exclude)); - } - else if (!strncmp("bcntrim=", full_param, len_param)) { - conf->bcntrim = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: bcntrim = %d\n", __FUNCTION__, conf->bcntrim)); - } -#ifdef UART_HB_CONFIG - else if (!strncmp("heartbeat_conf=", full_param, len_param)) { - conf->heartbeat_conf = (uint32)simple_strtol(data, NULL, 16); - CONFIG_INFO(("%s: heartbeat_conf = 0x%06x\n", __FUNCTION__, conf->heartbeat_conf)); - } - else if (!strncmp("heartbeat_enable=", full_param, len_param)) { - if (!strncmp(data, "1", 1)) - conf->heartbeat_enable = TRUE; - else - conf->heartbeat_enable = FALSE; - CONFIG_INFO(("%s: heartbeat_enable = %d\n", __FUNCTION__, conf->heartbeat_enable)); - } - else if (!strncmp("cons_uart_enable=", full_param, len_param)) { - if (!strncmp(data, "1", 1)) - conf->cons_uart_enable = TRUE; - else - conf->cons_uart_enable = FALSE; - CONFIG_INFO(("%s: cons_uart_enable = %d\n", __FUNCTION__, conf->cons_uart_enable)); - } -#endif /* UART_HB_CONFIG */ -#ifdef HAL_API - else if (!strncmp("max_sleep_ms=", full_param, len_param)) { - conf->max_sleep_ms = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: max_sleep_ms = %d\n", __FUNCTION__, conf->max_sleep_ms)); - } - else if (!strncmp("scan_nprobes=", full_param, len_param)) { - conf->scan_nprobes = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: scan_nprobes = %d\n", __FUNCTION__, conf->scan_nprobes)); - } - else if (!strncmp("bcn_trace_thresh=", full_param, len_param)) { - conf->bcn_trace_thresh = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: bcn_trace_thresh = %d\n", __FUNCTION__, conf->bcn_trace_thresh)); - } - else if (!strncmp("pretbtt_adjust=", full_param, len_param)) { - conf->pretbtt_adjust = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: pretbtt_adjust = %d\n", __FUNCTION__, conf->pretbtt_adjust)); - } - else if (!strncmp("indoor_regrev=", full_param, len_param)) { - conf->indoor_regrev = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: indoor regrev = %d\n", __FUNCTION__, conf->indoor_regrev)); - } - else if (!strncmp("outdoor_regrev=", full_param, len_param)) { - conf->outdoor_regrev = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: outdoor regrev = %d\n", __FUNCTION__, conf->outdoor_regrev)); - } - else if (!strncmp("default_reg_location=", full_param, len_param)) { - if (!strcmp(data, "indoor")) - conf->default_reg_location = REG_LOCATION_INDOOR; - else if (!strcmp(data, "outdoor")) - conf->default_reg_location = REG_LOCATION_OUTDOOR; - CONFIG_INFO(("%s: default reg location = %d\n", __FUNCTION__, - conf->default_reg_location)); - } - else if (!strncmp("force_full_scan=", full_param, len_param)) { - conf->force_full_scan = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: force_full_scan = %d\n", __FUNCTION__, conf->force_full_scan)); - } - else if (!strncmp("ps_resend_mode=", full_param, len_param)) { - conf->ps_resend_mode = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: ps_resend_mode = %d\n", __FUNCTION__, conf->ps_resend_mode)); - } - else if (!strncmp("rrm_bcn_req_thrtl_win=", full_param, len_param)) { - conf->rrm_bcn_req_thrtl_win = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: rrm_bcn_req_thrtl_win = %d\n", __FUNCTION__, conf->rrm_bcn_req_thrtl_win)); - } - else if (!strncmp("force_flush_txq=", full_param, len_param)) { - conf->force_flush_txq = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: force_flush_txq = %d\n", __FUNCTION__, conf->force_flush_txq)); - } -#endif /* HAL_API */ -#ifdef ASSOC_PREFER_BAND - else if (!strncmp("assoc_pref=", full_param, len_param)) { - if (!strncmp(data, "a", 1)) - conf->assoc_pref = WLC_BAND_5G; - else if (!strncmp(data, "b", 1)) - conf->assoc_pref = WLC_BAND_2G; - else - conf->assoc_pref = WLC_BAND_AUTO; - CONFIG_INFO(("%s: assoc_pref = %d\n", __FUNCTION__, conf->assoc_pref)); - } - else if (!strncmp("assoc_pref_rssi_thresh=", full_param, len_param)) { - conf->assoc_pref_rssi_thresh = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: assoc_pref_rssi_thresh = %d\n", __FUNCTION__, - conf->assoc_pref_rssi_thresh)); - } -#endif /* ASSOC_PREFER_BAND */ -#ifdef BCOL_TCPKA_SYNC - else if (!strncmp("tcpka_auto_rst=", full_param, len_param)) { - if (!strncmp(data, "1", 1)) - conf->tcpka_auto_rst = TRUE; - else - conf->tcpka_auto_rst = FALSE; - CONFIG_INFO(("%s: tcpka_auto_rst = %d\n", __FUNCTION__, conf->tcpka_auto_rst)); - } - else if (!strncmp("tcpka_tx=", full_param, len_param)) { - if (!strncmp(data, "1", 1)) - conf->tcpka_tx = TRUE; - else - conf->tcpka_tx = FALSE; - CONFIG_INFO(("%s: tcpka_tx = %d\n", __FUNCTION__, conf->tcpka_tx)); - } - else if (!strncmp("tcpka_wake_rst=", full_param, len_param)) { - if (!strncmp(data, "1", 1)) - conf->tcpka_wake_rst = TRUE; - else - conf->tcpka_wake_rst = FALSE; - CONFIG_INFO(("%s: tcpka_wake_rst = %d\n", __FUNCTION__, conf->tcpka_wake_rst)); - } -#ifdef TCPKA_REPAIR - else if (!strncmp("tcpka_repair=", full_param, len_param)) { - if (!strncmp(data, "1", 1)) { - conf->tcpka_repair = TRUE; - conf->tcpka_wake_rst = FALSE; - } else { - conf->tcpka_repair = FALSE; - } - CONFIG_INFO(("%s: tcpka_repair = %d\n", __FUNCTION__, conf->tcpka_repair)); - } - else if (!strncmp("tcpka_repair_timeout=", full_param, len_param)) { - conf->tcpka_repair_timeout = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: tcpka_repair_timeout = %d\n", __FUNCTION__, - conf->tcpka_repair_timeout)); - } -#endif /* TCPKA_REPAIR */ -#endif /* BCOL_TCPKA_SYNC */ -#ifdef PSPOLL_WAIT - else if (!strncmp("pm_bcmc_wait=", full_param, len_param)) { - conf->pm_bcmc_wait = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: pm_bcmc_wait = %d\n", __FUNCTION__, conf->pm_bcmc_wait)); - } - else if (!strncmp("pm_bcmc_moredata_wait=", full_param, len_param)) { - conf->pm_bcmc_moredata_wait = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: pm_bcmc_moredata_wait = %d\n", __FUNCTION__, - conf->pm_bcmc_moredata_wait)); - } - else if (!strncmp("pspoll_wait=", full_param, len_param)) { - conf->pspoll_wait = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: pspoll_wait = %d\n", __FUNCTION__, conf->pspoll_wait)); - } -#endif /* PSPOLL_WAIT */ -#ifdef PSPOLL_KA_WAIT - else if (!strncmp("pspoll_ka_wait=", full_param, len_param)) { - conf->pspoll_ka_wait = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: pspoll_ka_wait = %d\n", __FUNCTION__, conf->pspoll_ka_wait)); - } - else if (!strncmp("pspoll_ka_restrict=", full_param, len_param)) { - conf->pspoll_ka_restrict = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: pspoll_ka_restrict = %d\n", __FUNCTION__, conf->pspoll_ka_restrict)); - } -#endif /* PSPOLL_KA_WAIT */ -#ifdef PM_KEEP_ALIVE - else if (!strncmp("pm_keep_alive=", full_param, len_param)) { - conf->pm_keep_alive = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: pm_keep_alive = %d\n", __FUNCTION__, conf->pm_keep_alive)); - } -#endif /* PM_KEEP_ALIVE */ -#ifdef GARP_KEEP_ALIVE - else if (!strncmp("garp_enable=", full_param, len_param)) { - conf->garp_enable = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: garp_enable = %d\n", __FUNCTION__, conf->garp_enable)); - } -#endif /* GARP_KEEP_ALIVE */ -#ifdef BLOCK_LIST_CFG - else if (!strncmp("block_list_cnt=", full_param, len_param)) { - conf->block_list_cnt = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: block_list_cnt = %d\n", __FUNCTION__, conf->block_list_cnt)); - } - else if (!strncmp("block_list_tmo=", full_param, len_param)) { - conf->block_list_tmo = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: block_list_tmo = %d\n", __FUNCTION__, conf->block_list_tmo)); - } - else if (!strncmp("block_list_dhcp_tmo=", full_param, len_param)) { - conf->block_list_dhcp_tmo = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: block_list_dhcp_tmo = %d\n", - __FUNCTION__, conf->block_list_dhcp_tmo)); - } -#endif /* BLOCK_LIST_CFG */ -#ifdef RELOAD_WIFI - else if (!strncmp("fw_reload_reinit_thresh=", full_param, len_param)) { - conf->fw_reload_reinit_thresh = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: fw_reload_reinit_thresh = %d\n", - __FUNCTION__, conf->fw_reload_reinit_thresh)); - } -#endif /* RELOAD_WIFI */ -#ifdef NOTI_BITBANG - else if (!strncmp("noti_sample_delay=", full_param, len_param)) { - conf->noti_sample_delay = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: noti_sample_delay = %d\n", - __FUNCTION__, conf->noti_sample_delay)); - } - else if (!strncmp("noti_sample_bits=", full_param, len_param)) { - conf->noti_sample_bits = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: noti_sample_bits = %d\n", - __FUNCTION__, conf->noti_sample_bits)); - } - else if (!strncmp("bcol_noti_enab=", full_param, len_param)) { - conf->bcol_noti_enab = (int)simple_strtol(data, NULL, 10); - CONFIG_INFO(("%s: bcol_noti_enab = %d\n", - __FUNCTION__, conf->bcol_noti_enab)); - } -#endif /* NOTI_BITBANG */ - else - return false; - - return true; -} - -int -dhd_conf_read_config(dhd_pub_t *dhd, char *conf_path) -{ - int bcmerror = -1; - uint len = 0, start_pos=0; - void *image = NULL; - char *memblock = NULL; - char *bufp, *pick = NULL, *pch; - bool conf_file_exists; - uint len_param; - - conf_file_exists = ((conf_path != NULL) && (conf_path[0] != '\0')); - if (!conf_file_exists) { - CONFIG_ERROR(("%s: config path %s\n", __FUNCTION__, conf_path)); - return (0); - } - - if (conf_file_exists) { - image = dhd_os_open_image(conf_path); - if (image == NULL) { - CONFIG_ERROR(("%s: Ignore config file %s\n", __FUNCTION__, conf_path)); - goto err; - } - } - - memblock = MALLOC(dhd->osh, MAXSZ_CONFIG); - if (memblock == NULL) { - CONFIG_ERROR(("%s: Failed to allocate memory %d bytes\n", - __FUNCTION__, MAXSZ_CONFIG)); - goto err; - } - - pick = MALLOC(dhd->osh, MAXSZ_BUF); - if (!pick) { - CONFIG_ERROR(("%s: Failed to allocate memory %d bytes\n", - __FUNCTION__, MAXSZ_BUF)); - goto err; - } - - /* Read variables */ - if (conf_file_exists) { - len = dhd_os_get_image_block(memblock, MAXSZ_CONFIG, image); - } - if (len > 0 && len < MAXSZ_CONFIG) { - bufp = (char *)memblock; - bufp[len] = 0; - - while (start_pos < len) { - memset(pick, 0, MAXSZ_BUF); - start_pos = pick_config_vars(bufp, len, start_pos, pick); - pch = strchr(pick, '='); - if (pch != NULL) { - len_param = pch-pick+1; - if (len_param == strlen(pick)) { - CONFIG_ERROR(("%s: not a right parameter %s\n", __FUNCTION__, pick)); - continue; - } - } else { - CONFIG_ERROR(("%s: not a right parameter %s\n", __FUNCTION__, pick)); - continue; - } - - if (dhd_conf_read_log_level(dhd, pick, len_param)) - continue; - else if (dhd_conf_read_roam_params(dhd, pick, len_param)) - continue; - else if (dhd_conf_read_wme_ac_params(dhd, pick, len_param)) - continue; - else if (dhd_conf_read_fw_by_mac(dhd, pick, len_param)) - continue; - else if (dhd_conf_read_nv_by_mac(dhd, pick, len_param)) - continue; - else if (dhd_conf_read_nv_by_chip(dhd, pick, len_param)) - continue; - else if (dhd_conf_read_country_list(dhd, pick, len_param)) - continue; - else if (dhd_conf_read_mchan_params(dhd, pick, len_param)) - continue; -#ifdef PKT_FILTER_SUPPORT - else if (dhd_conf_read_pkt_filter(dhd, pick, len_param)) - continue; -#endif /* PKT_FILTER_SUPPORT */ -#ifdef IAPSTA_PREINIT - else if (dhd_conf_read_iapsta(dhd, pick, len_param)) - continue; -#endif /* IAPSTA_PREINIT */ -#ifdef IDHCP - else if (dhd_conf_read_dhcp_params(dhd, pick, len_param)) - continue; -#endif /* IDHCP */ -#ifdef BCMSDIO - else if (dhd_conf_read_sdio_params(dhd, pick, len_param)) - continue; -#endif /* BCMSDIO */ -#ifdef BCMPCIE - else if (dhd_conf_read_pcie_params(dhd, pick, len_param)) - continue; -#endif /* BCMPCIE */ - else if (dhd_conf_read_pm_params(dhd, pick, len_param)) - continue; - else if (dhd_conf_read_others(dhd, pick, len_param)) - continue; - else - continue; - } - - bcmerror = 0; - } else { - CONFIG_ERROR(("%s: error reading config file: %d\n", __FUNCTION__, len)); - bcmerror = BCME_SDIO_ERROR; - } - -err: - if (pick) - MFREE(dhd->osh, pick, MAXSZ_BUF); - - if (memblock) - MFREE(dhd->osh, memblock, MAXSZ_CONFIG); - - if (image) - dhd_os_close_image(image); - - return bcmerror; -} - -int -dhd_conf_read_regulatory(dhd_pub_t *dhd, char *reg_path) -{ - return dhd_conf_read_config(dhd, reg_path); -} - -int -dhd_conf_set_chiprev(dhd_pub_t *dhd, uint chip, uint chiprev) -{ - CONFIG_INFO(("%s: chip=0x%x, chiprev=%d\n", __FUNCTION__, chip, chiprev)); - dhd->conf->chip = chip; - dhd->conf->chiprev = chiprev; - return 0; -} - -uint -dhd_conf_get_chip(void *context) -{ - dhd_pub_t *dhd = context; - - if (dhd && dhd->conf) - return dhd->conf->chip; - return 0; -} - -uint -dhd_conf_get_chiprev(void *context) -{ - dhd_pub_t *dhd = context; - - if (dhd && dhd->conf) - return dhd->conf->chiprev; - return 0; -} - -#ifdef BCMSDIO -void -dhd_conf_set_txglom_params(dhd_pub_t *dhd, bool enable) -{ - struct dhd_conf *conf = dhd->conf; - - if (enable) { -#if defined(BCMSDIOH_TXGLOM_EXT) - if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID || - conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID || - conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID) { - conf->txglom_mode = SDPCM_TXGLOM_CPY; - } -#endif - // other parameters set in preinit or config.txt - } else { - // clear txglom parameters - conf->txglom_ext = FALSE; - conf->txglom_bucket_size = 0; - conf->txglomsize = 0; - conf->deferred_tx_len = 0; - } - if (conf->txglom_ext) - CONFIG_INFO(("%s: txglom_ext=%d, txglom_bucket_size=%d\n", __FUNCTION__, - conf->txglom_ext, conf->txglom_bucket_size)); - CONFIG_INFO(("%s: txglom_mode=%s\n", __FUNCTION__, - conf->txglom_mode==SDPCM_TXGLOM_MDESC?"multi-desc":"copy")); - CONFIG_INFO(("%s: txglomsize=%d, deferred_tx_len=%d\n", __FUNCTION__, - conf->txglomsize, conf->deferred_tx_len)); - CONFIG_INFO(("%s: tx_in_rx=%d, txinrx_thres=%d, dhd_txminmax=%d\n", __FUNCTION__, - conf->tx_in_rx, conf->txinrx_thres, conf->dhd_txminmax)); - CONFIG_INFO(("%s: tx_max_offset=%d, txctl_tmo_fix=%d\n", __FUNCTION__, - conf->tx_max_offset, conf->txctl_tmo_fix)); - -} -#endif - -bool -dhd_conf_set_wl_preinit(dhd_pub_t *dhd, char *data) -{ - int cmd, val; - char name[50], *pch, *pick_tmp, *pick_tmp2; - - /* Process wl_preinit: - * wl_preinit=[cmd]/[val], [cmd]/[val] \ - * Ex: wl_preinit=85/0, mpc/0 - */ - pick_tmp = data; - while (pick_tmp && (pick_tmp2 = bcmstrtok(&pick_tmp, ", ", 0)) != NULL) { - pch = bcmstrtok(&pick_tmp2, "=", 0); - if (!pch) - break; - memset(name, 0 , sizeof (name)); - cmd = (int)simple_strtol(pch, NULL, 0); - if (cmd == 0) { - cmd = WLC_SET_VAR; - strcpy(name, pch); - } - pch = bcmstrtok(&pick_tmp2, ", ", 0); - if (!pch) { - break; - } - val = (int)simple_strtol(pch, NULL, 0); - dhd_conf_set_intiovar(dhd, cmd, name, val, -1, TRUE); - } - - return true; -} - -void -dhd_conf_postinit_ioctls(dhd_pub_t *dhd) -{ - struct dhd_conf *conf = dhd->conf; - - dhd_conf_set_intiovar(dhd, WLC_UP, "up", 0, 0, FALSE); - dhd_conf_map_country_list(dhd, &conf->cspec, 0, -1); - dhd_conf_set_country(dhd, &conf->cspec); - dhd_conf_fix_country(dhd); - dhd_conf_get_country(dhd, &dhd->dhd_cspec); - - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "hostwake_evt_timeout", - conf->hostwake_evt_timeout, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "roam_btm_exclude", - conf->roam_btm_exclude, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bcntrim", - conf->bcntrim, 0, FALSE); -#ifdef UART_HB_CONFIG - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "wowl_alive_conf", - (char *)&conf->heartbeat_conf, - sizeof(conf->heartbeat_conf), FALSE); - dhd->wowl_alive = 0; - if (conf->heartbeat_enable) - dhd->wowl_alive |= WOWL_ALIVE_HB; - if (conf->cons_uart_enable) - dhd->wowl_alive |= WOWL_ALIVE_UART; - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "wowl_alive", - dhd->wowl_alive, 0, FALSE); -#endif /* UART_HB_CONFIG */ -#ifdef HAL_API - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "scan_nprobes", - conf->scan_nprobes, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "max_sleep_ms", - conf->max_sleep_ms, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "assoc_listen", - (int)((conf->max_sleep_ms / 100) + 1), 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bcn_trace_thresh", - conf->bcn_trace_thresh, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "pretbtt_adjust", - conf->pretbtt_adjust, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "pm_in_suspend", - conf->pm_in_suspend, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "pm2_sleep_ret_in_suspend", - conf->pm2_sleep_ret_in_suspend, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "pm_in_resume", - conf->pm, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "pm2_sleep_ret_in_resume", - conf->pm2_sleep_ret_in_resume, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "force_full_scan", - conf->force_full_scan, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "ps_resend_mode", - conf->ps_resend_mode, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "rrm_bcn_req_thrtl_win", - conf->rrm_bcn_req_thrtl_win, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "force_flush_txq", - conf->force_flush_txq, 0, FALSE); -#endif /* HAL_API */ -#ifdef PSPOLL_WAIT - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "pm_bcmc_wait", - conf->pm_bcmc_wait, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "pm_bcmc_moredata_wait", - conf->pm_bcmc_moredata_wait, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "pspoll_wait", - conf->pspoll_wait, 0, FALSE); -#endif /* PSPOLL_WAIT */ -#ifdef PSPOLL_KA_WAIT - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "pspoll_ka_wait", - conf->pspoll_ka_wait, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "pspoll_ka_restrict", - conf->pspoll_ka_restrict, 0, FALSE); -#endif /* PSPOLL_KA_WAIT */ -#ifdef PM_KEEP_ALIVE - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "pm_keep_alive", - conf->pm_keep_alive, 0, FALSE); -#endif /* PM_KEEP_ALIVE */ -#ifdef GARP_KEEP_ALIVE - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "garp_enable", - conf->garp_enable, 0, FALSE); -#endif /* GARP_KEEP_ALIVE */ -#ifdef BLOCK_LIST_CFG - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "block_list_cnt", - conf->block_list_cnt, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "block_list_tmo", - conf->block_list_tmo, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "block_list_dhcp_tmo", - conf->block_list_dhcp_tmo, 0, FALSE); -#endif /* BLOCK_LIST_CFG */ -#ifdef NOTI_BITBANG - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "noti_sample_delay", - conf->noti_sample_delay, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "noti_sample_bits", - conf->noti_sample_bits, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bcol_noti_enab", - conf->bcol_noti_enab, 0, FALSE); -#endif /* NOTI_BITBANG */ -#ifdef RELOAD_WIFI - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "fw_reload_reinit_thresh", - conf->fw_reload_reinit_thresh, 0, FALSE); -#endif /* RELOAD_WIFI */ -#ifdef ASSOC_PREFER_BAND - dhd_conf_set_intiovar(dhd, WLC_SET_ASSOC_PREFER, "assoc_pref", conf->assoc_pref, 0, FALSE); - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "assoc_pref_rssi_thresh", - (char *)&conf->assoc_pref_rssi_thresh, - sizeof(conf->assoc_pref_rssi_thresh), FALSE); -#endif /* ASSOC_PREFER_BAND */ -#ifdef BCOL_TCPKA_SYNC - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "tcpka_auto_rst", - conf->tcpka_auto_rst, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "tcpka_tx_ka", - conf->tcpka_tx, 0, FALSE); -#ifdef TCPKA_REPAIR - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "tcpka_conn_repair", - conf->tcpka_repair, 0, FALSE); - if (conf->tcpka_repair) { - conf->tcpka_wake_rst = FALSE; - } -#endif /* TCPKA_REPAIR */ - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "tcpka_wake_rst", - conf->tcpka_wake_rst, 0, FALSE); -#endif /* BCOL_TCPKA_SYNC */ - dhd_conf_set_intiovar(dhd, WLC_SET_BAND, "WLC_SET_BAND", conf->band, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bcn_timeout", conf->bcn_timeout, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_PM, "PM", conf->pm, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_SRL, "WLC_SET_SRL", conf->srl, 0, TRUE); - dhd_conf_set_intiovar(dhd, WLC_SET_LRL, "WLC_SET_LRL", conf->lrl, 0, FALSE); - dhd_conf_set_bw_cap(dhd); - dhd_conf_set_roam(dhd); - -#if defined(BCMPCIE) - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "bus:deepsleep_disable", - conf->bus_deepsleep_disable, 0, FALSE); -#endif /* defined(BCMPCIE) */ - -#ifdef IDHCP - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "dhcpc_enable", conf->dhcpc_enable, 0, FALSE); - if (dhd->conf->dhcpd_enable >= 0) { - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_addr", - (char *)&conf->dhcpd_ip_addr, sizeof(conf->dhcpd_ip_addr), FALSE); - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_mask", - (char *)&conf->dhcpd_ip_mask, sizeof(conf->dhcpd_ip_mask), FALSE); - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_start", - (char *)&conf->dhcpd_ip_start, sizeof(conf->dhcpd_ip_start), FALSE); - dhd_conf_set_bufiovar(dhd, WLC_SET_VAR, "dhcpd_ip_end", - (char *)&conf->dhcpd_ip_end, sizeof(conf->dhcpd_ip_end), FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "dhcpd_enable", - conf->dhcpd_enable, 0, FALSE); - } -#endif - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "txbf", conf->txbf, 0, FALSE); - dhd_conf_set_intiovar(dhd, WLC_SET_FAKEFRAG, "WLC_SET_FAKEFRAG", conf->frameburst, 0, FALSE); - - dhd_conf_set_wl_preinit(dhd, conf->wl_preinit); - -#ifndef WL_CFG80211 - dhd_conf_set_intiovar(dhd, WLC_UP, "up", 0, 0, FALSE); -#endif - -} - -int -dhd_conf_preinit(dhd_pub_t *dhd) -{ - struct dhd_conf *conf = dhd->conf; - int i; - - CONFIG_TRACE(("%s: Enter\n", __FUNCTION__)); - -#ifdef BCMSDIO - dhd_conf_free_mac_list(&conf->fw_by_mac); - dhd_conf_free_mac_list(&conf->nv_by_mac); - dhd_conf_free_chip_nv_path_list(&conf->nv_by_chip); -#endif - dhd_conf_free_country_list(&conf->country_list); - dhd_conf_free_country_list(&conf->country_list_nodfs); - if (conf->magic_pkt_filter_add) - kfree(conf->magic_pkt_filter_add); - if (conf->wl_preinit) - kfree(conf->wl_preinit); - memset(&conf->country_list, 0, sizeof(conf_country_list_t)); - conf->band = -1; - memset(&conf->bw_cap, -1, sizeof(conf->bw_cap)); - if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID) { - strcpy(conf->cspec.country_abbrev, "ALL"); - strcpy(conf->cspec.ccode, "ALL"); - conf->cspec.rev = 0; - } else if (conf->chip == BCM4335_CHIP_ID || conf->chip == BCM4339_CHIP_ID || - conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID || - conf->chip == BCM4345_CHIP_ID || conf->chip == BCM4371_CHIP_ID || - conf->chip == BCM43569_CHIP_ID || conf->chip == BCM4359_CHIP_ID || - conf->chip == BCM4362_CHIP_ID) { - strcpy(conf->cspec.country_abbrev, "CN"); - strcpy(conf->cspec.ccode, "CN"); - conf->cspec.rev = 38; - } else { - strcpy(conf->cspec.country_abbrev, "US"); - strcpy(conf->cspec.ccode, "US"); - conf->cspec.rev = 0; - } - memset(&conf->channels, 0, sizeof(wl_channel_list_t)); - conf->roam_off = 1; - conf->roam_off_suspend = 1; -#ifdef CUSTOM_ROAM_TRIGGER_SETTING - conf->roam_trigger[0] = CUSTOM_ROAM_TRIGGER_SETTING; -#else - conf->roam_trigger[0] = -65; -#endif - conf->roam_trigger[1] = WLC_BAND_ALL; - conf->roam_scan_period[0] = 10; - conf->roam_scan_period[1] = WLC_BAND_ALL; -#ifdef CUSTOM_ROAM_DELTA_SETTING - conf->roam_delta[0] = CUSTOM_ROAM_DELTA_SETTING; -#else - conf->roam_delta[0] = 15; -#endif - conf->roam_delta[1] = WLC_BAND_ALL; -#ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC - conf->fullroamperiod = 60; -#else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ - conf->fullroamperiod = 120; -#endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ -#ifdef CUSTOM_KEEP_ALIVE_SETTING - conf->keep_alive_period = CUSTOM_KEEP_ALIVE_SETTING; -#else - conf->keep_alive_period = 28000; -#endif - conf->force_wme_ac = 0; - memset(&conf->wme_sta, 0, sizeof(wme_param_t)); - memset(&conf->wme_ap, 0, sizeof(wme_param_t)); - conf->phy_oclscdenable = -1; -#ifdef PKT_FILTER_SUPPORT - memset(&conf->pkt_filter_add, 0, sizeof(conf_pkt_filter_add_t)); - memset(&conf->pkt_filter_del, 0, sizeof(conf_pkt_filter_del_t)); -#endif - conf->srl = -1; - conf->lrl = -1; - conf->bcn_timeout = 16; - conf->txbf = -1; - conf->disable_proptx = -1; - conf->dhd_poll = -1; -#ifdef BCMSDIO - conf->use_rxchain = 0; - conf->bus_rxglom = TRUE; - conf->txglom_ext = FALSE; - conf->tx_max_offset = 0; - conf->txglomsize = SDPCM_DEFGLOM_SIZE; - conf->txctl_tmo_fix = 300; - conf->tx_in_rx = TRUE; - conf->txglom_mode = SDPCM_TXGLOM_MDESC; - conf->deferred_tx_len = 0; - conf->dhd_txminmax = 1; - conf->txinrx_thres = -1; - conf->sd_f2_blocksize = 0; - conf->oob_enabled_later = FALSE; - conf->orphan_move = 0; -#endif -#ifdef BCMPCIE - conf->bus_deepsleep_disable = 1; -#endif - conf->dpc_cpucore = -1; - conf->rxf_cpucore = -1; - conf->frameburst = -1; - conf->deepsleep = FALSE; - conf->pm = -1; - conf->pm_in_suspend = -1; - conf->pm2_sleep_ret_in_suspend = -1; - conf->pm2_sleep_ret_in_resume = -1; - conf->suspend_bcn_li_dtim = -1; - conf->num_different_channels = -1; - conf->xmit_in_suspend = TRUE; - conf->ap_in_suspend = 0; -#ifdef SUSPEND_EVENT - conf->suspend_eventmask_enable = FALSE; - memset(&conf->suspend_eventmask, 0, sizeof(conf->suspend_eventmask)); - memset(&conf->resume_eventmask, 0, sizeof(conf->resume_eventmask)); -#endif -#ifdef IDHCP - conf->dhcpc_enable = -1; - conf->dhcpd_enable = -1; -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) - conf->tsq = 10; -#else - conf->tsq = 0; -#endif -#ifdef DHDTCPACK_SUPPRESS -#ifdef BCMPCIE - conf->tcpack_sup_mode = TCPACK_SUP_DEFAULT; -#else - conf->tcpack_sup_mode = TCPACK_SUP_OFF; -#endif -#endif - conf->pktprio8021x = -1; - conf->ctrl_resched = 2; - conf->dhd_ioctl_timeout_msec = 0; -#ifdef IAPSTA_PREINIT - memset(conf->iapsta_init, 0, sizeof(conf->iapsta_init)); - memset(conf->iapsta_config, 0, sizeof(conf->iapsta_config)); - memset(conf->iapsta_enable, 0, sizeof(conf->iapsta_enable)); -#endif - for (i=0; i<MCHAN_MAX_NUM; i++) { - memset(&conf->mchan[i], -1, sizeof(mchan_params_t)); - } - if (conf->chip == BCM4354_CHIP_ID || conf->chip == BCM4356_CHIP_ID || - conf->chip == BCM4371_CHIP_ID || conf->chip == BCM43569_CHIP_ID || - conf->chip == BCM4359_CHIP_ID || conf->chip == BCM4362_CHIP_ID) { -#ifdef DHDTCPACK_SUPPRESS -#ifdef BCMSDIO - conf->tcpack_sup_mode = TCPACK_SUP_REPLACE; -#endif -#endif -#if defined(BCMSDIO) || defined(BCMPCIE) - dhd_rxbound = 128; - dhd_txbound = 64; -#endif - conf->txbf = 1; - conf->frameburst = 1; -#ifdef BCMSDIO - conf->dhd_txminmax = -1; - conf->txinrx_thres = 128; - conf->sd_f2_blocksize = CUSTOM_SDIO_F2_BLKSIZE; - conf->oob_enabled_later = TRUE; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) - conf->orphan_move = 1; -#else - conf->orphan_move = 0; -#endif -#endif - } - -#ifdef BCMSDIO -#if defined(BCMSDIOH_TXGLOM_EXT) - if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID || - conf->chip == BCM43340_CHIP_ID || conf->chip == BCM43341_CHIP_ID || - conf->chip == BCM4334_CHIP_ID || conf->chip == BCM4324_CHIP_ID) { - conf->txglom_ext = TRUE; - } else { - conf->txglom_ext = FALSE; - } - if (conf->chip == BCM43362_CHIP_ID || conf->chip == BCM4330_CHIP_ID) { - conf->txglom_bucket_size = 1680; // fixed value, don't change - conf->txglomsize = 6; - } - if (conf->chip == BCM4334_CHIP_ID || conf->chip == BCM43340_CHIP_ID || - conf->chip == BCM43341_CHIP_ID || conf->chip == BCM4324_CHIP_ID) { - conf->txglom_bucket_size = 1684; // fixed value, don't change - conf->txglomsize = 16; - } -#endif - if (conf->txglomsize > SDPCM_MAXGLOM_SIZE) - conf->txglomsize = SDPCM_MAXGLOM_SIZE; -#endif -#ifdef HOSTWAKE_EVENT_TIMEOUT - conf->hostwake_evt_timeout = HOSTWAKE_EVENT_TIMEOUT; -#endif /* HOSTWAKE_EVENT_TIMEOUT */ -#ifdef UART_HB_CONFIG - /* 2 seconds delay, 2 seconds interval, pattern 0x55 */ - conf->heartbeat_conf = 0x020255; - conf->heartbeat_enable = FALSE; - conf->cons_uart_enable = FALSE; -#endif /* UART_HB_CONFIG */ -#ifdef HAL_API - /* bi = 102.4 ms, 1024 = 10 bi */ - conf->max_sleep_ms = 1024; - conf->scan_nprobes = 5; - conf->bcn_trace_thresh = -1; - conf->pretbtt_adjust = -1; - conf->indoor_regrev = -1; - conf->outdoor_regrev = -1; - conf->default_reg_location = REG_LOCATION_UNKNOWN; - conf->force_full_scan = 0; - conf->ps_resend_mode = -1; - conf->rrm_bcn_req_thrtl_win = -1; - conf->force_flush_txq = -1; -#endif /* HAL_API */ -#ifdef ASSOC_PREFER_BAND - conf->assoc_pref = WLC_BAND_5G; - conf->assoc_pref_rssi_thresh = -70; -#endif /* ASSOC_PREFER_BAND */ -#ifdef BCOL_TCPKA_SYNC - conf->tcpka_auto_rst = FALSE; - conf->tcpka_tx = FALSE; - conf->tcpka_wake_rst = FALSE; -#ifdef TCPKA_REPAIR - conf->tcpka_repair = FALSE; - conf->tcpka_repair_timeout = 5; -#endif /* TCPKA_REPAIR */ -#endif /* BCOL_TCPKA_SYNC */ -#ifdef PSPOLL_WAIT - conf->pm_bcmc_wait = -1; - conf->pm_bcmc_moredata_wait = -1; - conf->pspoll_wait = -1; -#endif /* PSPOLL_WAIT */ -#ifdef PSPOLL_KA_WAIT - conf->pspoll_ka_wait = -1; - conf->pspoll_ka_restrict = -1; -#endif /* PSPOLL_KA_WAIT */ -#ifdef PM_KEEP_ALIVE - conf->pm_keep_alive = FALSE; -#endif /* PM_KEEP_ALIVE */ -#ifdef GARP_KEEP_ALIVE - conf->garp_enable = FALSE; -#endif /* GARP_KEEP_ALIVE */ -#ifdef BLOCK_LIST_CFG - conf->block_list_cnt = -1; - conf->block_list_tmo = -1; - conf->block_list_dhcp_tmo = -1; -#endif /* BLOCK_LIST_CFG */ -#ifdef NOTI_BITBANG - conf->noti_sample_delay = -1; - conf->noti_sample_bits = -1; - conf->bcol_noti_enab = -1; -#endif /* NOTI_BITBANG */ -#ifdef RELOAD_WIFI - conf->fw_reload_reinit_thresh = -1; -#endif /* RELOAD_WIFI */ - return 0; -} - -int -dhd_conf_reset(dhd_pub_t *dhd) -{ -#ifdef BCMSDIO - dhd_conf_free_mac_list(&dhd->conf->fw_by_mac); - dhd_conf_free_mac_list(&dhd->conf->nv_by_mac); - dhd_conf_free_chip_nv_path_list(&dhd->conf->nv_by_chip); -#endif - dhd_conf_free_country_list(&dhd->conf->country_list); - dhd_conf_free_country_list(&dhd->conf->country_list_nodfs); - if (dhd->conf->magic_pkt_filter_add) - kfree(dhd->conf->magic_pkt_filter_add); - if (dhd->conf->wl_preinit) - kfree(dhd->conf->wl_preinit); - memset(dhd->conf, 0, sizeof(dhd_conf_t)); - return 0; -} - -int -dhd_conf_attach(dhd_pub_t *dhd) -{ - dhd_conf_t *conf; - - CONFIG_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (dhd->conf != NULL) { - CONFIG_ERROR(("%s: config is attached before!\n", __FUNCTION__)); - return 0; - } - /* Allocate private bus interface state */ - if (!(conf = MALLOC(dhd->osh, sizeof(dhd_conf_t)))) { - CONFIG_ERROR(("%s: MALLOC failed\n", __FUNCTION__)); - goto fail; - } - memset(conf, 0, sizeof(dhd_conf_t)); - - dhd->conf = conf; - - return 0; - -fail: - if (conf != NULL) - MFREE(dhd->osh, conf, sizeof(dhd_conf_t)); - return BCME_NOMEM; -} - -void -dhd_conf_detach(dhd_pub_t *dhd) -{ - CONFIG_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (dhd->conf) { -#ifdef BCMSDIO - dhd_conf_free_mac_list(&dhd->conf->fw_by_mac); - dhd_conf_free_mac_list(&dhd->conf->nv_by_mac); - dhd_conf_free_chip_nv_path_list(&dhd->conf->nv_by_chip); -#endif - dhd_conf_free_country_list(&dhd->conf->country_list); - dhd_conf_free_country_list(&dhd->conf->country_list_nodfs); - if (dhd->conf->magic_pkt_filter_add) - kfree(dhd->conf->magic_pkt_filter_add); - if (dhd->conf->wl_preinit) - kfree(dhd->conf->wl_preinit); - MFREE(dhd->osh, dhd->conf, sizeof(dhd_conf_t)); - } - dhd->conf = NULL; -}
diff --git a/bcmdhd.1.579.77.41.x/dhd_config.h b/bcmdhd.1.579.77.41.x/dhd_config.h deleted file mode 100644 index c9756c3..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_config.h +++ /dev/null
@@ -1,349 +0,0 @@ -/* - * Wifi configuration file operation - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_config.h 591129 2015-10-07 05:22:14Z $ - */ - -#ifndef _dhd_config_ -#define _dhd_config_ - -#include <bcmdevs.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 100 -typedef struct conf_country_list { - uint32 count; - wl_country_t *cspec[CONFIG_COUNTRY_LIST_SIZE]; -} conf_country_list_t; - -/* mchan_params */ -#define MCHAN_MAX_NUM 4 -#define MIRACAST_SOURCE 1 -#define MIRACAST_SINK 2 -typedef struct mchan_params { - int bw; - int p2p_mode; - int miracast_mode; -} mchan_params_t; - -typedef struct dhd_conf { - uint chip; - uint chiprev; - int fw_type; - wl_mac_list_ctrl_t fw_by_mac; - wl_mac_list_ctrl_t nv_by_mac; - wl_chip_nv_path_list_ctrl_t nv_by_chip; - conf_country_list_t country_list; - conf_country_list_t country_list_nodfs; - 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; - int force_wme_ac; - wme_param_t wme_sta; - wme_param_t wme_ap; - int phy_oclscdenable; -#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 txbf; - 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 tx_in_rx; - 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) - uint sd_f2_blocksize; - bool oob_enabled_later; - int orphan_move; -#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 pm2_sleep_ret_in_suspend; - int pm2_sleep_ret_in_resume; - int suspend_bcn_li_dtim; -#ifdef DHDTCPACK_SUPPRESS - uint8 tcpack_sup_mode; -#endif - int pktprio8021x; - int num_different_channels; - int xmit_in_suspend; - int ap_in_suspend; -#ifdef SUSPEND_EVENT - bool suspend_eventmask_enable; - char suspend_eventmask[WL_EVENTING_MASK_LEN]; - char resume_eventmask[WL_EVENTING_MASK_LEN]; -#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 IAPSTA_PREINIT - char iapsta_init[50]; - char iapsta_config[300]; - char iapsta_enable[50]; -#endif - int ctrl_resched; - int dhd_ioctl_timeout_msec; - struct mchan_params mchan[MCHAN_MAX_NUM]; - char *wl_preinit; - int tsq; - int hostwake_evt_timeout; - bool roam_btm_exclude; - int bcntrim; -#ifdef UART_HB_CONFIG - uint32 heartbeat_conf; - bool heartbeat_enable; - bool cons_uart_enable; -#endif /* UART_HB_CONFIG */ -#ifdef HAL_API - int max_sleep_ms; - int scan_nprobes; - int bcn_trace_thresh; - int pretbtt_adjust; - int indoor_regrev; - int outdoor_regrev; - int default_reg_location; - int ps_resend_mode; - int rrm_bcn_req_thrtl_win; - int force_flush_txq; -#endif /* HAL_API */ -#ifdef ASSOC_PREFER_BAND - int assoc_pref; - int assoc_pref_rssi_thresh; -#endif /* ASSOC_PREFER_BAND */ -#ifdef BCOL_TCPKA_SYNC - bool tcpka_tx; - bool tcpka_wake_rst; - bool tcpka_auto_rst; -#ifdef TCPKA_REPAIR - bool tcpka_repair; - int tcpka_repair_timeout; -#endif /* TCPKA_REPAIR */ -#endif /* BCOL_TCPKA_SYNC */ -#ifdef PSPOLL_WAIT - int pm_bcmc_wait; - int pm_bcmc_moredata_wait; - int pspoll_wait; -#endif /* PSPOLL_WAIT */ -#ifdef PSPOLL_KA_WAIT - int pspoll_ka_wait; - int pspoll_ka_restrict; -#endif /* PSPOLL_KA_WAIT */ -#ifdef PM_KEEP_ALIVE - int pm_keep_alive; -#endif /* PM_KEEP_ALIVE */ -#ifdef GARP_KEEP_ALIVE - bool garp_enable; -#endif /* GARP_KEEP_ALIVE */ -#ifdef BLOCK_LIST_CFG - int block_list_cnt; - int block_list_tmo; - int block_list_dhcp_tmo; -#endif /* BLOCK_LIST_CFG */ -#ifdef NOTI_BITBANG - int noti_sample_delay; - int noti_sample_bits; - int bcol_noti_enab; -#endif /* NOTI_BITBANG */ -#ifdef RELOAD_WIFI - uint fw_reload_reinit_thresh; -#endif /* RELOAD_WIFI */ - bool force_full_scan; -} dhd_conf_t; - -#ifdef BCMSDIO -int dhd_conf_get_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, uint8 *mac); -void dhd_conf_set_fw_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *fw_path); -void dhd_conf_set_nv_name_by_mac(dhd_pub_t *dhd, bcmsdh_info_t *sdh, char *nv_path); -#if defined(HW_OOB) || defined(FORCE_WOWLAN) -void dhd_conf_set_hw_oob_intr(bcmsdh_info_t *sdh, uint chip); -#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_fw_name_by_chip(dhd_pub_t *dhd, char *fw_path); -void dhd_conf_set_clm_name_by_chip(dhd_pub_t *dhd, char *clm_path); -void dhd_conf_set_nv_name_by_chip(dhd_pub_t *dhd, char *nv_path); -void dhd_conf_set_path(dhd_pub_t *dhd, char *dst_name, char *dst_path, char *src_path); -#ifdef CONFIG_PATH_AUTO_SELECT -void dhd_conf_set_conf_name_by_chip(dhd_pub_t *dhd, char *conf_path); -void dhd_conf_set_reg_name_by_chip(dhd_pub_t *dhd, char *reg_path); -#endif -int dhd_conf_set_intiovar(dhd_pub_t *dhd, uint cmd, char *name, int val, int def, bool down); -int dhd_conf_get_iovar(dhd_pub_t *dhd, int cmd, char *name, char *buf, int len, int ifidx); -int dhd_conf_set_bufiovar(dhd_pub_t *dhd, uint cmd, char *name, char *buf, int len, bool down); -uint 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 nodfs, int location); -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 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_read_regulatory(dhd_pub_t *dhd, char *reg_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); -#ifdef PROP_TXSTATUS -int dhd_conf_get_disable_proptx(dhd_pub_t *dhd); -#endif -int dhd_conf_get_ap_mode_in_suspend(dhd_pub_t *dhd); -int dhd_conf_set_ap_in_suspend(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); -void *dhd_get_conf(struct net_device *dev); -#endif /* _dhd_config_ */
diff --git a/bcmdhd.1.579.77.41.x/dhd_custom_gpio.c b/bcmdhd.1.579.77.41.x/dhd_custom_gpio.c deleted file mode 100644 index 5105104..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_custom_gpio.c +++ /dev/null
@@ -1,299 +0,0 @@ -/* - * Customer code to add GPIO control during WLAN start/stop - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_custom_gpio.c 664997 2016-10-14 11:56:35Z $ - */ - -#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> - -#define WL_ERROR(x) printf x -#define WL_TRACE(x) - -#if defined(OOB_INTR_ONLY) - -#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; - -#if defined(CUSTOMER_HW2) - host_oob_irq = wifi_platform_get_irq_number(adapter, irq_flags_ptr); - -#else -#if defined(CUSTOM_OOB_GPIO_NUM) - if (dhd_oob_gpio_num < 0) { - dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; - } -#endif /* CUSTOMER_OOB_GPIO_NUM */ - - if (dhd_oob_gpio_num < 0) { - WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n", - __FUNCTION__)); - return (dhd_oob_gpio_num); - } - - WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n", - __FUNCTION__, dhd_oob_gpio_num)); - -#endif - - return (host_oob_irq); -} -#endif - -/* Customer function to control hw specific wlan gpios */ -int -dhd_customer_gpio_wlan_ctrl(void *adapter, int onoff) -{ - int err = 0; - - return err; -} - -#ifdef GET_CUSTOM_MAC_ENABLE -/* 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 defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) - ret = wifi_platform_get_mac_addr(adapter, buf); -#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(CUSTOMER_HW2) -#if defined(BCM4335_CHIP) - {"", "XZ", 11}, /* Universal if Country code is unknown or empty */ -#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 */ -#ifdef BCM4330_CHIP - {"RU", "RU", 1}, - {"US", "US", 5} -#endif -#endif -}; - - -/* Customized Locale convertor -* input : ISO 3166-1 country abbreviation -* output: customized cspec -*/ -void -#if defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) -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 /* defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) */ -{ -#if (defined(CUSTOMER_HW) || defined(CUSTOMER_HW2)) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) - - struct cntry_locales_custom *cloc_ptr; - - if (!cspec) - return; -#if defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) - 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 /* defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) */ - - 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) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) */ -}
diff --git a/bcmdhd.1.579.77.41.x/dhd_custom_memprealloc.c b/bcmdhd.1.579.77.41.x/dhd_custom_memprealloc.c deleted file mode 100644 index 1f593a4..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_custom_memprealloc.c +++ /dev/null
@@ -1,513 +0,0 @@ -/* - * Platform Dependent file for usage of Preallocted Memory - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_custom_memprealloc.c 707595 2017-06-28 08:28:30Z $ - */ - -#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_STATIC_STAT_REPORT_BUF 18 - -#define WLAN_SCAN_BUF_SIZE (64 * 1024) - -#if defined(CONFIG_64BIT) -#define WLAN_DHD_INFO_BUF_SIZE (32 * 1024) -#define WLAN_DHD_WLFC_BUF_SIZE (64 * 1024) -#define WLAN_DHD_IF_FLOW_LKUP_SIZE (64 * 1024) -#else -#define WLAN_DHD_INFO_BUF_SIZE (32 * 1024) -#define WLAN_DHD_WLFC_BUF_SIZE (16 * 1024) -#define WLAN_DHD_IF_FLOW_LKUP_SIZE (20 * 1024) -#endif /* CONFIG_64BIT */ -#define WLAN_DHD_MEMDUMP_SIZE (1536 * 1024) - -#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) -#define DHD_LOG_DUMP_BUF_EX_SIZE (8 * 1024) - -#define DHD_PKTLOG_DUMP_BUF_SIZE (64 * 1024) - -#define DHD_STAT_REPORT_BUF_SIZE (128 * 1024) - -#define WLAN_DHD_WLFC_HANGER_MAXITEMS 3072 -#define WLAN_DHD_WLFC_HANGER_ITEM_SIZE 32 -#define WLAN_DHD_WLFC_HANGER_SIZE ((WLAN_DHD_WLFC_HANGER_ITEM_SIZE) + \ - ((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; -static void *wlan_static_stat_report_buf = NULL; - -#define GET_STATIC_BUF(section, config_size, req_size, buf) ({\ - void *__ret; \ - if (req_size > config_size) {\ - pr_err("request " #section " size(%lu) is bigger than" \ - " static size(%d)\n", \ - req_size, config_size); \ - __ret = NULL; \ - } else { __ret = buf;} \ - __ret; \ -}) - -void -*dhd_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 == WLAN_STATIC_STAT_REPORT_BUF) { - return GET_STATIC_BUF(WLAN_STATIC_STAT_REPORT_BUF, - DHD_STAT_REPORT_BUF_SIZE, size, wlan_static_stat_report_buf); - } - - if ((section < 0) || (section >= PREALLOC_WLAN_SEC_NUM)) { - return NULL; - } - - 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; - - 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; - } - } - - 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; - } - } - -#if !defined(CONFIG_BCMDHD_PCIE) - wlan_static_skb[i] = dev_alloc_skb(DHD_SKB_4PAGE_BUFSIZE); - 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; - } - - wlan_static_stat_report_buf = kmalloc(DHD_STAT_REPORT_BUF_SIZE, GFP_KERNEL); - if (!wlan_static_stat_report_buf) { - pr_err("Failed to alloc wlan_static_stat_report_buf\n"); - goto err_mem_alloc; - } - - pr_err("%s: WIFI MEM Allocated\n", __FUNCTION__); - return 0; - -err_mem_alloc: -#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); - } - - if (wlan_static_stat_report_buf) { - kfree(wlan_static_stat_report_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); -#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */
diff --git a/bcmdhd.1.579.77.41.x/dhd_custom_msm.c b/bcmdhd.1.579.77.41.x/dhd_custom_msm.c deleted file mode 100644 index 27399d0..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_custom_msm.c +++ /dev/null
@@ -1,253 +0,0 @@ -/* - * Platform Dependent file for Qualcomm MSM/APQ - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_custom_msm.c 674523 2016-12-09 04:05:27Z $ - * - */ - -#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/mmc/host.h> -#include <linux/msm_pcie.h> -#include <linux/fcntl.h> -#include <linux/fs.h> -#include <linux/of_gpio.h> -#if defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_ARCH_MSM8998) -#include <linux/msm_pcie.h> -#endif /* CONFIG_ARCH_MSM8996 || CONFIG_ARCH_MSM8998 */ - -#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 -static int wlan_reg_on = -1; -#define DHD_DT_COMPAT_ENTRY "android,bcmdhd_wlan" -#ifdef CUSTOMER_HW2 -#define WIFI_WL_REG_ON_PROPNAME "wl_reg_on" -#else -#define WIFI_WL_REG_ON_PROPNAME "wlan-en-gpio" -#endif /* CUSTOMER_HW2 */ - -#if defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_ARCH_MSM8998) -#define MSM_PCIE_CH_NUM 0 -#else -#define MSM_PCIE_CH_NUM 1 -#endif /* CONFIG_ARCH_MSM8996 || CONFIG_ARCH_MSM8998 */ - -#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE -static int wlan_host_wake_up = -1; -static int wlan_host_wake_irq = 0; -#ifdef CUSTOMER_HW2 -#define WIFI_WLAN_HOST_WAKE_PROPNAME "wl_host_wake" -#else -#define WIFI_WLAN_HOST_WAKE_PROPNAME "wlan-host-wake-gpio" -#endif /* CUSTOMER_HW2 */ -#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ - -int __init -dhd_wifi_init_gpio(void) -{ - char *wlan_node = DHD_DT_COMPAT_ENTRY; - struct device_node *root_node = NULL; - - root_node = of_find_compatible_node(NULL, NULL, wlan_node); - if (!root_node) { - WARN(1, "failed to get device node of BRCM WLAN\n"); - return -ENODEV; - } - - /* ========== WLAN_PWR_EN ============ */ - wlan_reg_on = of_get_named_gpio(root_node, WIFI_WL_REG_ON_PROPNAME, 0); - printk(KERN_INFO "%s: gpio_wlan_power : %d\n", __FUNCTION__, wlan_reg_on); - - if (gpio_request_one(wlan_reg_on, GPIOF_OUT_INIT_LOW, "WL_REG_ON")) { - printk(KERN_ERR "%s: Faiiled to request gpio %d for WL_REG_ON\n", - __FUNCTION__, wlan_reg_on); - } else { - printk(KERN_ERR "%s: gpio_request WL_REG_ON done - WLAN_EN: GPIO %d\n", - __FUNCTION__, wlan_reg_on); - } - - if (gpio_direction_output(wlan_reg_on, 1)) { - printk(KERN_ERR "%s: WL_REG_ON failed to pull up\n", __FUNCTION__); - } else { - printk(KERN_ERR "%s: WL_REG_ON is pulled up\n", __FUNCTION__); - } - - if (gpio_get_value(wlan_reg_on)) { - printk(KERN_INFO "%s: Initial WL_REG_ON: [%d]\n", - __FUNCTION__, gpio_get_value(wlan_reg_on)); - } - - /* Wait for WIFI_TURNON_DELAY due to power stability */ - msleep(WIFI_TURNON_DELAY); - -#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE - /* ========== WLAN_HOST_WAKE ============ */ - wlan_host_wake_up = of_get_named_gpio(root_node, WIFI_WLAN_HOST_WAKE_PROPNAME, 0); - printk(KERN_INFO "%s: gpio_wlan_host_wake : %d\n", __FUNCTION__, wlan_host_wake_up); - -#ifndef CUSTOMER_HW2 - if (gpio_request_one(wlan_host_wake_up, GPIOF_IN, "WLAN_HOST_WAKE")) { - printk(KERN_ERR "%s: 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); - } -#endif /* !CUSTOMER_HW2 */ - - gpio_direction_input(wlan_host_wake_up); - wlan_host_wake_irq = gpio_to_irq(wlan_host_wake_up); -#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ - -#if defined(CONFIG_BCM4359) || defined(CONFIG_BCM4361) - printk(KERN_INFO "%s: Call msm_pcie_enumerate\n", __FUNCTION__); - msm_pcie_enumerate(MSM_PCIE_CH_NUM); -#endif /* CONFIG_BCM4359 || CONFIG_BCM4361 */ - - return 0; -} - -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__); - } - } - } else { - if (gpio_direction_output(wlan_reg_on, 0)) { - printk(KERN_ERR "%s: WL_REG_ON is failed to pull up\n", __FUNCTION__); - return -EIO; - } - if (gpio_get_value(wlan_reg_on)) { - printk(KERN_INFO"WL_REG_ON on-step-2 : [%d]\n", - gpio_get_value(wlan_reg_on)); - } - } - return 0; -} -EXPORT_SYMBOL(dhd_wlan_power); - -static int -dhd_wlan_reset(int onoff) -{ - return 0; -} - -static int -dhd_wlan_set_carddetect(int val) -{ - return 0; -} - -struct resource dhd_wlan_resources = { - .name = "bcmdhd_wlan_irq", - .start = 0, /* Dummy */ - .end = 0, /* Dummy */ - .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE | -#ifdef CONFIG_BCMDHD_PCIE - IORESOURCE_IRQ_HIGHEDGE, -#else - IORESOURCE_IRQ_HIGHLEVEL, -#endif /* CONFIG_BCMDHD_PCIE */ -}; -EXPORT_SYMBOL(dhd_wlan_resources); - -struct wifi_platform_data dhd_wlan_control = { - .set_power = dhd_wlan_power, - .set_reset = dhd_wlan_reset, - .set_carddetect = dhd_wlan_set_carddetect, -#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM - .mem_prealloc = dhd_wlan_mem_prealloc, -#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ -}; -EXPORT_SYMBOL(dhd_wlan_control); - -int __init -dhd_wlan_init(void) -{ - int ret; - - printk(KERN_INFO"%s: START.......\n", __FUNCTION__); - ret = dhd_wifi_init_gpio(); - if (ret < 0) { - printk(KERN_ERR "%s: failed to initiate GPIO, ret=%d\n", - __FUNCTION__, ret); - goto fail; - } - -#ifdef CONFIG_BCMDHD_OOB_HOST_WAKE - dhd_wlan_resources.start = wlan_host_wake_irq; - dhd_wlan_resources.end = wlan_host_wake_irq; -#endif /* CONFIG_BCMDHD_OOB_HOST_WAKE */ - -#ifdef CONFIG_BROADCOM_WIFI_RESERVED_MEM - ret = dhd_init_wlan_mem(); - if (ret < 0) { - printk(KERN_ERR "%s: failed to alloc reserved memory," - " ret=%d\n", __FUNCTION__, ret); - } -#endif /* CONFIG_BROADCOM_WIFI_RESERVED_MEM */ - -fail: - printk(KERN_INFO"%s: FINISH.......\n", __FUNCTION__); - return ret; -} -#if defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_ARCH_MSM8998) -#if defined(CONFIG_DEFERRED_INITCALLS) -deferred_module_init(dhd_wlan_init); -#else -late_initcall(dhd_wlan_init); -#endif /* CONFIG_DEFERRED_INITCALLS */ -#else -device_initcall(dhd_wlan_init); -#endif /* CONFIG_ARCH_MSM8996 || CONFIG_ARCH_MSM8998 */
diff --git a/bcmdhd.1.579.77.41.x/dhd_dbg.h b/bcmdhd.1.579.77.41.x/dhd_dbg.h deleted file mode 100644 index 72a79b0..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_dbg.h +++ /dev/null
@@ -1,348 +0,0 @@ -/* - * Debug/trace/assert driver definitions for Dongle Host Driver. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_dbg.h 667145 2016-10-26 04:27:53Z $ - */ - -#ifndef _dhd_dbg_ -#define _dhd_dbg_ - - -#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) -extern void dhd_log_dump_print(const char *fmt, ...); -extern void dhd_log_dump_print_drv(const char *fmt, ...); -#endif - -#define DHD_PRINT(args) printf args -#if defined(DHD_DEBUG) - -#ifdef DHD_LOG_DUMP -extern void dhd_log_dump_write(int type, const char *fmt, ...); -extern char *dhd_log_dump_get_timestamp(void); -#ifndef _DHD_LOG_DUMP_DEFINITIONS_ -#define _DHD_LOG_DUMP_DEFINITIONS_ -#define DLD_BUF_TYPE_GENERAL 0 -#define DLD_BUF_TYPE_SPECIAL 1 -#define DHD_LOG_DUMP_WRITE(fmt, ...) dhd_log_dump_write(DLD_BUF_TYPE_GENERAL, fmt, ##__VA_ARGS__) -#define DHD_LOG_DUMP_WRITE_EX(fmt, ...) dhd_log_dump_write(DLD_BUF_TYPE_SPECIAL, fmt, ##__VA_ARGS__) -#endif /* !_DHD_LOG_DUMP_DEFINITIONS_ */ - -#ifdef DHD_EFI -#define DHD_ERROR(args) \ -do { \ - if (dhd_msg_level & DHD_ERROR_VAL) { \ - printf args; \ - dhd_log_dump_print_drv("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ - dhd_log_dump_print_drv args; \ - } \ -} while (0) -#define DHD_INFO(args) \ -do { \ - if (dhd_msg_level & DHD_INFO_VAL) { \ - printf args; \ - dhd_log_dump_print_drv("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ - dhd_log_dump_print_drv args; \ - } \ -} while (0) -#else /* DHD_EFI */ -#define DHD_ERROR(args) \ -do { \ - if (dhd_msg_level & DHD_ERROR_VAL) { \ - printf args; \ - DHD_LOG_DUMP_WRITE("[%s] %s: ", dhd_log_dump_get_timestamp(), __func__); \ - DHD_LOG_DUMP_WRITE args; \ - } \ -} while (0) -#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0) -#endif /* DHD_EFI */ -#else /* DHD_LOG_DUMP */ -#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) - -#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) -#ifdef DHD_LOG_DUMP -#ifndef DHD_EFI -#define DHD_EVENT(args) \ -do { \ - if (dhd_msg_level & DHD_EVENT_VAL) { \ - printf args; \ - DHD_LOG_DUMP_WRITE("[%s] %s: ", dhd_log_dump_get_timestamp(), __func__); \ - DHD_LOG_DUMP_WRITE args; \ - } \ -} while (0) -#else -#define DHD_EVENT(args) \ -do { \ - if (dhd_msg_level & DHD_EVENT_VAL) { \ - dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ - dhd_log_dump_print args; \ - } \ -} while (0) -#endif /* !DHD_EFI */ -#else -#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0) -#endif /* DHD_LOG_DUMP */ -#define DHD_ISCAN(args) do {if (dhd_msg_level & DHD_ISCAN_VAL) printf args;} while (0) -#define DHD_ARPOE(args) do {if (dhd_msg_level & DHD_ARPOE_VAL) printf args;} while (0) -#define DHD_REORDER(args) do {if (dhd_msg_level & DHD_REORDER_VAL) printf args;} while (0) -#define DHD_PNO(args) do {if (dhd_msg_level & DHD_PNO_VAL) printf args;} while (0) -#define DHD_RTT(args) do {if (dhd_msg_level & DHD_RTT_VAL) printf args;} while (0) -#define DHD_PKT_MON(args) do {if (dhd_msg_level & DHD_PKT_MON_VAL) printf args;} while (0) -#ifdef DHD_LOG_DUMP -#ifndef DHD_EFI -#define DHD_MSGTRACE_LOG(args) \ -do { \ - if (dhd_msg_level & DHD_MSGTRACE_VAL) { \ - printf args; \ - DHD_LOG_DUMP_WRITE("[%s] %s: ", dhd_log_dump_get_timestamp(), __func__); \ - DHD_LOG_DUMP_WRITE args; \ - } \ -} while (0) -#else -#define DHD_MSGTRACE_LOG(args) \ -do { \ - if (dhd_msg_level & DHD_MSGTRACE_VAL) { \ - dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ - dhd_log_dump_print args; \ - } \ -} while (0) -#endif /* !DHD_EFI */ -#else -#define DHD_MSGTRACE_LOG(args) do {if (dhd_msg_level & DHD_MSGTRACE_VAL) printf args;} while (0) -#endif /* DHD_LOG_DUMP */ - -#if defined(DHD_LOG_DUMP) && defined(DHD_EFI) -#define DHD_FWLOG(args) DHD_MSGTRACE_LOG(args) -#else - -#define DHD_FWLOG(args) do {if (dhd_msg_level & DHD_FWLOG_VAL) printf args;} while (0) -#endif /* DHD_LOG_DUMP & DHD_EFI */ -#define DHD_DBGIF(args) do {if (dhd_msg_level & DHD_DBGIF_VAL) printf args;} while (0) - -#ifdef DHD_LOG_DUMP -#ifdef DHD_EFI -#define DHD_ERROR_MEM(args) \ -do { \ - if (dhd_msg_level & DHD_ERROR_VAL) { \ - dhd_log_dump_print_drv("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ - dhd_log_dump_print_drv args; \ - } \ -} while (0) -#define DHD_ERROR_EX(args) DHD_ERROR(args) -#else -#define DHD_ERROR_MEM(args) \ -do { \ - if (dhd_msg_level & DHD_ERROR_VAL) { \ - if (dhd_msg_level & DHD_ERROR_MEM_VAL) { \ - printf args; \ - } \ - DHD_LOG_DUMP_WRITE("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ - DHD_LOG_DUMP_WRITE args; \ - } \ -} while (0) -#define DHD_ERROR_EX(args) \ -do { \ - if (dhd_msg_level & DHD_ERROR_VAL) { \ - printf args; \ - DHD_LOG_DUMP_WRITE_EX("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ - DHD_LOG_DUMP_WRITE_EX args; \ - } \ -} while (0) -#endif /* DHD_EFI */ -#else -#define DHD_ERROR_MEM(args) DHD_ERROR(args) -#define DHD_ERROR_EX(args) DHD_ERROR(args) -#endif /* DHD_LOG_DUMP */ - -#ifdef CUSTOMER_HW4_DEBUG -#define DHD_TRACE_HW4 DHD_ERROR -#define DHD_INFO_HW4 DHD_ERROR -#else -#define DHD_TRACE_HW4 DHD_TRACE -#define DHD_INFO_HW4 DHD_INFO -#endif /* CUSTOMER_HW4_DEBUG */ - -#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_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) - -#else /* defined(BCMDBG) || defined(DHD_DEBUG) */ - -#if defined(DHD_EFI) -extern void dhd_log_dump_print_drv(const char *fmt, ...); -extern char *dhd_log_dump_get_timestamp(void); -#define DHD_ERROR(args) \ -do { \ - if (dhd_msg_level & DHD_ERROR_VAL) { \ - printf args; \ - dhd_log_dump_print_drv("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ - dhd_log_dump_print_drv args; \ - } \ -} while (0) -#define DHD_INFO(args) \ -do { \ - if (dhd_msg_level & DHD_INFO_VAL) { \ - printf args; \ - dhd_log_dump_print_drv("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ - dhd_log_dump_print_drv args; \ - } \ -} while (0) -#define DHD_TRACE(args) -#else /* DHD_EFI */ - -#define DHD_ERROR(args) do {if (dhd_msg_level & DHD_ERROR_VAL) \ - printf args;} while (0) -#define DHD_TRACE(args) -#define DHD_INFO(args) -#endif - -#define DHD_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) - -#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) -#define DHD_EVENT(args) \ -do { \ - if (dhd_msg_level & DHD_EVENT_VAL) { \ - dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ - dhd_log_dump_print args; \ - } \ -} while (0) -#else -#define DHD_EVENT(args) -#endif /* DHD_EFI && DHD_LOG_DUMP */ - -#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) - -#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) -#define DHD_MSGTRACE_LOG(args) \ -do { \ - if (dhd_msg_level & DHD_MSGTRACE_VAL) { \ - dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ - dhd_log_dump_print args; \ - } \ -} while (0) -#define DHD_FWLOG(args) DHD_MSGTRACE_LOG(args) -#else -#define DHD_MSGTRACE_LOG(args) -#define DHD_FWLOG(args) -#endif /* DHD_EFI && DHD_LOG_DUMP */ - -#define DHD_DBGIF(args) - -#if defined(DHD_EFI) && defined(DHD_LOG_DUMP) -#define DHD_ERROR_MEM(args) \ -do { \ - if (dhd_msg_level & DHD_ERROR_VAL) { \ - dhd_log_dump_print("[%s] %s: ", dhd_log_dump_get_timestamp(), __FUNCTION__); \ - dhd_log_dump_print args; \ - } \ -} while (0) -#define DHD_ERROR_EX(args) DHD_ERROR(args) -#else -#define DHD_ERROR_MEM(args) DHD_ERROR(args) -#define DHD_ERROR_EX(args) DHD_ERROR(args) -#endif /* DHD_EFI && DHD_LOG_DUMP */ - -#ifdef CUSTOMER_HW4_DEBUG -#define DHD_TRACE_HW4 DHD_ERROR -#define DHD_INFO_HW4 DHD_ERROR -#else -#define DHD_TRACE_HW4 DHD_TRACE -#define DHD_INFO_HW4 DHD_INFO -#endif /* CUSTOMER_HW4_DEBUG */ - -#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_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 -#endif - -#define DHD_LOG(args) - -#define DHD_BLOG(cp, size) - -#define DHD_NONE(args) -extern int dhd_msg_level; - -/* Defines msg bits */ -#include <dhdioctl.h> - -#endif /* _dhd_dbg_ */
diff --git a/bcmdhd.1.579.77.41.x/dhd_debug.c b/bcmdhd.1.579.77.41.x/dhd_debug.c deleted file mode 100644 index cd4c6f7..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_debug.c +++ /dev/null
@@ -1,2335 +0,0 @@ -/* - * DHD debugability support - * - * <<Broadcom-WL-IPTag/Open:>> - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_debug.c 711908 2017-07-20 10:37:34Z $ - */ - -#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> - -#if defined(DHD_EFI) -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) -#define container_of(ptr, type, member) \ - ((type *)((char *)(ptr) - offsetof(type, member))) -#endif - -#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 DHD_PKT_INFO DHD_ERROR -struct map_table { - uint16 fw_id; - uint16 host_id; - char *desc; -}; - -struct map_table event_map[] = { - {WLC_E_AUTH, WIFI_EVENT_AUTH_COMPLETE, "AUTH_COMPLETE"}, - {WLC_E_ASSOC, WIFI_EVENT_ASSOC_COMPLETE, "ASSOC_COMPLETE"}, - {TRACE_FW_AUTH_STARTED, WIFI_EVENT_FW_AUTH_STARTED, "AUTH STARTED"}, - {TRACE_FW_ASSOC_STARTED, WIFI_EVENT_FW_ASSOC_STARTED, "ASSOC STARTED"}, - {TRACE_FW_RE_ASSOC_STARTED, WIFI_EVENT_FW_RE_ASSOC_STARTED, "REASSOC STARTED"}, - {TRACE_G_SCAN_STARTED, WIFI_EVENT_G_SCAN_STARTED, "GSCAN STARTED"}, - {WLC_E_PFN_SCAN_COMPLETE, WIFI_EVENT_G_SCAN_COMPLETE, "GSCAN COMPLETE"}, - {WLC_E_DISASSOC, WIFI_EVENT_DISASSOCIATION_REQUESTED, "DIASSOC REQUESTED"}, - {WLC_E_REASSOC, WIFI_EVENT_RE_ASSOCIATION_REQUESTED, "REASSOC REQUESTED"}, - {TRACE_ROAM_SCAN_STARTED, WIFI_EVENT_ROAM_REQUESTED, "ROAM REQUESTED"}, - {WLC_E_BEACON_FRAME_RX, WIFI_EVENT_BEACON_RECEIVED, "BEACON Received"}, - {TRACE_ROAM_SCAN_STARTED, WIFI_EVENT_ROAM_SCAN_STARTED, "ROAM SCAN STARTED"}, - {TRACE_ROAM_SCAN_COMPLETE, WIFI_EVENT_ROAM_SCAN_COMPLETE, "ROAM SCAN COMPLETED"}, - {TRACE_ROAM_AUTH_STARTED, WIFI_EVENT_ROAM_AUTH_STARTED, "ROAM AUTH STARTED"}, - {WLC_E_AUTH, WIFI_EVENT_ROAM_AUTH_COMPLETE, "ROAM AUTH COMPLETED"}, - {TRACE_FW_RE_ASSOC_STARTED, WIFI_EVENT_ROAM_ASSOC_STARTED, "ROAM ASSOC STARTED"}, - {WLC_E_ASSOC, WIFI_EVENT_ROAM_ASSOC_COMPLETE, "ROAM ASSOC COMPLETED"}, - {TRACE_ROAM_SCAN_COMPLETE, WIFI_EVENT_ROAM_SCAN_COMPLETE, "ROAM SCAN COMPLETED"}, - {TRACE_BT_COEX_BT_SCO_START, WIFI_EVENT_BT_COEX_BT_SCO_START, "BT SCO START"}, - {TRACE_BT_COEX_BT_SCO_STOP, WIFI_EVENT_BT_COEX_BT_SCO_STOP, "BT SCO STOP"}, - {TRACE_BT_COEX_BT_SCAN_START, WIFI_EVENT_BT_COEX_BT_SCAN_START, "BT COEX SCAN START"}, - {TRACE_BT_COEX_BT_SCAN_STOP, WIFI_EVENT_BT_COEX_BT_SCAN_STOP, "BT COEX SCAN STOP"}, - {TRACE_BT_COEX_BT_HID_START, WIFI_EVENT_BT_COEX_BT_HID_START, "BT HID START"}, - {TRACE_BT_COEX_BT_HID_STOP, WIFI_EVENT_BT_COEX_BT_HID_STOP, "BT HID STOP"}, - {WLC_E_EAPOL_MSG, WIFI_EVENT_FW_EAPOL_FRAME_RECEIVED, "FW EAPOL PKT RECEIVED"}, - {TRACE_FW_EAPOL_FRAME_TRANSMIT_START, WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_START, - "FW EAPOL PKT TRANSMITED"}, - {TRACE_FW_EAPOL_FRAME_TRANSMIT_STOP, WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_STOP, - "FW EAPOL PKT TX STOPPED"}, - {TRACE_BLOCK_ACK_NEGOTIATION_COMPLETE, WIFI_EVENT_BLOCK_ACK_NEGOTIATION_COMPLETE, - "BLOCK ACK NEGO COMPLETED"}, -}; - -struct map_table event_tag_map[] = { - {TRACE_TAG_VENDOR_SPECIFIC, WIFI_TAG_VENDOR_SPECIFIC, "VENDOR SPECIFIC DATA"}, - {TRACE_TAG_BSSID, WIFI_TAG_BSSID, "BSSID"}, - {TRACE_TAG_ADDR, WIFI_TAG_ADDR, "ADDR_0"}, - {TRACE_TAG_SSID, WIFI_TAG_SSID, "SSID"}, - {TRACE_TAG_STATUS, WIFI_TAG_STATUS, "STATUS"}, - {TRACE_TAG_CHANNEL_SPEC, WIFI_TAG_CHANNEL_SPEC, "CHANSPEC"}, - {TRACE_TAG_WAKE_LOCK_EVENT, WIFI_TAG_WAKE_LOCK_EVENT, "WAKELOCK EVENT"}, - {TRACE_TAG_ADDR1, WIFI_TAG_ADDR1, "ADDR_1"}, - {TRACE_TAG_ADDR2, WIFI_TAG_ADDR2, "ADDR_2"}, - {TRACE_TAG_ADDR3, WIFI_TAG_ADDR3, "ADDR_3"}, - {TRACE_TAG_ADDR4, WIFI_TAG_ADDR4, "ADDR_4"}, - {TRACE_TAG_TSF, WIFI_TAG_TSF, "TSF"}, - {TRACE_TAG_IE, WIFI_TAG_IE, "802.11 IE"}, - {TRACE_TAG_INTERFACE, WIFI_TAG_INTERFACE, "INTERFACE"}, - {TRACE_TAG_REASON_CODE, WIFI_TAG_REASON_CODE, "REASON CODE"}, - {TRACE_TAG_RATE_MBPS, WIFI_TAG_RATE_MBPS, "RATE"}, -}; - -/* define log level per ring type */ -struct log_level_table fw_verbose_level_map[] = { - {1, EVENT_LOG_TAG_PCI_ERROR, EVENT_LOG_SET_BUS, "PCI_ERROR"}, - {1, EVENT_LOG_TAG_PCI_WARN, EVENT_LOG_SET_BUS, "PCI_WARN"}, - {2, EVENT_LOG_TAG_PCI_INFO, EVENT_LOG_SET_BUS, "PCI_INFO"}, - {3, EVENT_LOG_TAG_PCI_DBG, EVENT_LOG_SET_BUS, "PCI_DEBUG"}, - {3, EVENT_LOG_TAG_BEACON_LOG, EVENT_LOG_SET_WL, "BEACON_LOG"}, - {2, EVENT_LOG_TAG_WL_ASSOC_LOG, EVENT_LOG_SET_WL, "ASSOC_LOG"}, - {2, EVENT_LOG_TAG_WL_ROAM_LOG, EVENT_LOG_SET_WL, "ROAM_LOG"}, - {1, EVENT_LOG_TAG_TRACE_WL_INFO, EVENT_LOG_SET_WL, "WL_INFO"}, - {1, EVENT_LOG_TAG_TRACE_BTCOEX_INFO, EVENT_LOG_SET_WL, "BTCOEX_INFO"}, -#ifdef CUSTOMER_HW4_DEBUG - {3, EVENT_LOG_TAG_SCAN_WARN, EVENT_LOG_SET_WL, "SCAN_WARN"}, -#else - {1, EVENT_LOG_TAG_SCAN_WARN, EVENT_LOG_SET_WL, "SCAN_WARN"}, -#endif /* CUSTOMER_HW4_DEBUG */ - {1, EVENT_LOG_TAG_SCAN_ERROR, EVENT_LOG_SET_WL, "SCAN_ERROR"}, - {2, EVENT_LOG_TAG_SCAN_TRACE_LOW, EVENT_LOG_SET_WL, "SCAN_TRACE_LOW"}, - {2, EVENT_LOG_TAG_SCAN_TRACE_HIGH, EVENT_LOG_SET_WL, "SCAN_TRACE_HIGH"} -}; - -struct log_level_table fw_event_level_map[] = { - {1, EVENT_LOG_TAG_TRACE_WL_INFO, EVENT_LOG_SET_WL, "WL_INFO"}, - {1, EVENT_LOG_TAG_TRACE_BTCOEX_INFO, EVENT_LOG_SET_WL, "BTCOEX_INFO"}, -#ifdef CUSTOMER_HW4_DEBUG - {3, EVENT_LOG_TAG_BEACON_LOG, EVENT_LOG_SET_WL, "BEACON LOG"}, -#else - {2, EVENT_LOG_TAG_BEACON_LOG, EVENT_LOG_SET_WL, "BEACON LOG"}, -#endif /* CUSTOMER_HW4_DEBUG */ -}; - -struct map_table nan_event_map[] = { - {TRACE_NAN_CLUSTER_STARTED, NAN_EVENT_CLUSTER_STARTED, "NAN_CLUSTER_STARTED"}, - {TRACE_NAN_CLUSTER_JOINED, NAN_EVENT_CLUSTER_JOINED, "NAN_CLUSTER_JOINED"}, - {TRACE_NAN_CLUSTER_MERGED, NAN_EVENT_CLUSTER_MERGED, "NAN_CLUSTER_MERGED"}, - {TRACE_NAN_ROLE_CHANGED, NAN_EVENT_ROLE_CHANGED, "NAN_ROLE_CHANGED"}, - {TRACE_NAN_SCAN_COMPLETE, NAN_EVENT_SCAN_COMPLETE, "NAN_SCAN_COMPLETE"}, - {TRACE_NAN_STATUS_CHNG, NAN_EVENT_STATUS_CHNG, "NAN_STATUS_CHNG"}, -}; - -struct log_level_table nan_event_level_map[] = { - {1, EVENT_LOG_TAG_NAN_ERROR, 0, "NAN_ERROR"}, - {2, EVENT_LOG_TAG_NAN_INFO, 0, "NAN_INFO"}, - {3, EVENT_LOG_TAG_NAN_DBG, 0, "NAN_DEBUG"}, -}; - -struct map_table nan_evt_tag_map[] = { - {TRACE_TAG_BSSID, WIFI_TAG_BSSID, "BSSID"}, - {TRACE_TAG_ADDR, WIFI_TAG_ADDR, "ADDR_0"}, -}; - -/* reference tab table */ -uint ref_tag_tbl[EVENT_LOG_TAG_MAX + 1] = {0}; - -typedef struct dhddbg_loglist_item { - dll_t list; - event_log_hdr_t *hdr; -} loglist_item_t; - -typedef struct dhbdbg_pending_item { - dll_t list; - dhd_dbg_ring_status_t ring_status; - dhd_dbg_ring_entry_t *ring_entry; -} pending_item_t; - -/* trace log entry header user space processing */ -struct tracelog_header { - int magic_num; - int buf_size; - int seq_num; -}; -#define TRACE_LOG_MAGIC_NUMBER 0xEAE47C06 - -int -dhd_dbg_ring_pull_single(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len, - bool strip_header) -{ - dhd_dbg_ring_t *ring; - dhd_dbg_ring_entry_t *r_entry; - uint32 rlen; - char *buf; - - if (!dhdp || !dhdp->dbg) { - return 0; - } - - ring = &dhdp->dbg->dbg_rings[ring_id]; - - if (ring->state != RING_ACTIVE) { - return 0; - } - - if (ring->rp == ring->wp) { - return 0; - } - - 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)); - return 0; - } - - 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); - return 0; - } - - memcpy(data, buf, rlen); - /* update ring context */ - 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, 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); - } - 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)); - - return rlen; -} - -int -dhd_dbg_ring_pull(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len) -{ - int32 r_len, total_r_len = 0; - dhd_dbg_ring_t *ring; - - if (!dhdp || !dhdp->dbg) - return 0; - ring = &dhdp->dbg->dbg_rings[ring_id]; - if (ring->state != RING_ACTIVE) - return 0; - - while (buf_len > 0) { - r_len = dhd_dbg_ring_pull_single(dhdp, ring_id, data, buf_len, FALSE); - 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_push(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_entry_t *hdr, void *data) -{ - unsigned long flags; - uint32 pending_len; - uint32 w_len; - uint32 avail_size; - dhd_dbg_ring_t *ring; - dhd_dbg_ring_entry_t *w_entry, *r_entry; - - if (!dhdp || !dhdp->dbg) { - return BCME_BADADDR; - } - - ring = &dhdp->dbg->dbg_rings[ring_id]; - - if (ring->state != RING_ACTIVE) { - return BCME_OK; - } - - flags = dhd_os_spin_lock(ring->lock); - - w_len = ENTRY_LENGTH(hdr); - - if (w_len > ring->ring_size) { - dhd_os_spin_unlock(ring->lock, flags); - return BCME_ERROR; - } - - /* 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 (ring->rp == ring->wp) { - ring->rp = 0; - } - ring->wp = 0; - } else { - /* Not enough space for new entry, free some up */ - r_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf + - ring->rp); - 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\n", __FUNCTION__, - ring->id, ring->name, avail_size, w_len)); - ring->rp = 0; - ring->tail_padded = FALSE; - ring->rem_len = 0; - } - if (ring->rp >= ring->ring_size) { - DHD_ERROR(("%s: RING%d[%s] rp points out of boundary," - " ring->rp = %d, ring->ring_size=%d\n", - __FUNCTION__, ring->id, ring->name, ring->rp, - ring->ring_size)); - ASSERT(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); - - 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; - if (ring->wp >= ring->ring_size) { - DHD_ERROR(("%s: RING%d[%s] wp pointed out of ring boundary, " - "wp=%d, ring_size=%d\n", __FUNCTION__, ring->id, - ring->name, ring->wp, ring->ring_size)); - ASSERT(0); - } - /* 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)); - - /* Calculate current pending size */ - 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 = 0xFFFFFFFF - ring->stat.read_bytes + ring->stat.written_bytes; - } else { - pending_len = 0; - } - - /* if the current pending size is bigger than threshold */ - if (ring->threshold > 0 && - (pending_len >= ring->threshold) && ring->sched_pull) { - dhdp->dbg->pullreq(dhdp->dbg->private, ring->id); - ring->sched_pull = FALSE; - } - dhd_os_spin_unlock(ring->lock, flags); - return BCME_OK; -} - -static int -dhd_dbg_msgtrace_seqchk(uint32 *prev, uint32 cur) -{ - /* normal case including wrap around */ - if ((cur == 0 && *prev == 0xFFFFFFFF) || ((cur - *prev) == 1)) { - goto done; - } else if (cur == *prev) { - DHD_EVENT(("%s duplicate trace\n", __FUNCTION__)); - return -1; - } else if (cur > *prev) { - DHD_EVENT(("%s lost %d packets\n", __FUNCTION__, cur - *prev)); - } else { - DHD_EVENT(("%s seq out of order, dhd %d, dongle %d\n", - __FUNCTION__, *prev, cur)); - } -done: - *prev = cur; - return 0; -} - -#ifndef MACOSX_DHD -static void -dhd_dbg_msgtrace_msg_parser(void *event_data) -{ - msgtrace_hdr_t *hdr; - char *data, *s; - static uint32 seqnum_prev = 0; - - hdr = (msgtrace_hdr_t *)event_data; - data = (char *)event_data + MSGTRACE_HDRLEN; - - /* There are 2 bytes available at the end of data */ - data[ntoh16(hdr->len)] = '\0'; - - if (ntoh32(hdr->discarded_bytes) || ntoh32(hdr->discarded_printf)) { - DHD_DBGIF(("WLC_E_TRACE: [Discarded traces in dongle -->" - "discarded_bytes %d discarded_printf %d]\n", - ntoh32(hdr->discarded_bytes), - ntoh32(hdr->discarded_printf))); - } - - if (dhd_dbg_msgtrace_seqchk(&seqnum_prev, ntoh32(hdr->seqnum))) - return; - - /* Display the trace buffer. Advance from - * \n to \n to avoid display big - * printf (issue with Linux printk ) - */ - while (*data != '\0' && (s = strstr(data, "\n")) != NULL) { - *s = '\0'; - DHD_FWLOG(("[FWLOG] %s\n", data)); - data = s+1; - } - if (*data) - DHD_FWLOG(("[FWLOG] %s", data)); -} -#endif /* MACOSX_DHD */ -#ifdef SHOW_LOGTRACE -static const uint8 * -event_get_tlv(uint16 id, const char* tlvs, uint tlvs_len) -{ - const uint8 *pos = (const uint8 *)tlvs; - const uint8 *end = pos + tlvs_len; - const tlv_log *tlv; - int rest; - - while (pos + 1 < end) { - if (pos + 4 + pos[1] > end) - break; - tlv = (const tlv_log *) pos; - if (tlv->tag == id) - return pos; - rest = tlv->len % 4; /* padding values */ - pos += 4 + tlv->len + rest; - } - return NULL; -} - -#define DATA_UNIT_FOR_LOG_CNT 4 -/* #pragma used as a WAR to fix build failure, - * ignore dropping of 'const' qualifier in tlv_data assignment - * this pragma disables the warning only for the following function - */ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif -static int -dhd_dbg_nan_event_handler(dhd_pub_t *dhdp, event_log_hdr_t *hdr, uint32 *data) -{ - int ret = BCME_OK; - wl_event_log_id_ver_t nan_hdr; - log_nan_event_t *evt_payload; - uint16 evt_payload_len = 0, tot_payload_len = 0; - dhd_dbg_ring_entry_t msg_hdr; - bool evt_match = FALSE; - event_log_hdr_t *ts_hdr; - uint32 *ts_data; - char *tlvs, *dest_tlvs; - tlv_log *tlv_data; - int tlv_len = 0; - int i = 0, evt_idx = 0; - char eaddr_buf[ETHER_ADDR_STR_LEN]; - - BCM_REFERENCE(eaddr_buf); - - nan_hdr.t = *data; - DHD_DBGIF(("%s: version %u event %x\n", __FUNCTION__, nan_hdr.version, - nan_hdr.event)); - - if (nan_hdr.version != DIAG_VERSION) { - DHD_ERROR(("Event payload version %u mismatch with current version %u\n", - nan_hdr.version, DIAG_VERSION)); - return BCME_VERSION; - } - - /* nan event log should at least contain a wl_event_log_id_ver_t - * header and a arm cycle count - */ - if (hdr->count < NAN_EVENT_LOG_MIN_LENGTH) { - return BCME_BADLEN; - } - - memset(&msg_hdr, 0, sizeof(dhd_dbg_ring_entry_t)); - ts_hdr = (event_log_hdr_t *)((uint8 *)data - sizeof(event_log_hdr_t)); - if (ts_hdr->tag == EVENT_LOG_TAG_TS) { - ts_data = (uint32 *)ts_hdr - ts_hdr->count; - msg_hdr.timestamp = (uint64)ts_data[0]; - msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_TIMESTAMP; - } - msg_hdr.type = DBG_RING_ENTRY_NAN_EVENT_TYPE; - for (i = 0; i < ARRAYSIZE(nan_event_map); i++) { - if (nan_event_map[i].fw_id == nan_hdr.event) { - evt_match = TRUE; - evt_idx = i; - break; - } - } - if (evt_match) { - DHD_DBGIF(("%s : event (%s)\n", __FUNCTION__, nan_event_map[evt_idx].desc)); - /* payload length for nan event data */ - evt_payload_len = sizeof(log_nan_event_t) + - (hdr->count - 2) * DATA_UNIT_FOR_LOG_CNT; - if ((evt_payload = MALLOC(dhdp->osh, evt_payload_len)) == NULL) { - DHD_ERROR(("Memory allocation failed for nan evt log (%u)\n", - evt_payload_len)); - return BCME_NOMEM; - } - evt_payload->version = NAN_EVENT_VERSION; - evt_payload->event = nan_event_map[evt_idx].host_id; - dest_tlvs = (char *)evt_payload->tlvs; - tot_payload_len = sizeof(log_nan_event_t); - tlvs = (char *)(&data[1]); - tlv_len = (hdr->count - 2) * DATA_UNIT_FOR_LOG_CNT; - for (i = 0; i < ARRAYSIZE(nan_evt_tag_map); i++) { - tlv_data = (tlv_log *)event_get_tlv(nan_evt_tag_map[i].fw_id, - tlvs, tlv_len); - if (tlv_data) { - DHD_DBGIF(("NAN evt tlv.tag(%s), tlv.len : %d, tlv.data : ", - nan_evt_tag_map[i].desc, tlv_data->len)); - memcpy(dest_tlvs, tlv_data, sizeof(tlv_log) + tlv_data->len); - tot_payload_len += tlv_data->len + sizeof(tlv_log); - switch (tlv_data->tag) { - case TRACE_TAG_BSSID: - case TRACE_TAG_ADDR: - DHD_DBGIF(("%s\n", - bcm_ether_ntoa( - (const struct ether_addr *)tlv_data->value, - eaddr_buf))); - break; - default: - if (DHD_DBGIF_ON()) { - prhex(NULL, &tlv_data->value[0], - tlv_data->len); - } - break; - } - dest_tlvs += tlv_data->len + sizeof(tlv_log); - } - } - msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_BINARY; - msg_hdr.len = tot_payload_len; - dhd_dbg_ring_push(dhdp, NAN_EVENT_RING_ID, &msg_hdr, evt_payload); - MFREE(dhdp->osh, evt_payload, evt_payload_len); - } - return ret; -} - -static int -dhd_dbg_custom_evnt_handler(dhd_pub_t *dhdp, event_log_hdr_t *hdr, uint32 *data) -{ - int i = 0, match_idx = 0; - int payload_len, tlv_len; - uint16 tot_payload_len = 0; - int ret = BCME_OK; - int log_level; - wl_event_log_id_ver_t wl_log_id; - dhd_dbg_ring_entry_t msg_hdr; - log_conn_event_t *event_data; - bool evt_match = FALSE; - event_log_hdr_t *ts_hdr; - uint32 *ts_data; - char *tlvs, *dest_tlvs; - tlv_log *tlv_data; - static uint64 ts_saved = 0; - char eabuf[ETHER_ADDR_STR_LEN]; - char chanbuf[CHANSPEC_STR_LEN]; - - BCM_REFERENCE(eabuf); - BCM_REFERENCE(chanbuf); - /* get a event type and version */ - wl_log_id.t = *data; - if (wl_log_id.version != DIAG_VERSION) - return BCME_VERSION; - - /* custom event log should at least contain a wl_event_log_id_ver_t - * header and a arm cycle count - */ - if (hdr->count < NAN_EVENT_LOG_MIN_LENGTH) { - return BCME_BADLEN; - } - - ts_hdr = (event_log_hdr_t *)((uint8 *)data - sizeof(event_log_hdr_t)); - if (ts_hdr->tag == EVENT_LOG_TAG_TS) { - ts_data = (uint32 *)ts_hdr - ts_hdr->count; - ts_saved = (uint64)ts_data[0]; - } - memset(&msg_hdr, 0, sizeof(dhd_dbg_ring_entry_t)); - msg_hdr.timestamp = ts_saved; - - DHD_DBGIF(("Android Event ver %d, payload %d words, ts %llu\n", - (*data >> 16), hdr->count - 1, ts_saved)); - - /* Perform endian convertion */ - for (i = 0; i < hdr->count; i++) { - /* *(data + i) = ntoh32(*(data + i)); */ - DHD_DATA(("%08x ", *(data + i))); - } - DHD_DATA(("\n")); - msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_TIMESTAMP; - msg_hdr.flags |= DBG_RING_ENTRY_FLAGS_HAS_BINARY; - msg_hdr.type = DBG_RING_ENTRY_EVENT_TYPE; - - /* convert the data to log_conn_event_t format */ - for (i = 0; i < ARRAYSIZE(event_map); i++) { - if (event_map[i].fw_id == wl_log_id.event) { - evt_match = TRUE; - match_idx = i; - break; - } - } - if (evt_match) { - log_level = dhdp->dbg->dbg_rings[FW_EVENT_RING_ID].log_level; - /* filter the data based on log_level */ - for (i = 0; i < ARRAYSIZE(fw_event_level_map); i++) { - if ((fw_event_level_map[i].tag == hdr->tag) && - (fw_event_level_map[i].log_level > log_level)) { - return BCME_OK; - } - } - DHD_DBGIF(("%s : event (%s)\n", __FUNCTION__, event_map[match_idx].desc)); - /* get the payload length for event data (skip : log header + timestamp) */ - payload_len = sizeof(log_conn_event_t) + DATA_UNIT_FOR_LOG_CNT * (hdr->count - 2); - event_data = MALLOC(dhdp->osh, payload_len); - if (!event_data) { - DHD_ERROR(("failed to allocate the log_conn_event_t with length(%d)\n", - payload_len)); - return BCME_NOMEM; - } - event_data->event = event_map[match_idx].host_id; - dest_tlvs = (char *)event_data->tlvs; - tot_payload_len = sizeof(log_conn_event_t); - tlvs = (char *)(&data[1]); - tlv_len = (hdr->count - 2) * DATA_UNIT_FOR_LOG_CNT; - for (i = 0; i < ARRAYSIZE(event_tag_map); i++) { - tlv_data = (tlv_log *)event_get_tlv(event_tag_map[i].fw_id, - tlvs, tlv_len); - if (tlv_data) { - DHD_DBGIF(("tlv.tag(%s), tlv.len : %d, tlv.data : ", - event_tag_map[i].desc, tlv_data->len)); - memcpy(dest_tlvs, tlv_data, sizeof(tlv_log) + tlv_data->len); - tot_payload_len += tlv_data->len + sizeof(tlv_log); - switch (tlv_data->tag) { - case TRACE_TAG_BSSID: - case TRACE_TAG_ADDR: - case TRACE_TAG_ADDR1: - case TRACE_TAG_ADDR2: - case TRACE_TAG_ADDR3: - case TRACE_TAG_ADDR4: - DHD_DBGIF(("%s\n", - bcm_ether_ntoa((const struct ether_addr *)tlv_data->value, - eabuf))); - break; - case TRACE_TAG_SSID: - DHD_DBGIF(("%s\n", tlv_data->value)); - break; - case TRACE_TAG_STATUS: - DHD_DBGIF(("%d\n", ltoh32_ua(&tlv_data->value[0]))); - break; - case TRACE_TAG_REASON_CODE: - DHD_DBGIF(("%d\n", ltoh16_ua(&tlv_data->value[0]))); - break; - case TRACE_TAG_RATE_MBPS: - DHD_DBGIF(("%d Kbps\n", - ltoh16_ua(&tlv_data->value[0]) * 500)); - break; - case TRACE_TAG_CHANNEL_SPEC: - DHD_DBGIF(("%s\n", - wf_chspec_ntoa( - ltoh16_ua(&tlv_data->value[0]), chanbuf))); - break; - default: - if (DHD_DBGIF_ON()) { - prhex(NULL, &tlv_data->value[0], tlv_data->len); - } - } - dest_tlvs += tlv_data->len + sizeof(tlv_log); - } - } - msg_hdr.len = tot_payload_len; - dhd_dbg_ring_push(dhdp, FW_EVENT_RING_ID, &msg_hdr, event_data); - MFREE(dhdp->osh, event_data, payload_len); - } - return ret; -} -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - -/* To identify format of types %Ns where N >= 0 is a number */ -bool -check_valid_string_format(char *curr_ptr) -{ - char *next_ptr; - if ((next_ptr = bcmstrstr(curr_ptr, "s")) != NULL) { - /* Default %s format */ - if (curr_ptr == next_ptr) { - return TRUE; - } - - /* Verify each charater between '%' and 's' is a valid number */ - while (curr_ptr < next_ptr) { - if (bcm_isdigit(*curr_ptr) == FALSE) { - return FALSE; - } - curr_ptr++; - } - - return TRUE; - } else { - return FALSE; - } -} - -#define MAX_NO_OF_ARG 16 -#define FMTSTR_SIZE 132 -#define ROMSTR_SIZE 200 -#define SIZE_LOC_STR 50 -static uint64 verboselog_ts_saved = 0; -static void -dhd_dbg_verboselog_handler(dhd_pub_t *dhdp, event_log_hdr_t *hdr, - void *raw_event_ptr) -{ - event_log_hdr_t *ts_hdr; - uint32 *log_ptr = (uint32 *)hdr - hdr->count; - char fmtstr_loc_buf[ROMSTR_SIZE] = { 0 }; - uint32 rom_str_len = 0; - uint32 *ts_data; - - if (!raw_event_ptr) { - return; - } - - /* Get time stamp if it's updated */ - ts_hdr = (event_log_hdr_t *)((char *)log_ptr - sizeof(event_log_hdr_t)); - if (ts_hdr->tag == EVENT_LOG_TAG_TS) { - ts_data = (uint32 *)ts_hdr - ts_hdr->count; - verboselog_ts_saved = (uint64)ts_data[0]; - DHD_MSGTRACE_LOG(("EVENT_LOG_TS[0x%08x]: SYS:%08x CPU:%08x\n", - ts_data[ts_hdr->count - 1], ts_data[0], ts_data[1])); - } - - if (hdr->tag == EVENT_LOG_TAG_ROM_PRINTF) { - rom_str_len = (hdr->count - 1) * sizeof(uint32); - if (rom_str_len >= (ROMSTR_SIZE -1)) - rom_str_len = ROMSTR_SIZE - 1; - - /* copy all ascii data for ROM printf to local string */ - memcpy(fmtstr_loc_buf, log_ptr, rom_str_len); - /* add end of line at last */ - fmtstr_loc_buf[rom_str_len] = '\0'; - - DHD_MSGTRACE_LOG(("EVENT_LOG_ROM[0x%08x]: %s", - log_ptr[hdr->count - 1], fmtstr_loc_buf)); - - /* Add newline if missing */ - if (fmtstr_loc_buf[strlen(fmtstr_loc_buf) - 1] != '\n') - DHD_MSGTRACE_LOG(("\n")); - - return; - } - - if (hdr->tag == EVENT_LOG_TAG_MSCHPROFILE || hdr->tag == EVENT_LOG_TAG_MSCHPROFILE_TLV) { - wl_mschdbg_verboselog_handler(dhdp, raw_event_ptr, hdr->tag, log_ptr); - return; - } - - /* print the message out in a logprint */ - dhd_dbg_verboselog_printf(dhdp, hdr, raw_event_ptr, log_ptr); -} - -void -dhd_dbg_verboselog_printf(dhd_pub_t *dhdp, event_log_hdr_t *hdr, - void *raw_event_ptr, uint32 *log_ptr) -{ - dhd_event_log_t *raw_event = (dhd_event_log_t *)raw_event_ptr; - uint16 count; - int log_level, id; - char fmtstr_loc_buf[ROMSTR_SIZE] = { 0 }; - char (*str_buf)[SIZE_LOC_STR] = NULL; - char *str_tmpptr = NULL; - uint32 addr = 0; - typedef union { - uint32 val; - char * addr; - } u_arg; - u_arg arg[MAX_NO_OF_ARG] = {{0}}; - char *c_ptr = NULL; - - BCM_REFERENCE(arg); - - if (!raw_event) { - return; - } - - /* print the message out in a logprint */ - if (!(raw_event->fmts) || hdr->fmt_num == 0xffff) { - if (dhdp->dbg) { - log_level = dhdp->dbg->dbg_rings[FW_VERBOSE_RING_ID].log_level; - for (id = 0; id < ARRAYSIZE(fw_verbose_level_map); id++) { - if ((fw_verbose_level_map[id].tag == hdr->tag) && - (fw_verbose_level_map[id].log_level > log_level)) - return; - } - } - - DHD_EVENT(("%d.%d EL:tag=%d len=%d fmt=0x%x", - (uint32)verboselog_ts_saved / 1000, - (uint32)verboselog_ts_saved % 1000, - hdr->tag, - hdr->count, - hdr->fmt_num)); - - for (count = 0; count < (hdr->count-1); count++) { - if (count % 8 == 0) - DHD_EVENT(("\n\t%08x", log_ptr[count])); - else - DHD_EVENT((" %08x", log_ptr[count])); - } - DHD_EVENT(("\n")); - - return; - } - - str_buf = MALLOCZ(dhdp->osh, (MAX_NO_OF_ARG * SIZE_LOC_STR)); - if (!str_buf) { - DHD_ERROR(("%s: malloc failed str_buf\n", __FUNCTION__)); - return; - } - - if ((hdr->fmt_num >> 2) < raw_event->num_fmts) { - if (hdr->tag == EVENT_LOG_TAG_MSCHPROFILE) { - snprintf(fmtstr_loc_buf, FMTSTR_SIZE, "%s", - raw_event->fmts[hdr->fmt_num >> 2]); - hdr->count++; - } else { - snprintf(fmtstr_loc_buf, FMTSTR_SIZE, "CONSOLE_E: %6d.%3d %s", - log_ptr[hdr->count-1]/1000, (log_ptr[hdr->count - 1] % 1000), - raw_event->fmts[hdr->fmt_num >> 2]); - } - c_ptr = fmtstr_loc_buf; - } else { - DHD_ERROR(("%s: fmt number out of range \n", __FUNCTION__)); - goto exit; - } - - for (count = 0; count < (hdr->count - 1); count++) { - if (c_ptr != NULL) - if ((c_ptr = bcmstrstr(c_ptr, "%")) != NULL) - c_ptr++; - - if (c_ptr != NULL) { - if (check_valid_string_format(c_ptr)) { - if ((raw_event->raw_sstr) && - ((log_ptr[count] > raw_event->rodata_start) && - (log_ptr[count] < raw_event->rodata_end))) { - /* ram static string */ - addr = log_ptr[count] - raw_event->rodata_start; - str_tmpptr = raw_event->raw_sstr + addr; - memcpy(str_buf[count], str_tmpptr, - SIZE_LOC_STR); - str_buf[count][SIZE_LOC_STR-1] = '\0'; - arg[count].addr = str_buf[count]; - } else if ((raw_event->rom_raw_sstr) && - ((log_ptr[count] > - raw_event->rom_rodata_start) && - (log_ptr[count] < - raw_event->rom_rodata_end))) { - /* rom static string */ - addr = log_ptr[count] - raw_event->rom_rodata_start; - str_tmpptr = raw_event->rom_raw_sstr + addr; - memcpy(str_buf[count], str_tmpptr, - SIZE_LOC_STR); - str_buf[count][SIZE_LOC_STR-1] = '\0'; - arg[count].addr = str_buf[count]; - } else { - /* - * Dynamic string OR - * No data for static string. - * So store all string's address as string. - */ - snprintf(str_buf[count], SIZE_LOC_STR, - "(s)0x%x", log_ptr[count]); - arg[count].addr = str_buf[count]; - } - } else { - /* Other than string */ - arg[count].val = log_ptr[count]; - } - } - } - - /* Print FW logs */ - DHD_FWLOG((fmtstr_loc_buf, arg[0], arg[1], arg[2], arg[3], - arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], - arg[11], arg[12], arg[13], arg[14], arg[15])); - -exit: - MFREE(dhdp->osh, str_buf, (MAX_NO_OF_ARG * SIZE_LOC_STR)); -} - -static void -dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data, - void *raw_event_ptr, uint datalen) -{ - msgtrace_hdr_t *hdr; - char *data; - int id; - uint32 log_hdr_len = sizeof(event_log_hdr_t); - uint32 log_pyld_len; - static uint32 seqnum_prev = 0; - event_log_hdr_t *log_hdr; - bool msg_processed = FALSE; - uint32 *log_ptr = NULL; - dll_t list_head, *cur; - loglist_item_t *log_item; - int32 nan_evt_ring_log_level = 0; - dhd_dbg_ring_entry_t msg_hdr; - char *logbuf; - struct tracelog_header *logentry_header; - - /* log trace event consists of: - * msgtrace header - * event log block header - * event log payload - */ - if (datalen <= MSGTRACE_HDRLEN + EVENT_LOG_BLOCK_HDRLEN) { - return; - } - hdr = (msgtrace_hdr_t *)event_data; - data = (char *)event_data + MSGTRACE_HDRLEN; - datalen -= MSGTRACE_HDRLEN; - - if (dhd_dbg_msgtrace_seqchk(&seqnum_prev, ntoh32(hdr->seqnum))) - return; - - /* Save the whole message to event log ring */ - memset(&msg_hdr, 0, sizeof(dhd_dbg_ring_entry_t)); - logbuf = VMALLOC(dhdp->osh, sizeof(*logentry_header) + datalen); - if (logbuf == NULL) - return; - logentry_header = (struct tracelog_header *)logbuf; - logentry_header->magic_num = TRACE_LOG_MAGIC_NUMBER; - logentry_header->buf_size = datalen; - logentry_header->seq_num = hdr->seqnum; - msg_hdr.type = DBG_RING_ENTRY_DATA_TYPE; - - if ((sizeof(*logentry_header) + datalen) > PAYLOAD_MAX_LEN) { - DHD_ERROR(("%s:Payload len=%u exceeds max len\n", __FUNCTION__, - ((uint)sizeof(*logentry_header) + datalen))); - VMFREE(dhdp->osh, logbuf, sizeof(*logentry_header) + datalen); - return; - } - - msg_hdr.len = sizeof(*logentry_header) + datalen; - memcpy(logbuf + sizeof(*logentry_header), data, datalen); - dhd_dbg_ring_push(dhdp, FW_VERBOSE_RING_ID, &msg_hdr, logbuf); - VMFREE(dhdp->osh, logbuf, sizeof(*logentry_header) + datalen); - - /* Print sequence number, originating set and length of received - * event log buffer. Refer to event log buffer structure in - * event_log.h - */ - DHD_MSGTRACE_LOG(("EVENT_LOG_HDR[0x%x]: Set: 0x%08x length = %d\n", - ltoh16(*((uint16 *)(data+2))), ltoh32(*((uint32 *)(data + 4))), - ltoh16(*((uint16 *)(data))))); - data += EVENT_LOG_BLOCK_HDRLEN; - datalen -= EVENT_LOG_BLOCK_HDRLEN; - - /* start parsing from the tail of packet - * Sameple format of a meessage - * 001d3c54 00000064 00000064 001d3c54 001dba08 035d6ce1 0c540639 - * 001d3c54 00000064 00000064 035d6d89 0c580439 - * 0x0c580439 -- 39 is tag, 04 is count, 580c is format number - * all these uint32 values comes in reverse order as group as EL data - * while decoding we can only parse from last to first - * |<- datalen ->| - * |----(payload and maybe more logs)----|event_log_hdr_t| - * data log_hdr - */ - dll_init(&list_head); - while (datalen > log_hdr_len) { - log_hdr = (event_log_hdr_t *)(data + datalen - log_hdr_len); - /* skip zero padding at end of frame */ - if (log_hdr->tag == EVENT_LOG_TAG_NULL) { - datalen -= log_hdr_len; - continue; - } - /* Check argument count, any event log should contain at least - * one argument (4 bytes) for arm cycle count and up to 16 - * arguments when the format is valid - */ - if (log_hdr->count == 0) { - break; - } - if ((log_hdr->count > MAX_NO_OF_ARG) && (log_hdr->fmt_num != 0xffff)) { - break; - } - - log_pyld_len = log_hdr->count * DATA_UNIT_FOR_LOG_CNT; - /* log data should not cross the event data boundary */ - if ((char *)log_hdr - data < log_pyld_len) - break; - /* skip 4 bytes time stamp packet */ - if (log_hdr->tag == EVENT_LOG_TAG_TS) { - datalen -= log_pyld_len + log_hdr_len; - continue; - } - if (!(log_item = MALLOC(dhdp->osh, sizeof(*log_item)))) { - DHD_ERROR(("%s allocating log list item failed\n", - __FUNCTION__)); - break; - } - log_item->hdr = log_hdr; - dll_insert(&log_item->list, &list_head); - datalen -= (log_pyld_len + log_hdr_len); - } - - while (!dll_empty(&list_head)) { - msg_processed = FALSE; - cur = dll_head_p(&list_head); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - log_item = (loglist_item_t *)container_of(cur, loglist_item_t, list); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - log_hdr = log_item->hdr; - log_ptr = (uint32 *)log_hdr - log_hdr->count; - dll_delete(cur); - MFREE(dhdp->osh, log_item, sizeof(*log_item)); - - /* Before DHD debugability is implemented WLC_E_TRACE had been - * used to carry verbose logging from firmware. We need to - * be able to handle those messages even without a initialized - * debug layer. - */ - if (dhdp->dbg) { - /* check the data for NAN event ring; keeping first as small table */ - /* process only user configured to log */ - nan_evt_ring_log_level = dhdp->dbg->dbg_rings[NAN_EVENT_RING_ID].log_level; - if (dhdp->dbg->dbg_rings[NAN_EVENT_RING_ID].log_level) { - for (id = 0; id < ARRAYSIZE(nan_event_level_map); id++) { - if (nan_event_level_map[id].tag == log_hdr->tag) { - /* dont process if tag log level is greater - * than ring log level - */ - if (nan_event_level_map[id].log_level > - nan_evt_ring_log_level) { - msg_processed = TRUE; - break; - } - /* In case of BCME_VERSION error, - * this is not NAN event type data - */ - if (dhd_dbg_nan_event_handler(dhdp, - log_hdr, log_ptr) != BCME_VERSION) { - msg_processed = TRUE; - } - break; - } - } - } - if (!msg_processed) { - /* check the data for event ring */ - for (id = 0; id < ARRAYSIZE(fw_event_level_map); id++) { - if (fw_event_level_map[id].tag == log_hdr->tag) { - /* In case of BCME_VERSION error, - * this is not event type data - */ - if (dhd_dbg_custom_evnt_handler(dhdp, - log_hdr, log_ptr) != BCME_VERSION) { - msg_processed = TRUE; - } - break; - } - } - } - } - if (!msg_processed) - dhd_dbg_verboselog_handler(dhdp, log_hdr, raw_event_ptr); - - } -} -#else /* !SHOW_LOGTRACE */ -static INLINE void dhd_dbg_verboselog_handler(dhd_pub_t *dhdp, - event_log_hdr_t *hdr, void *raw_event_ptr) {}; -static INLINE void dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, - void *event_data, void *raw_event_ptr, uint datalen) {}; -#endif /* SHOW_LOGTRACE */ -#ifndef MACOSX_DHD -void -dhd_dbg_trace_evnt_handler(dhd_pub_t *dhdp, void *event_data, - void *raw_event_ptr, uint datalen) -{ - msgtrace_hdr_t *hdr; - - hdr = (msgtrace_hdr_t *)event_data; - - if (hdr->version != MSGTRACE_VERSION) { - DHD_DBGIF(("%s unsupported MSGTRACE version, dhd %d, dongle %d\n", - __FUNCTION__, MSGTRACE_VERSION, hdr->version)); - return; - } - - if (hdr->trace_type == MSGTRACE_HDR_TYPE_MSG) - dhd_dbg_msgtrace_msg_parser(event_data); - else if (hdr->trace_type == MSGTRACE_HDR_TYPE_LOG) - dhd_dbg_msgtrace_log_parser(dhdp, event_data, raw_event_ptr, datalen); -} -#endif /* MACOSX_DHD */ -static int -dhd_dbg_ring_init(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring, uint16 id, uint8 *name, - uint32 ring_sz, int section) -{ - void *buf; - unsigned long flags; -#ifdef CONFIG_DHD_USE_STATIC_BUF - buf = DHD_OS_PREALLOC(dhdp, section, ring_sz); -#else - buf = MALLOCZ(dhdp->osh, ring_sz); -#endif - if (!buf) - return BCME_NOMEM; - - ring->lock = dhd_os_spin_lock_init(dhdp->osh); - - flags = dhd_os_spin_lock(ring->lock); - 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->sched_pull = TRUE; - ring->rem_len = 0; - dhd_os_spin_unlock(ring->lock, flags); - - return BCME_OK; -} - -static void -dhd_dbg_ring_deinit(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring) -{ - void *buf; - uint32 ring_sz; - unsigned long flags; - - if (!ring->ring_buf) - return; - - flags = dhd_os_spin_lock(ring->lock); - ring->id = 0; - ring->name[0] = 0; - ring_sz = ring->ring_size; - ring->ring_size = 0; - ring->wp = ring->rp = 0; - buf = ring->ring_buf; - ring->ring_buf = NULL; - memset(&ring->stat, 0, sizeof(ring->stat)); - ring->threshold = 0; - ring->state = RING_STOP; - dhd_os_spin_unlock(ring->lock, flags); - - dhd_os_spin_lock_deinit(dhdp->osh, ring->lock); -#ifndef CONFIG_DHD_USE_STATIC_BUF - MFREE(dhdp->osh, buf, ring_sz); -#endif -} - -uint8 -dhd_dbg_find_sets_by_tag(uint16 tag) -{ - uint i; - uint8 sets = 0; - - for (i = 0; i < ARRAYSIZE(fw_verbose_level_map); i++) { - if (fw_verbose_level_map[i].tag == tag) { - sets |= fw_verbose_level_map[i].sets; - } - } - - for (i = 0; i < ARRAYSIZE(fw_event_level_map); i++) { - if (fw_event_level_map[i].tag == tag) { - sets |= fw_event_level_map[i].sets; - } - } - - return sets; -} - -/* - * dhd_dbg_set_event_log_tag : modify the state of an event log tag - */ -void -dhd_dbg_set_event_log_tag(dhd_pub_t *dhdp, uint16 tag, uint8 set) -{ - wl_el_tag_params_t pars; - char *cmd = "event_log_tag_control"; - char iovbuf[WLC_IOCTL_SMLEN] = { 0 }; - int ret; - - memset(&pars, 0, sizeof(pars)); - pars.tag = tag; - pars.set = dhd_dbg_find_sets_by_tag(tag); - pars.flags = set ? EVENT_LOG_TAG_FLAG_LOG : EVENT_LOG_TAG_FLAG_NONE; - - if (!bcm_mkiovar(cmd, (char *)&pars, sizeof(pars), iovbuf, sizeof(iovbuf))) { - DHD_ERROR(("%s mkiovar failed\n", __FUNCTION__)); - return; - } - - ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - if (ret) { - DHD_ERROR(("%s set log tag iovar failed %d\n", __FUNCTION__, ret)); - } -} - -int -dhd_dbg_set_configuration(dhd_pub_t *dhdp, int ring_id, int log_level, int flags, uint32 threshold) -{ - dhd_dbg_ring_t *ring; - uint8 set = 1; - unsigned long lock_flags; - int i, array_len = 0; - struct log_level_table *log_level_tbl = NULL; - if (!dhdp || !dhdp->dbg) - return BCME_BADADDR; - - ring = &dhdp->dbg->dbg_rings[ring_id]; - - if (ring->state == RING_STOP) - return BCME_UNSUPPORTED; - - lock_flags = dhd_os_spin_lock(ring->lock); - 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_os_spin_unlock(ring->lock, lock_flags); - if (log_level > 0) - set = TRUE; - - if (ring->id == FW_EVENT_RING_ID) { - log_level_tbl = fw_event_level_map; - array_len = ARRAYSIZE(fw_event_level_map); - } else if (ring->id == FW_VERBOSE_RING_ID) { - log_level_tbl = fw_verbose_level_map; - array_len = ARRAYSIZE(fw_verbose_level_map); - } else if (ring->id == NAN_EVENT_RING_ID) { - log_level_tbl = nan_event_level_map; - array_len = ARRAYSIZE(nan_event_level_map); - } - - for (i = 0; i < array_len; i++) { - if (log_level == 0 || (log_level_tbl[i].log_level > log_level)) { - /* clear the reference per ring */ - ref_tag_tbl[log_level_tbl[i].tag] &= ~(1 << ring_id); - } else { - /* set the reference per ring */ - ref_tag_tbl[log_level_tbl[i].tag] |= (1 << ring_id); - } - set = (ref_tag_tbl[log_level_tbl[i].tag])? 1 : 0; - DHD_DBGIF(("%s TAG(%s) is %s for the ring(%s)\n", __FUNCTION__, - log_level_tbl[i].desc, (set)? "SET" : "CLEAR", ring->name)); - dhd_dbg_set_event_log_tag(dhdp, log_level_tbl[i].tag, set); - } - return BCME_OK; -} - -/* -* dhd_dbg_get_ring_status : get the ring status from the coresponding ring buffer -* Return: An error code or 0 on success. -*/ - -int -dhd_dbg_get_ring_status(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_status_t *dbg_ring_status) -{ - int ret = BCME_OK; - int id = 0; - dhd_dbg_t *dbg; - dhd_dbg_ring_t *dbg_ring; - dhd_dbg_ring_status_t ring_status; - if (!dhdp || !dhdp->dbg) - return BCME_BADADDR; - dbg = dhdp->dbg; - - memset(&ring_status, 0, sizeof(dhd_dbg_ring_status_t)); - for (id = DEBUG_RING_ID_INVALID + 1; id < DEBUG_RING_ID_MAX; id++) { - dbg_ring = &dbg->dbg_rings[id]; - if (VALID_RING(dbg_ring->id) && (dbg_ring->id == ring_id)) { - RING_STAT_TO_STATUS(dbg_ring, ring_status); - *dbg_ring_status = ring_status; - break; - } - } - if (!VALID_RING(id)) { - DHD_ERROR(("%s : cannot find the ring_id : %d\n", __FUNCTION__, ring_id)); - ret = BCME_NOTFOUND; - } - return ret; -} - -/* -* dhd_dbg_find_ring_id : return ring_id based on ring_name -* Return: An invalid ring id for failure or valid ring id on success. -*/ - -int -dhd_dbg_find_ring_id(dhd_pub_t *dhdp, char *ring_name) -{ - int id; - dhd_dbg_t *dbg; - dhd_dbg_ring_t *ring; - - if (!dhdp || !dhdp->dbg) - return BCME_BADADDR; - - dbg = dhdp->dbg; - for (id = DEBUG_RING_ID_INVALID + 1; id < DEBUG_RING_ID_MAX; id++) { - ring = &dbg->dbg_rings[id]; - if (!strncmp((char *)ring->name, ring_name, sizeof(ring->name) - 1)) - break; - } - return id; -} - -/* -* dhd_dbg_get_priv : get the private data of dhd dbugability module -* Return : An NULL on failure or valid data address -*/ -void * -dhd_dbg_get_priv(dhd_pub_t *dhdp) -{ - if (!dhdp || !dhdp->dbg) - return NULL; - return dhdp->dbg->private; -} - -/* -* dhd_dbg_start : start and stop All of Ring buffers -* Return: An error code or 0 on success. -*/ -int -dhd_dbg_start(dhd_pub_t *dhdp, bool start) -{ - int ret = BCME_OK; - int ring_id; - dhd_dbg_t *dbg; - dhd_dbg_ring_t *dbg_ring; - if (!dhdp) - return BCME_BADARG; - dbg = dhdp->dbg; - - for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) { - dbg_ring = &dbg->dbg_rings[ring_id]; - if (!start) { - if (VALID_RING(dbg_ring->id)) { - /* Initialize the information for the ring */ - dbg_ring->state = RING_SUSPEND; - dbg_ring->log_level = 0; - dbg_ring->rp = dbg_ring->wp = 0; - dbg_ring->threshold = 0; - memset(&dbg_ring->stat, 0, sizeof(struct ring_statistics)); - memset(dbg_ring->ring_buf, 0, dbg_ring->ring_size); - } - } - } - return ret; -} - -/* - * dhd_dbg_send_urgent_evt: send the health check evt to Upper layer - * - * Return: An error code or 0 on success. - */ - -int -dhd_dbg_send_urgent_evt(dhd_pub_t *dhdp, const void *data, const uint32 len) -{ - dhd_dbg_t *dbg; - int ret = BCME_OK; - if (!dhdp || !dhdp->dbg) - return BCME_BADADDR; - - dbg = dhdp->dbg; - if (dbg->urgent_notifier) { - dbg->urgent_notifier(dhdp, data, len); - } - return ret; -} - -#if defined(DBG_PKT_MON) || defined(DHD_PKT_LOGGING) -uint32 -__dhd_dbg_pkt_hash(uintptr_t pkt, uint32 pktid) -{ - uint32 __pkt; - uint32 __pktid; - - __pkt = ((int)pkt) >= 0 ? (2 * pkt) : (-2 * pkt - 1); - __pktid = ((int)pktid) >= 0 ? (2 * pktid) : (-2 * pktid - 1); - - return (__pkt >= __pktid ? (__pkt * __pkt + __pkt + __pktid) : - (__pkt + __pktid * __pktid)); -} - -#define __TIMESPEC_TO_US(ts) \ - (((uint32)(ts).tv_sec * USEC_PER_SEC) + ((ts).tv_nsec / NSEC_PER_USEC)) - -uint32 -__dhd_dbg_driver_ts_usec(void) -{ - struct timespec ts; - - get_monotonic_boottime(&ts); - return ((uint32)(__TIMESPEC_TO_US(ts))); -} - -wifi_tx_packet_fate -__dhd_dbg_map_tx_status_to_pkt_fate(uint16 status) -{ - wifi_tx_packet_fate pkt_fate; - - switch (status) { - case WLFC_CTL_PKTFLAG_DISCARD: - pkt_fate = TX_PKT_FATE_ACKED; - break; - case WLFC_CTL_PKTFLAG_D11SUPPRESS: - /* intensional fall through */ - case WLFC_CTL_PKTFLAG_WLSUPPRESS: - pkt_fate = TX_PKT_FATE_FW_QUEUED; - break; - case WLFC_CTL_PKTFLAG_TOSSED_BYWLC: - pkt_fate = TX_PKT_FATE_FW_DROP_INVALID; - break; - case WLFC_CTL_PKTFLAG_DISCARD_NOACK: - pkt_fate = TX_PKT_FATE_SENT; - break; - default: - pkt_fate = TX_PKT_FATE_FW_DROP_OTHER; - break; - } - - return pkt_fate; -} -#endif /* DBG_PKT_MON || DHD_PKT_LOGGING */ - -#ifdef DBG_PKT_MON -static int -__dhd_dbg_free_tx_pkts(dhd_pub_t *dhdp, dhd_dbg_tx_info_t *tx_pkts, - uint16 pkt_count) -{ - uint16 count; - - DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__)); - count = 0; - while ((count < pkt_count) && tx_pkts) { - if (tx_pkts->info.pkt) - PKTFREE(dhdp->osh, tx_pkts->info.pkt, TRUE); - tx_pkts++; - count++; - } - - return BCME_OK; -} - -static int -__dhd_dbg_free_rx_pkts(dhd_pub_t *dhdp, dhd_dbg_rx_info_t *rx_pkts, - uint16 pkt_count) -{ - uint16 count; - - DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__)); - count = 0; - while ((count < pkt_count) && rx_pkts) { - if (rx_pkts->info.pkt) - PKTFREE(dhdp->osh, rx_pkts->info.pkt, TRUE); - rx_pkts++; - count++; - } - - return BCME_OK; -} - -void -__dhd_dbg_dump_pkt_info(dhd_pub_t *dhdp, dhd_dbg_pkt_info_t *info) -{ - if (DHD_PKT_MON_DUMP_ON()) { - DHD_PKT_MON(("payload type = %d\n", info->payload_type)); - DHD_PKT_MON(("driver ts = %u\n", info->driver_ts)); - DHD_PKT_MON(("firmware ts = %u\n", info->firmware_ts)); - DHD_PKT_MON(("packet hash = %u\n", info->pkt_hash)); - DHD_PKT_MON(("packet length = %zu\n", info->pkt_len)); - DHD_PKT_MON(("packet address = %p\n", info->pkt)); - DHD_PKT_MON(("packet data = \n")); - if (DHD_PKT_MON_ON()) { - prhex(NULL, PKTDATA(dhdp->osh, info->pkt), info->pkt_len); - } - } -} - -void -__dhd_dbg_dump_tx_pkt_info(dhd_pub_t *dhdp, dhd_dbg_tx_info_t *tx_pkt, - uint16 count) -{ - if (DHD_PKT_MON_DUMP_ON()) { - DHD_PKT_MON(("\nTX (count: %d)\n", ++count)); - DHD_PKT_MON(("packet fate = %d\n", tx_pkt->fate)); - __dhd_dbg_dump_pkt_info(dhdp, &tx_pkt->info); - } -} - -void -__dhd_dbg_dump_rx_pkt_info(dhd_pub_t *dhdp, dhd_dbg_rx_info_t *rx_pkt, - uint16 count) -{ - if (DHD_PKT_MON_DUMP_ON()) { - DHD_PKT_MON(("\nRX (count: %d)\n", ++count)); - DHD_PKT_MON(("packet fate = %d\n", rx_pkt->fate)); - __dhd_dbg_dump_pkt_info(dhdp, &rx_pkt->info); - } -} - -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) -{ - - dhd_dbg_tx_report_t *tx_report = NULL; - dhd_dbg_rx_report_t *rx_report = NULL; - dhd_dbg_tx_info_t *tx_pkts = NULL; - dhd_dbg_rx_info_t *rx_pkts = NULL; - 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; - gfp_t kflags; - uint32 alloc_len; - int ret = BCME_OK; - unsigned long flags; - - DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__)); - if (!dhdp || !dhdp->dbg) { - DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, - dhdp, (dhdp ? dhdp->dbg : NULL))); - return -EINVAL; - } - - DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); - tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state; - tx_status_state = dhdp->dbg->pkt_mon.tx_pkt_state; - rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state; - - if (PKT_MON_ATTACHED(tx_pkt_state) || PKT_MON_ATTACHED(tx_status_state) || - PKT_MON_ATTACHED(rx_pkt_state)) { - DHD_PKT_MON(("%s(): packet monitor is already attached, " - "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n", - __FUNCTION__, tx_pkt_state, tx_status_state, rx_pkt_state)); - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - /* return success as the intention was to initialize packet monitor */ - return BCME_OK; - } - - kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - - /* allocate and initialize tx packet monitoring */ - alloc_len = sizeof(*tx_report); - tx_report = (dhd_dbg_tx_report_t *)kzalloc(alloc_len, kflags); - if (unlikely(!tx_report)) { - DHD_ERROR(("%s(): could not allocate memory for - " - "dhd_dbg_tx_report_t\n", __FUNCTION__)); - ret = -ENOMEM; - goto fail; - } - - alloc_len = (sizeof(*tx_pkts) * MAX_FATE_LOG_LEN); - tx_pkts = (dhd_dbg_tx_info_t *)kzalloc(alloc_len, kflags); - if (unlikely(!tx_pkts)) { - DHD_ERROR(("%s(): could not allocate memory for - " - "dhd_dbg_tx_info_t\n", __FUNCTION__)); - ret = -ENOMEM; - goto fail; - } - dhdp->dbg->pkt_mon.tx_report = tx_report; - dhdp->dbg->pkt_mon.tx_report->tx_pkts = tx_pkts; - dhdp->dbg->pkt_mon.tx_pkt_mon = tx_pkt_mon; - dhdp->dbg->pkt_mon.tx_status_mon = tx_status_mon; - dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_ATTACHED; - dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_ATTACHED; - - /* allocate and initialze rx packet monitoring */ - alloc_len = sizeof(*rx_report); - rx_report = (dhd_dbg_rx_report_t *)kzalloc(alloc_len, kflags); - if (unlikely(!rx_report)) { - DHD_ERROR(("%s(): could not allocate memory for - " - "dhd_dbg_rx_report_t\n", __FUNCTION__)); - ret = -ENOMEM; - goto fail; - } - - alloc_len = (sizeof(*rx_pkts) * MAX_FATE_LOG_LEN); - rx_pkts = (dhd_dbg_rx_info_t *)kzalloc(alloc_len, kflags); - if (unlikely(!rx_pkts)) { - DHD_ERROR(("%s(): could not allocate memory for - " - "dhd_dbg_rx_info_t\n", __FUNCTION__)); - ret = -ENOMEM; - goto fail; - } - dhdp->dbg->pkt_mon.rx_report = rx_report; - dhdp->dbg->pkt_mon.rx_report->rx_pkts = rx_pkts; - dhdp->dbg->pkt_mon.rx_pkt_mon = rx_pkt_mon; - dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_ATTACHED; - - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - DHD_PKT_MON(("%s(): packet monitor attach succeeded\n", __FUNCTION__)); - return ret; - -fail: - /* tx packet monitoring */ - if (tx_pkts) { - kfree(tx_pkts); - } - if (tx_report) { - kfree(tx_report); - } - dhdp->dbg->pkt_mon.tx_report = NULL; - dhdp->dbg->pkt_mon.tx_report->tx_pkts = NULL; - dhdp->dbg->pkt_mon.tx_pkt_mon = NULL; - dhdp->dbg->pkt_mon.tx_status_mon = NULL; - dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_DETACHED; - dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_DETACHED; - - /* rx packet monitoring */ - if (rx_pkts) { - kfree(rx_pkts); - } - if (rx_report) { - kfree(rx_report); - } - dhdp->dbg->pkt_mon.rx_report = NULL; - dhdp->dbg->pkt_mon.rx_report->rx_pkts = NULL; - dhdp->dbg->pkt_mon.rx_pkt_mon = NULL; - dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_DETACHED; - - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - DHD_ERROR(("%s(): packet monitor attach failed\n", __FUNCTION__)); - return ret; -} - -int -dhd_dbg_start_pkt_monitor(dhd_pub_t *dhdp) -{ - 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; - unsigned long flags; - - DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__)); - if (!dhdp || !dhdp->dbg) { - DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, - dhdp, (dhdp ? dhdp->dbg : NULL))); - return -EINVAL; - } - - DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); - tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state; - tx_status_state = dhdp->dbg->pkt_mon.tx_status_state; - rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state; - - if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state) || - PKT_MON_DETACHED(rx_pkt_state)) { - DHD_PKT_MON(("%s(): packet monitor is not yet enabled, " - "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n", - __FUNCTION__, tx_pkt_state, tx_status_state, rx_pkt_state)); - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - return -EINVAL; - } - - dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STARTING; - dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STARTING; - dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STARTING; - - tx_report = dhdp->dbg->pkt_mon.tx_report; - rx_report = dhdp->dbg->pkt_mon.rx_report; - if (!tx_report || !rx_report) { - DHD_PKT_MON(("%s(): tx_report=%p, rx_report=%p\n", - __FUNCTION__, tx_report, rx_report)); - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - return -EINVAL; - } - - - tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state; - tx_status_state = dhdp->dbg->pkt_mon.tx_status_state; - rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state; - - /* Safe to free packets as state pkt_state is STARTING */ - __dhd_dbg_free_tx_pkts(dhdp, tx_report->tx_pkts, tx_report->pkt_pos); - - __dhd_dbg_free_rx_pkts(dhdp, rx_report->rx_pkts, rx_report->pkt_pos); - - /* reset array postion */ - tx_report->pkt_pos = 0; - tx_report->status_pos = 0; - dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STARTED; - dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STARTED; - - rx_report->pkt_pos = 0; - dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STARTED; - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - - DHD_PKT_MON(("%s(): packet monitor started\n", __FUNCTION__)); - return BCME_OK; -} - -int -dhd_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid) -{ - dhd_dbg_tx_report_t *tx_report; - dhd_dbg_tx_info_t *tx_pkts; - dhd_dbg_pkt_mon_state_t tx_pkt_state; - uint32 pkt_hash, driver_ts; - uint16 pkt_pos; - unsigned long flags; - - if (!dhdp || !dhdp->dbg) { - DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, - dhdp, (dhdp ? dhdp->dbg : NULL))); - return -EINVAL; - } - - DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); - tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state; - if (PKT_MON_STARTED(tx_pkt_state)) { - tx_report = dhdp->dbg->pkt_mon.tx_report; - pkt_pos = tx_report->pkt_pos; - - if (!PKT_MON_PKT_FULL(pkt_pos)) { - tx_pkts = tx_report->tx_pkts; - pkt_hash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid); - driver_ts = __dhd_dbg_driver_ts_usec(); - - tx_pkts[pkt_pos].info.pkt = PKTDUP(dhdp->osh, pkt); - tx_pkts[pkt_pos].info.pkt_len = PKTLEN(dhdp->osh, pkt); - tx_pkts[pkt_pos].info.pkt_hash = pkt_hash; - tx_pkts[pkt_pos].info.driver_ts = driver_ts; - tx_pkts[pkt_pos].info.firmware_ts = 0U; - tx_pkts[pkt_pos].info.payload_type = FRAME_TYPE_ETHERNET_II; - tx_pkts[pkt_pos].fate = TX_PKT_FATE_DRV_QUEUED; - - tx_report->pkt_pos++; - } else { - dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STOPPED; - DHD_PKT_MON(("%s(): tx pkt logging stopped, reached " - "max limit\n", __FUNCTION__)); - } - } - - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - return BCME_OK; -} - -int -dhd_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid, - uint16 status) -{ - dhd_dbg_tx_report_t *tx_report; - dhd_dbg_tx_info_t *tx_pkt; - dhd_dbg_pkt_mon_state_t tx_status_state; - wifi_tx_packet_fate pkt_fate; - uint32 pkt_hash, temp_hash; - uint16 pkt_pos, status_pos; - int16 count; - bool found = FALSE; - unsigned long flags; - - if (!dhdp || !dhdp->dbg) { - DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, - dhdp, (dhdp ? dhdp->dbg : NULL))); - return -EINVAL; - } - - DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); - tx_status_state = dhdp->dbg->pkt_mon.tx_status_state; - if (PKT_MON_STARTED(tx_status_state)) { - tx_report = dhdp->dbg->pkt_mon.tx_report; - pkt_pos = tx_report->pkt_pos; - status_pos = tx_report->status_pos; - - if (!PKT_MON_STATUS_FULL(pkt_pos, status_pos)) { - pkt_hash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid); - pkt_fate = __dhd_dbg_map_tx_status_to_pkt_fate(status); - - /* best bet (in-order tx completion) */ - count = status_pos; - tx_pkt = (((dhd_dbg_tx_info_t *)tx_report->tx_pkts) + status_pos); - while ((count < pkt_pos) && tx_pkt) { - temp_hash = tx_pkt->info.pkt_hash; - if (temp_hash == pkt_hash) { - tx_pkt->fate = pkt_fate; - tx_report->status_pos++; - found = TRUE; - break; - } - tx_pkt++; - count++; - } - - /* search until beginning (handles out-of-order completion) */ - if (!found) { - count = status_pos - 1; - tx_pkt = (((dhd_dbg_tx_info_t *)tx_report->tx_pkts) + count); - while ((count >= 0) && tx_pkt) { - temp_hash = tx_pkt->info.pkt_hash; - if (temp_hash == pkt_hash) { - tx_pkt->fate = pkt_fate; - tx_report->status_pos++; - found = TRUE; - break; - } - tx_pkt--; - count--; - } - - if (!found) { - /* still couldn't match tx_status */ - DHD_ERROR(("%s(): couldn't match tx_status, pkt_pos=%u, " - "status_pos=%u, pkt_fate=%u\n", __FUNCTION__, - pkt_pos, status_pos, pkt_fate)); - } - } - } else { - dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STOPPED; - DHD_PKT_MON(("%s(): tx_status logging stopped, reached " - "max limit\n", __FUNCTION__)); - } - } - - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - return BCME_OK; -} - -int -dhd_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt) -{ - dhd_dbg_rx_report_t *rx_report; - dhd_dbg_rx_info_t *rx_pkts; - dhd_dbg_pkt_mon_state_t rx_pkt_state; - uint32 driver_ts; - uint16 pkt_pos; - unsigned long flags; - - if (!dhdp || !dhdp->dbg) { - DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, - dhdp, (dhdp ? dhdp->dbg : NULL))); - return -EINVAL; - } - - DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); - rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state; - if (PKT_MON_STARTED(rx_pkt_state)) { - rx_report = dhdp->dbg->pkt_mon.rx_report; - pkt_pos = rx_report->pkt_pos; - - if (!PKT_MON_PKT_FULL(pkt_pos)) { - rx_pkts = rx_report->rx_pkts; - driver_ts = __dhd_dbg_driver_ts_usec(); - - rx_pkts[pkt_pos].info.pkt = PKTDUP(dhdp->osh, pkt); - rx_pkts[pkt_pos].info.pkt_len = PKTLEN(dhdp->osh, pkt); - rx_pkts[pkt_pos].info.pkt_hash = 0U; - rx_pkts[pkt_pos].info.driver_ts = driver_ts; - rx_pkts[pkt_pos].info.firmware_ts = 0U; - rx_pkts[pkt_pos].info.payload_type = FRAME_TYPE_ETHERNET_II; - rx_pkts[pkt_pos].fate = RX_PKT_FATE_SUCCESS; - - rx_report->pkt_pos++; - } else { - dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STOPPED; - DHD_PKT_MON(("%s(): rx pkt logging stopped, reached " - "max limit\n", __FUNCTION__)); - } - } - - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - return BCME_OK; -} - -int -dhd_dbg_stop_pkt_monitor(dhd_pub_t *dhdp) -{ - 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; - unsigned long flags; - - DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__)); - if (!dhdp || !dhdp->dbg) { - DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, - dhdp, (dhdp ? dhdp->dbg : NULL))); - return -EINVAL; - } - - DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); - tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state; - tx_status_state = dhdp->dbg->pkt_mon.tx_status_state; - rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state; - - if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state) || - PKT_MON_DETACHED(rx_pkt_state)) { - DHD_PKT_MON(("%s(): packet monitor is not yet enabled, " - "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n", - __FUNCTION__, tx_pkt_state, tx_status_state, rx_pkt_state)); - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - return -EINVAL; - } - dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STOPPED; - dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STOPPED; - dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STOPPED; - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - - DHD_PKT_MON(("%s(): packet monitor stopped\n", __FUNCTION__)); - return BCME_OK; -} - -#define __COPY_TO_USER(to, from, n) \ - do { \ - int __ret; \ - __ret = copy_to_user((void __user *)(to), (void *)(from), \ - (unsigned long)(n)); \ - if (unlikely(__ret)) { \ - DHD_ERROR(("%s():%d: copy_to_user failed, ret=%d\n", \ - __FUNCTION__, __LINE__, __ret)); \ - return __ret; \ - } \ - } while (0); - -int -dhd_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf, - uint16 req_count, uint16 *resp_count) -{ - dhd_dbg_tx_report_t *tx_report; - dhd_dbg_tx_info_t *tx_pkt; - wifi_tx_report_t *ptr; - compat_wifi_tx_report_t *cptr; - dhd_dbg_pkt_mon_state_t tx_pkt_state; - dhd_dbg_pkt_mon_state_t tx_status_state; - uint16 pkt_count, count; - unsigned long flags; - - DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__)); - BCM_REFERENCE(ptr); - BCM_REFERENCE(cptr); - - if (!dhdp || !dhdp->dbg) { - DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, - dhdp, (dhdp ? dhdp->dbg : NULL))); - return -EINVAL; - } - - DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); - tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state; - tx_status_state = dhdp->dbg->pkt_mon.tx_status_state; - if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state)) { - DHD_PKT_MON(("%s(): packet monitor is not yet enabled, " - "tx_pkt_state=%d, tx_status_state=%d\n", __FUNCTION__, - tx_pkt_state, tx_status_state)); - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - return -EINVAL; - } - - count = 0; - tx_report = dhdp->dbg->pkt_mon.tx_report; - tx_pkt = tx_report->tx_pkts; - pkt_count = MIN(req_count, tx_report->status_pos); - -#ifdef CONFIG_COMPAT -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)) - if (in_compat_syscall()) -#else - if (is_compat_task()) -#endif - { - cptr = (compat_wifi_tx_report_t *)user_buf; - while ((count < pkt_count) && tx_pkt && cptr) { - compat_wifi_tx_report_t *comp_ptr = compat_ptr((uintptr_t) cptr); - compat_dhd_dbg_pkt_info_t compat_tx_pkt; - __dhd_dbg_dump_tx_pkt_info(dhdp, tx_pkt, count); - __COPY_TO_USER(&comp_ptr->fate, &tx_pkt->fate, sizeof(tx_pkt->fate)); - - compat_tx_pkt.payload_type = tx_pkt->info.payload_type; - compat_tx_pkt.pkt_len = tx_pkt->info.pkt_len; - compat_tx_pkt.driver_ts = tx_pkt->info.driver_ts; - compat_tx_pkt.firmware_ts = tx_pkt->info.firmware_ts; - compat_tx_pkt.pkt_hash = tx_pkt->info.pkt_hash; - __COPY_TO_USER(&comp_ptr->frame_inf.payload_type, - &compat_tx_pkt.payload_type, - OFFSETOF(compat_dhd_dbg_pkt_info_t, pkt_hash)); - __COPY_TO_USER(comp_ptr->frame_inf.frame_content.ethernet_ii, - PKTDATA(dhdp->osh, tx_pkt->info.pkt), tx_pkt->info.pkt_len); - - cptr++; - tx_pkt++; - count++; - } - } else -#endif /* CONFIG_COMPAT */ - - { - ptr = (wifi_tx_report_t *)user_buf; - while ((count < pkt_count) && tx_pkt && ptr) { - __dhd_dbg_dump_tx_pkt_info(dhdp, tx_pkt, count); - __COPY_TO_USER(&ptr->fate, &tx_pkt->fate, sizeof(tx_pkt->fate)); - __COPY_TO_USER(&ptr->frame_inf.payload_type, - &tx_pkt->info.payload_type, - OFFSETOF(dhd_dbg_pkt_info_t, pkt_hash)); - __COPY_TO_USER(ptr->frame_inf.frame_content.ethernet_ii, - PKTDATA(dhdp->osh, tx_pkt->info.pkt), tx_pkt->info.pkt_len); - - ptr++; - tx_pkt++; - count++; - } - } - *resp_count = pkt_count; - - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - if (!pkt_count) { - DHD_ERROR(("%s(): no tx_status in tx completion messages, " - "make sure that 'd11status' is enabled in firmware, " - "status_pos=%u\n", __FUNCTION__, pkt_count)); - } - - return BCME_OK; -} - -int -dhd_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf, - uint16 req_count, uint16 *resp_count) -{ - dhd_dbg_rx_report_t *rx_report; - dhd_dbg_rx_info_t *rx_pkt; - wifi_rx_report_t *ptr; - compat_wifi_rx_report_t *cptr; - dhd_dbg_pkt_mon_state_t rx_pkt_state; - uint16 pkt_count, count; - unsigned long flags; - - DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__)); - BCM_REFERENCE(ptr); - BCM_REFERENCE(cptr); - - if (!dhdp || !dhdp->dbg) { - DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, - dhdp, (dhdp ? dhdp->dbg : NULL))); - return -EINVAL; - } - - DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); - rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state; - if (PKT_MON_DETACHED(rx_pkt_state)) { - DHD_PKT_MON(("%s(): packet fetch is not allowed , " - "rx_pkt_state=%d\n", __FUNCTION__, rx_pkt_state)); - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - return -EINVAL; - } - - count = 0; - rx_report = dhdp->dbg->pkt_mon.rx_report; - rx_pkt = rx_report->rx_pkts; - pkt_count = MIN(req_count, rx_report->pkt_pos); - -#ifdef CONFIG_COMPAT -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)) - if (in_compat_syscall()) -#else - if (is_compat_task()) -#endif - { - cptr = (compat_wifi_rx_report_t *)user_buf; - while ((count < pkt_count) && rx_pkt && cptr) { - compat_wifi_rx_report_t *comp_ptr = compat_ptr((uintptr_t) cptr); - compat_dhd_dbg_pkt_info_t compat_rx_pkt; - __dhd_dbg_dump_rx_pkt_info(dhdp, rx_pkt, count); - __COPY_TO_USER(&comp_ptr->fate, &rx_pkt->fate, sizeof(rx_pkt->fate)); - - compat_rx_pkt.payload_type = rx_pkt->info.payload_type; - compat_rx_pkt.pkt_len = rx_pkt->info.pkt_len; - compat_rx_pkt.driver_ts = rx_pkt->info.driver_ts; - compat_rx_pkt.firmware_ts = rx_pkt->info.firmware_ts; - compat_rx_pkt.pkt_hash = rx_pkt->info.pkt_hash; - __COPY_TO_USER(&comp_ptr->frame_inf.payload_type, - &compat_rx_pkt.payload_type, - OFFSETOF(compat_dhd_dbg_pkt_info_t, pkt_hash)); - __COPY_TO_USER(comp_ptr->frame_inf.frame_content.ethernet_ii, - PKTDATA(dhdp->osh, rx_pkt->info.pkt), rx_pkt->info.pkt_len); - - cptr++; - rx_pkt++; - count++; - } - } else -#endif /* CONFIG_COMPAT */ - { - ptr = (wifi_rx_report_t *)user_buf; - while ((count < pkt_count) && rx_pkt && ptr) { - __dhd_dbg_dump_rx_pkt_info(dhdp, rx_pkt, count); - - __COPY_TO_USER(&ptr->fate, &rx_pkt->fate, sizeof(rx_pkt->fate)); - __COPY_TO_USER(&ptr->frame_inf.payload_type, - &rx_pkt->info.payload_type, - OFFSETOF(dhd_dbg_pkt_info_t, pkt_hash)); - __COPY_TO_USER(ptr->frame_inf.frame_content.ethernet_ii, - PKTDATA(dhdp->osh, rx_pkt->info.pkt), rx_pkt->info.pkt_len); - - ptr++; - rx_pkt++; - count++; - } - } - - *resp_count = pkt_count; - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - - return BCME_OK; -} - -int -dhd_dbg_detach_pkt_monitor(dhd_pub_t *dhdp) -{ - 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; - unsigned long flags; - - DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__)); - if (!dhdp || !dhdp->dbg) { - DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__, - dhdp, (dhdp ? dhdp->dbg : NULL))); - return -EINVAL; - } - - DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags); - tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state; - tx_status_state = dhdp->dbg->pkt_mon.tx_status_state; - rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state; - - if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state) || - PKT_MON_DETACHED(rx_pkt_state)) { - DHD_PKT_MON(("%s(): packet monitor is already detached, " - "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n", - __FUNCTION__, tx_pkt_state, tx_status_state, rx_pkt_state)); - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - return -EINVAL; - } - - tx_report = dhdp->dbg->pkt_mon.tx_report; - rx_report = dhdp->dbg->pkt_mon.rx_report; - - /* free and de-initalize tx packet monitoring */ - dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_DETACHED; - dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_DETACHED; - if (tx_report) { - if (tx_report->tx_pkts) { - __dhd_dbg_free_tx_pkts(dhdp, tx_report->tx_pkts, - tx_report->pkt_pos); - kfree(tx_report->tx_pkts); - dhdp->dbg->pkt_mon.tx_report->tx_pkts = NULL; - } - kfree(tx_report); - dhdp->dbg->pkt_mon.tx_report = NULL; - } - dhdp->dbg->pkt_mon.tx_pkt_mon = NULL; - dhdp->dbg->pkt_mon.tx_status_mon = NULL; - - /* free and de-initalize rx packet monitoring */ - dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_DETACHED; - if (rx_report) { - if (rx_report->rx_pkts) { - __dhd_dbg_free_rx_pkts(dhdp, rx_report->rx_pkts, - rx_report->pkt_pos); - kfree(rx_report->rx_pkts); - dhdp->dbg->pkt_mon.rx_report->rx_pkts = NULL; - } - kfree(rx_report); - dhdp->dbg->pkt_mon.rx_report = NULL; - } - dhdp->dbg->pkt_mon.rx_pkt_mon = NULL; - - DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags); - DHD_PKT_MON(("%s(): packet monitor detach succeeded\n", __FUNCTION__)); - return BCME_OK; -} -#endif /* DBG_PKT_MON */ - -/* - * dhd_dbg_attach: initialziation of dhd dbugability module - * - * Return: An error code or 0 on success. - */ -int -dhd_dbg_attach(dhd_pub_t *dhdp, dbg_pullreq_t os_pullreq, - dbg_urgent_noti_t os_urgent_notifier, void *os_priv) -{ - dhd_dbg_t *dbg; - int ret, ring_id; - - dbg = MALLOCZ(dhdp->osh, sizeof(dhd_dbg_t)); - if (!dbg) - return BCME_NOMEM; - - ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[FW_VERBOSE_RING_ID], FW_VERBOSE_RING_ID, - (uint8 *)FW_VERBOSE_RING_NAME, FW_VERBOSE_RING_SIZE, DHD_PREALLOC_FW_VERBOSE_RING); - if (ret) - goto error; - - ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[FW_EVENT_RING_ID], FW_EVENT_RING_ID, - (uint8 *)FW_EVENT_RING_NAME, FW_EVENT_RING_SIZE, DHD_PREALLOC_FW_EVENT_RING); - if (ret) - goto error; - - ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[DHD_EVENT_RING_ID], DHD_EVENT_RING_ID, - (uint8 *)DHD_EVENT_RING_NAME, DHD_EVENT_RING_SIZE, DHD_PREALLOC_DHD_EVENT_RING); - if (ret) - goto error; - - ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[NAN_EVENT_RING_ID], NAN_EVENT_RING_ID, - (uint8 *)NAN_EVENT_RING_NAME, NAN_EVENT_RING_SIZE, DHD_PREALLOC_NAN_EVENT_RING); - if (ret) - goto error; - - dbg->private = os_priv; - dbg->pullreq = os_pullreq; - dbg->urgent_notifier = os_urgent_notifier; - dhdp->dbg = dbg; - - return BCME_OK; - -error: - for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) { - if (VALID_RING(dbg->dbg_rings[ring_id].id)) { - dhd_dbg_ring_deinit(dhdp, &dbg->dbg_rings[ring_id]); - } - } - MFREE(dhdp->osh, dhdp->dbg, sizeof(dhd_dbg_t)); - - return ret; -} - -/* - * dhd_dbg_detach: clean up dhd dbugability module - */ -void -dhd_dbg_detach(dhd_pub_t *dhdp) -{ - int ring_id; - dhd_dbg_t *dbg; - if (!dhdp->dbg) - return; - dbg = dhdp->dbg; - for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) { - if (VALID_RING(dbg->dbg_rings[ring_id].id)) { - dhd_dbg_ring_deinit(dhdp, &dbg->dbg_rings[ring_id]); - } - } - MFREE(dhdp->osh, dhdp->dbg, sizeof(dhd_dbg_t)); -}
diff --git a/bcmdhd.1.579.77.41.x/dhd_debug.h b/bcmdhd.1.579.77.41.x/dhd_debug.h deleted file mode 100644 index 9337113..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_debug.h +++ /dev/null
@@ -1,868 +0,0 @@ -/* - * DHD debugability header file - * - * <<Broadcom-WL-IPTag/Open:>> - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_debug.h 705824 2017-06-19 13:58:39Z $ - */ - -#ifndef _dhd_debug_h_ -#define _dhd_debug_h_ -#include <event_log.h> -#include <bcmutils.h> - -enum { - DEBUG_RING_ID_INVALID = 0, - FW_VERBOSE_RING_ID, - FW_EVENT_RING_ID, - DHD_EVENT_RING_ID, - NAN_EVENT_RING_ID, - /* add new id here */ - DEBUG_RING_ID_MAX -}; - -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)) -}; - -#define DBGRING_NAME_MAX 32 -/* firmware verbose ring, ring id 1 */ -#define FW_VERBOSE_RING_NAME "fw_verbose" -#define FW_VERBOSE_RING_SIZE (64 * 1024) -/* 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 DBG_RING_STATUS_SIZE (sizeof(dhd_dbg_ring_status_t)) - -#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 */ - -#define TXACTIVESZ(r, w, d) (((r) <= (w)) ? ((w) - (r)) : ((d) - (r) + (w))) -#define DBG_RING_READ_AVAIL_SPACE(w, r, d) (((w) >= (r)) ? ((w) - (r)) : ((d) - (r))) -#define DBG_RING_WRITE_SPACE_AVAIL_CONT(r, w, d) (((w) >= (r)) ? ((d) - (w)) : ((r) - (w))) -#define DBG_RING_WRITE_SPACE_AVAIL(r, w, d) (d - (TXACTIVESZ(r, w, d))) -#define DBG_RING_CHECK_WRITE_SPACE(r, w, d) \ - MIN(DBG_RING_WRITE_SPACE_AVAIL(r, w, d), DBG_RING_WRITE_SPACE_AVAIL_CONT(r, w, d)) - -enum { - /* driver receive association command from kernel */ - WIFI_EVENT_ASSOCIATION_REQUESTED = 0, - 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 -}; - -typedef struct dhd_dbg_ring_entry { - uint16 len; /* payload length excluding the header */ - uint8 flags; - uint8 type; /* Per ring specific */ - uint64 timestamp; /* present if has_timestamp bit is set. */ -} PACKED_STRUCT dhd_dbg_ring_entry_t; - -#define DBG_RING_ENTRY_SIZE (sizeof(dhd_dbg_ring_entry_t)) - -#define ENTRY_LENGTH(hdr) ((hdr)->len + DBG_RING_ENTRY_SIZE) - -#define PAYLOAD_MAX_LEN 65535 - -typedef struct dhd_dbg_ring_status { - uint8 name[DBGRING_NAME_MAX]; - uint32 flags; - int ring_id; /* unique integer representing the ring */ - /* total memory size allocated for the buffer */ - uint32 ring_buffer_byte_size; - uint32 verbose_level; - /* number of bytes that was written to the buffer by driver */ - uint32 written_bytes; - /* number of bytes that was read from the buffer by user land */ - uint32 read_bytes; - /* number of records that was read from the buffer by user land */ - uint32 written_records; -} dhd_dbg_ring_status_t; - -struct log_level_table { - int log_level; - uint16 tag; - uint8 sets; - char *desc; -}; - -#ifdef DEBUGABILITY -#define DBG_EVENT_LOG(dhdp, connect_state) \ -{ \ - do { \ - uint16 state = connect_state; \ - if (DBG_RING_ACTIVE(dhdp, DHD_EVENT_RING_ID)) \ - dhd_os_push_push_ring_data(dhdp, DHD_EVENT_RING_ID, \ - &state, sizeof(state)); \ - } while (0); \ -} -#else -#define DBG_EVENT_LOG(dhdp, connect_state) -#endif /* DEBUGABILITY */ - - -#define 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 lack of buffer space. */ - TX_PKT_FATE_FW_DROP_NOBUFS, - - /* - * 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, - - } 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; - -enum dbg_ring_state { - RING_STOP = 0, /* ring is not initialized */ - RING_ACTIVE, /* ring is live and logging */ - RING_SUSPEND /* ring is initialized but not logging */ -}; - -struct ring_statistics { - /* number of bytes that was written to the buffer by driver */ - uint32 written_bytes; - /* number of bytes that was read from the buffer by user land */ - uint32 read_bytes; - /* number of records that was written to the buffer by driver */ - uint32 written_records; -}; - -typedef struct dhd_dbg_ring { - int id; /* ring id */ - uint8 name[DBGRING_NAME_MAX]; /* name string */ - uint32 ring_size; /* numbers of item in ring */ - uint32 wp; /* write pointer */ - uint32 rp; /* read pointer */ - uint32 log_level; /* log_level */ - uint32 threshold; /* threshold bytes */ - void * ring_buf; /* pointer of actually ring buffer */ - void * lock; /* spin lock for ring access */ - struct ring_statistics stat; /* statistics */ - enum dbg_ring_state state; /* ring state enum */ - bool tail_padded; /* writer does not have enough space */ - uint32 rem_len; /* number of bytes from wp_pad to end */ - bool sched_pull; /* schedule reader immediately */ -} dhd_dbg_ring_t; - -typedef struct dhd_dbg { - dhd_dbg_ring_t dbg_rings[DEBUG_RING_ID_MAX]; - void *private; /* os private_data */ - 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; - char buff[100]; -} dhd_iov_li_t; - -#define IOV_LIST_MAX_LEN 5 -#endif /* DUMP_IOCTL_IOV_LIST */ - -#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 */ - -/* dhd_dbg functions */ -extern void dhd_dbg_trace_evnt_handler(dhd_pub_t *dhdp, void *event_data, - void *raw_event_ptr, uint datalen); -extern int dhd_dbg_attach(dhd_pub_t *dhdp, dbg_pullreq_t os_pullreq, - dbg_urgent_noti_t os_urgent_notifier, void *os_priv); -extern void dhd_dbg_detach(dhd_pub_t *dhdp); -extern int dhd_dbg_start(dhd_pub_t *dhdp, bool start); -extern int dhd_dbg_set_configuration(dhd_pub_t *dhdp, int ring_id, - int log_level, int flags, uint32 threshold); -extern int dhd_dbg_get_ring_status(dhd_pub_t *dhdp, int ring_id, - dhd_dbg_ring_status_t *dbg_ring_status); -extern int dhd_dbg_ring_push(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_entry_t *hdr, void *data); -extern int dhd_dbg_ring_pull(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len); -extern int dhd_dbg_ring_pull_single(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len, - bool strip_header); -extern int dhd_dbg_find_ring_id(dhd_pub_t *dhdp, char *ring_name); -extern void *dhd_dbg_get_priv(dhd_pub_t *dhdp); -extern int dhd_dbg_send_urgent_evt(dhd_pub_t *dhdp, const void *data, const uint32 len); -extern void dhd_dbg_verboselog_printf(dhd_pub_t *dhdp, event_log_hdr_t *hdr, - void *raw_event_ptr, uint32 *log_ptr); - -#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 */ - -/* 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_ */
diff --git a/bcmdhd.1.579.77.41.x/dhd_debug_linux.c b/bcmdhd.1.579.77.41.x/dhd_debug_linux.c deleted file mode 100644 index 7137529..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_debug_linux.c +++ /dev/null
@@ -1,512 +0,0 @@ -/* - * DHD debugability Linux os layer - * - * <<Broadcom-WL-IPTag/Open:>> - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_debug_linux.c 710862 2017-07-14 07:43:59Z $ - */ - -#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, 0, "DRIVER EAPOL TX REQ"}, - {1, WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED, 0, "DRIVER EAPOL RX"}, - {2, WIFI_EVENT_DRIVER_SCAN_REQUESTED, 0, "SCAN_REQUESTED"}, - {2, WIFI_EVENT_DRIVER_SCAN_COMPLETE, 0, "SCAN COMPELETE"}, - {3, WIFI_EVENT_DRIVER_SCAN_RESULT_FOUND, 0, "SCAN RESULT FOUND"}, - {2, WIFI_EVENT_DRIVER_PNO_ADD, 0, "PNO ADD"}, - {2, WIFI_EVENT_DRIVER_PNO_REMOVE, 0, "PNO REMOVE"}, - {2, WIFI_EVENT_DRIVER_PNO_NETWORK_FOUND, 0, "PNO NETWORK FOUND"}, - {2, WIFI_EVENT_DRIVER_PNO_SCAN_REQUESTED, 0, "PNO SCAN_REQUESTED"}, - {1, WIFI_EVENT_DRIVER_PNO_SCAN_RESULT_FOUND, 0, "PNO SCAN RESULT FOUND"}, - {1, WIFI_EVENT_DRIVER_PNO_SCAN_COMPLETE, 0, "PNO SCAN COMPELETE"} -}; - -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 (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 - linux_dbgring_info_t *ring_info = - container_of(d_work, linux_dbgring_info_t, work); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - dhd_pub_t *dhdp = ring_info->dhdp; - int ringid = ring_info->ring_id; - 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]; - flags = dhd_os_spin_lock(ring->lock); - 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; - } - - rlen = dhd_dbg_ring_pull(dhdp, ringid, buf, buflen); - 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_os_spin_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; - uint32 ms; - - ring_id = dhd_dbg_find_ring_id(dhdp, ring_name); - if (!VALID_RING(ring_id)) - return BCME_UNSUPPORTED; - - DHD_DBGIF(("%s , log_level : %d, time_intval : %d, threshod %d Bytes\n", - __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 (ring_id == FW_VERBOSE_RING_ID || ring_id == FW_EVENT_RING_ID) { - ring_info->tsoffset = local_clock(); - if (dhd_wl_ioctl_get_intiovar(dhdp, "rte_timesync", &ms, WLC_GET_VAR, - FALSE, 0)) - DHD_ERROR(("%s rte_timesync failed\n", __FUNCTION__)); - do_div(ring_info->tsoffset, 1000000); - ring_info->tsoffset -= ms; - } - if (time_intval == 0 || log_level == 0) { - ring_info->interval = 0; - cancel_delayed_work_sync(&ring_info->work); - } 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 = MAX(os_priv[FW_VERBOSE_RING_ID].log_level, - os_priv[FW_EVENT_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 */ - do_div(msg_hdr.timestamp, 1000000); - 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_ring_push(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; - *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 */ - 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); -}
diff --git a/bcmdhd.1.579.77.41.x/dhd_flowring.c b/bcmdhd.1.579.77.41.x/dhd_flowring.c deleted file mode 100644 index 17a9dc3..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_flowring.c +++ /dev/null
@@ -1,1063 +0,0 @@ -/* - * @file Broadcom Dongle Host Driver (DHD), Flow ring specific code at top level - * - * Flow rings are transmit traffic (=propagating towards antenna) related entities - * - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_flowring.c 710862 2017-07-14 07:43:59Z $ - */ - - -#include <typedefs.h> -#include <bcmutils.h> -#include <bcmendian.h> -#include <bcmdevs.h> - -#include <ethernet.h> -#include <bcmevent.h> -#include <dngl_stats.h> - -#include <dhd.h> - -#include <dhd_flowring.h> -#include <dhd_bus.h> -#include <dhd_proto.h> -#include <dhd_dbg.h> -#include <802.1d.h> -#include <pcie_core.h> -#include <bcmmsgbuf.h> -#include <dhd_pcie.h> - -static INLINE int dhd_flow_queue_throttle(flow_queue_t *queue); - -static INLINE uint16 dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex, - uint8 prio, char *sa, char *da); - -static INLINE uint16 dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex, - uint8 prio, char *sa, char *da); - -static INLINE int dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex, - uint8 prio, char *sa, char *da, uint16 *flowid); -int BCMFASTPATH dhd_flow_queue_overflow(flow_queue_t *queue, void *pkt); - -#define FLOW_QUEUE_PKT_NEXT(p) PKTLINK(p) -#define FLOW_QUEUE_PKT_SETNEXT(p, x) PKTSETLINK((p), (x)) - -#if defined(EAPOL_PKT_PRIO) || defined(DHD_LOSSLESS_ROAMING) -const uint8 prio2ac[8] = { 0, 1, 1, 0, 2, 2, 3, 7 }; -#else -const uint8 prio2ac[8] = { 0, 1, 1, 0, 2, 2, 3, 3 }; -#endif /* EAPOL_PKT_PRIO || DHD_LOSSLESS_ROAMING */ -const uint8 prio2tid[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; - -/** Queue overflow throttle. Return value: TRUE if throttle needs to be applied */ -static INLINE int -dhd_flow_queue_throttle(flow_queue_t *queue) -{ - return DHD_FLOW_QUEUE_FULL(queue); -} - -int BCMFASTPATH -dhd_flow_queue_overflow(flow_queue_t *queue, void *pkt) -{ - return BCME_NORESOURCE; -} - -/** Returns flow ring given a flowid */ -flow_ring_node_t * -dhd_flow_ring_node(dhd_pub_t *dhdp, uint16 flowid) -{ - flow_ring_node_t * flow_ring_node; - - ASSERT(dhdp != (dhd_pub_t*)NULL); - ASSERT(flowid < dhdp->num_flow_rings); - - flow_ring_node = &(((flow_ring_node_t*)(dhdp->flow_ring_table))[flowid]); - - ASSERT(flow_ring_node->flowid == flowid); - return flow_ring_node; -} - -/** Returns 'backup' queue given a flowid */ -flow_queue_t * -dhd_flow_queue(dhd_pub_t *dhdp, uint16 flowid) -{ - flow_ring_node_t * flow_ring_node; - - flow_ring_node = dhd_flow_ring_node(dhdp, flowid); - return &flow_ring_node->queue; -} - -/* Flow ring's queue management functions */ - -/** Reinitialize a flow ring's queue. */ -void -dhd_flow_queue_reinit(dhd_pub_t *dhdp, flow_queue_t *queue, int max) -{ - ASSERT((queue != NULL) && (max > 0)); - - queue->head = queue->tail = NULL; - queue->len = 0; - - /* Set queue's threshold and queue's parent cummulative length counter */ - ASSERT(max > 1); - DHD_FLOW_QUEUE_SET_MAX(queue, max); - DHD_FLOW_QUEUE_SET_THRESHOLD(queue, max); - DHD_FLOW_QUEUE_SET_CLEN(queue, &dhdp->cumm_ctr); - DHD_FLOW_QUEUE_SET_L2CLEN(queue, &dhdp->l2cumm_ctr); - - queue->failures = 0U; - queue->cb = &dhd_flow_queue_overflow; -} - -/** Initialize a flow ring's queue, called on driver initialization. */ -void -dhd_flow_queue_init(dhd_pub_t *dhdp, flow_queue_t *queue, int max) -{ - ASSERT((queue != NULL) && (max > 0)); - - dll_init(&queue->list); - dhd_flow_queue_reinit(dhdp, queue, max); -} - -/** Register an enqueue overflow callback handler */ -void -dhd_flow_queue_register(flow_queue_t *queue, flow_queue_cb_t cb) -{ - ASSERT(queue != NULL); - queue->cb = cb; -} - -/** - * Enqueue an 802.3 packet at the back of a flow ring's queue. From there, it will travel later on - * to the flow ring itself. - */ -int BCMFASTPATH -dhd_flow_queue_enqueue(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt) -{ - int ret = BCME_OK; - - ASSERT(queue != NULL); - - if (dhd_flow_queue_throttle(queue)) { - queue->failures++; - ret = (*queue->cb)(queue, pkt); - goto done; - } - - if (queue->head) { - FLOW_QUEUE_PKT_SETNEXT(queue->tail, pkt); - } else { - queue->head = pkt; - } - - FLOW_QUEUE_PKT_SETNEXT(pkt, NULL); - - queue->tail = pkt; /* at tail */ - - queue->len++; - /* increment parent's cummulative length */ - DHD_CUMM_CTR_INCR(DHD_FLOW_QUEUE_CLEN_PTR(queue)); - /* increment grandparent's cummulative length */ - DHD_CUMM_CTR_INCR(DHD_FLOW_QUEUE_L2CLEN_PTR(queue)); - -done: - return ret; -} - -/** Dequeue an 802.3 packet from a flow ring's queue, from head (FIFO) */ -void * BCMFASTPATH -dhd_flow_queue_dequeue(dhd_pub_t *dhdp, flow_queue_t *queue) -{ - void * pkt; - - ASSERT(queue != NULL); - - pkt = queue->head; /* from head */ - - if (pkt == NULL) { - ASSERT((queue->len == 0) && (queue->tail == NULL)); - goto done; - } - - queue->head = FLOW_QUEUE_PKT_NEXT(pkt); - if (queue->head == NULL) - queue->tail = NULL; - - queue->len--; - /* decrement parent's cummulative length */ - DHD_CUMM_CTR_DECR(DHD_FLOW_QUEUE_CLEN_PTR(queue)); - /* decrement grandparent's cummulative length */ - DHD_CUMM_CTR_DECR(DHD_FLOW_QUEUE_L2CLEN_PTR(queue)); - - FLOW_QUEUE_PKT_SETNEXT(pkt, NULL); /* dettach packet from queue */ - -done: - return pkt; -} - -/** Reinsert a dequeued 802.3 packet back at the head */ -void BCMFASTPATH -dhd_flow_queue_reinsert(dhd_pub_t *dhdp, flow_queue_t *queue, void *pkt) -{ - if (queue->head == NULL) { - queue->tail = pkt; - } - - FLOW_QUEUE_PKT_SETNEXT(pkt, queue->head); - queue->head = pkt; - queue->len++; - /* increment parent's cummulative length */ - DHD_CUMM_CTR_INCR(DHD_FLOW_QUEUE_CLEN_PTR(queue)); - /* increment grandparent's cummulative length */ - DHD_CUMM_CTR_INCR(DHD_FLOW_QUEUE_L2CLEN_PTR(queue)); -} - -/** Fetch the backup queue for a flowring, and assign flow control thresholds */ -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) -{ - flow_queue_t * queue; - - ASSERT(dhdp != (dhd_pub_t*)NULL); - ASSERT(queue_budget > 1); - ASSERT(cumm_threshold > 1); - ASSERT(cumm_ctr != (void*)NULL); - ASSERT(l2cumm_threshold > 1); - ASSERT(l2cumm_ctr != (void*)NULL); - - queue = dhd_flow_queue(dhdp, flowid); - - DHD_FLOW_QUEUE_SET_MAX(queue, queue_budget); /* Max queue length */ - - /* Set the queue's parent threshold and cummulative counter */ - DHD_FLOW_QUEUE_SET_THRESHOLD(queue, cumm_threshold); - DHD_FLOW_QUEUE_SET_CLEN(queue, cumm_ctr); - - /* Set the queue's grandparent threshold and cummulative counter */ - DHD_FLOW_QUEUE_SET_L2THRESHOLD(queue, l2cumm_threshold); - DHD_FLOW_QUEUE_SET_L2CLEN(queue, l2cumm_ctr); -} - -/** Initializes data structures of multiple flow rings */ -int -dhd_flow_rings_init(dhd_pub_t *dhdp, uint32 num_flow_rings) -{ - uint32 idx; - uint32 flow_ring_table_sz; - uint32 if_flow_lkup_sz = 0; - void * flowid_allocator; - flow_ring_table_t *flow_ring_table = NULL; - if_flow_lkup_t *if_flow_lkup = NULL; - void *lock = NULL; - void *list_lock = NULL; - unsigned long flags; - - DHD_INFO(("%s\n", __FUNCTION__)); - - /* Construct a 16bit flowid allocator */ - flowid_allocator = id16_map_init(dhdp->osh, - num_flow_rings - dhdp->bus->max_cmn_rings, FLOWID_RESERVED); - if (flowid_allocator == NULL) { - DHD_ERROR(("%s: flowid allocator init failure\n", __FUNCTION__)); - return BCME_NOMEM; - } - - /* Allocate a flow ring table, comprising of requested number of rings */ - flow_ring_table_sz = (num_flow_rings * sizeof(flow_ring_node_t)); - flow_ring_table = (flow_ring_table_t *)MALLOCZ(dhdp->osh, flow_ring_table_sz); - if (flow_ring_table == NULL) { - DHD_ERROR(("%s: flow ring table alloc failure\n", __FUNCTION__)); - goto fail; - } - - /* Initialize flow ring table state */ - DHD_CUMM_CTR_INIT(&dhdp->cumm_ctr); - DHD_CUMM_CTR_INIT(&dhdp->l2cumm_ctr); - bzero((uchar *)flow_ring_table, flow_ring_table_sz); - for (idx = 0; idx < num_flow_rings; idx++) { - flow_ring_table[idx].status = FLOW_RING_STATUS_CLOSED; - flow_ring_table[idx].flowid = (uint16)idx; - flow_ring_table[idx].lock = dhd_os_spin_lock_init(dhdp->osh); -#ifdef IDLE_TX_FLOW_MGMT - flow_ring_table[idx].last_active_ts = OSL_SYSUPTIME(); -#endif /* IDLE_TX_FLOW_MGMT */ - if (flow_ring_table[idx].lock == NULL) { - DHD_ERROR(("%s: Failed to init spinlock for queue!\n", __FUNCTION__)); - goto fail; - } - - dll_init(&flow_ring_table[idx].list); - - /* Initialize the per flow ring backup queue */ - dhd_flow_queue_init(dhdp, &flow_ring_table[idx].queue, - FLOW_RING_QUEUE_THRESHOLD); - } - - /* Allocate per interface hash table (for fast lookup from interface to flow ring) */ - if_flow_lkup_sz = sizeof(if_flow_lkup_t) * DHD_MAX_IFS; - if_flow_lkup = (if_flow_lkup_t *)DHD_OS_PREALLOC(dhdp, - DHD_PREALLOC_IF_FLOW_LKUP, if_flow_lkup_sz); - if (if_flow_lkup == NULL) { - DHD_ERROR(("%s: if flow lkup alloc failure\n", __FUNCTION__)); - goto fail; - } - - /* Initialize per interface hash table */ - for (idx = 0; idx < DHD_MAX_IFS; idx++) { - int hash_ix; - if_flow_lkup[idx].status = 0; - if_flow_lkup[idx].role = 0; - for (hash_ix = 0; hash_ix < DHD_FLOWRING_HASH_SIZE; hash_ix++) - if_flow_lkup[idx].fl_hash[hash_ix] = NULL; - } - - lock = dhd_os_spin_lock_init(dhdp->osh); - if (lock == NULL) - goto fail; - - list_lock = dhd_os_spin_lock_init(dhdp->osh); - if (list_lock == NULL) - goto lock_fail; - - dhdp->flow_prio_map_type = DHD_FLOW_PRIO_AC_MAP; - bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); -#ifdef DHD_LOSSLESS_ROAMING - dhdp->dequeue_prec_map = ALLPRIO; -#endif - /* Now populate into dhd pub */ - DHD_FLOWID_LOCK(lock, flags); - dhdp->num_flow_rings = num_flow_rings; - dhdp->flowid_allocator = (void *)flowid_allocator; - dhdp->flow_ring_table = (void *)flow_ring_table; - dhdp->if_flow_lkup = (void *)if_flow_lkup; - dhdp->flowid_lock = lock; - dhdp->flow_rings_inited = TRUE; - dhdp->flowring_list_lock = list_lock; - DHD_FLOWID_UNLOCK(lock, flags); - - DHD_INFO(("%s done\n", __FUNCTION__)); - return BCME_OK; - -lock_fail: - /* deinit the spinlock */ - dhd_os_spin_lock_deinit(dhdp->osh, lock); - -fail: - /* Destruct the per interface flow lkup table */ - if (if_flow_lkup != NULL) { - DHD_OS_PREFREE(dhdp, if_flow_lkup, if_flow_lkup_sz); - } - if (flow_ring_table != NULL) { - for (idx = 0; idx < num_flow_rings; idx++) { - if (flow_ring_table[idx].lock != NULL) - dhd_os_spin_lock_deinit(dhdp->osh, flow_ring_table[idx].lock); - } - MFREE(dhdp->osh, flow_ring_table, flow_ring_table_sz); - } - id16_map_fini(dhdp->osh, flowid_allocator); - - return BCME_NOMEM; -} - -/** Deinit Flow Ring specific data structures */ -void dhd_flow_rings_deinit(dhd_pub_t *dhdp) -{ - uint16 idx; - uint32 flow_ring_table_sz; - uint32 if_flow_lkup_sz; - flow_ring_table_t *flow_ring_table; - unsigned long flags; - void *lock; - - DHD_INFO(("dhd_flow_rings_deinit\n")); - - if (!(dhdp->flow_rings_inited)) { - DHD_ERROR(("dhd_flow_rings not initialized!\n")); - return; - } - - if (dhdp->flow_ring_table != NULL) { - - ASSERT(dhdp->num_flow_rings > 0); - - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; - dhdp->flow_ring_table = NULL; - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - for (idx = 0; idx < dhdp->num_flow_rings; idx++) { - if (flow_ring_table[idx].active) { - dhd_bus_clean_flow_ring(dhdp->bus, &flow_ring_table[idx]); - } - ASSERT(DHD_FLOW_QUEUE_EMPTY(&flow_ring_table[idx].queue)); - - /* Deinit flow ring queue locks before destroying flow ring table */ - if (flow_ring_table[idx].lock != NULL) { - dhd_os_spin_lock_deinit(dhdp->osh, flow_ring_table[idx].lock); - } - flow_ring_table[idx].lock = NULL; - - } - - /* Destruct the flow ring table */ - flow_ring_table_sz = dhdp->num_flow_rings * sizeof(flow_ring_table_t); - MFREE(dhdp->osh, flow_ring_table, flow_ring_table_sz); - } - - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - - /* Destruct the per interface flow lkup table */ - if (dhdp->if_flow_lkup != NULL) { - if_flow_lkup_sz = sizeof(if_flow_lkup_t) * DHD_MAX_IFS; - bzero((uchar *)dhdp->if_flow_lkup, if_flow_lkup_sz); - DHD_OS_PREFREE(dhdp, dhdp->if_flow_lkup, if_flow_lkup_sz); - dhdp->if_flow_lkup = NULL; - } - - /* Destruct the flowid allocator */ - if (dhdp->flowid_allocator != NULL) - dhdp->flowid_allocator = id16_map_fini(dhdp->osh, dhdp->flowid_allocator); - - dhdp->num_flow_rings = 0U; - bzero(dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); - - lock = dhdp->flowid_lock; - dhdp->flowid_lock = NULL; - - if (lock) { - DHD_FLOWID_UNLOCK(lock, flags); - dhd_os_spin_lock_deinit(dhdp->osh, lock); - } - - dhd_os_spin_lock_deinit(dhdp->osh, dhdp->flowring_list_lock); - dhdp->flowring_list_lock = NULL; - - ASSERT(dhdp->if_flow_lkup == NULL); - ASSERT(dhdp->flowid_allocator == NULL); - ASSERT(dhdp->flow_ring_table == NULL); - dhdp->flow_rings_inited = FALSE; -} - -/** Uses hash table to quickly map from ifindex to a flow ring 'role' (STA/AP) */ -uint8 -dhd_flow_rings_ifindex2role(dhd_pub_t *dhdp, uint8 ifindex) -{ - if_flow_lkup_t *if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - ASSERT(if_flow_lkup); - return if_flow_lkup[ifindex].role; -} - -#ifdef WLTDLS -bool is_tdls_destination(dhd_pub_t *dhdp, uint8 *da) -{ - unsigned long flags; - tdls_peer_node_t *cur = NULL; - - DHD_TDLS_LOCK(&dhdp->tdls_lock, flags); - cur = dhdp->peer_tbl.node; - - while (cur != NULL) { - if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) { - DHD_TDLS_UNLOCK(&dhdp->tdls_lock, flags); - return TRUE; - } - cur = cur->next; - } - DHD_TDLS_UNLOCK(&dhdp->tdls_lock, flags); - return FALSE; -} -#endif /* WLTDLS */ - -/** Uses hash table to quickly map from ifindex+prio+da to a flow ring id */ -static INLINE uint16 -dhd_flowid_find(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da) -{ - int hash; - bool ismcast = FALSE; - flow_hash_info_t *cur; - if_flow_lkup_t *if_flow_lkup; - unsigned long flags; - - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - - ASSERT(if_flow_lkup); - - if ((if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_STA) || - (if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_WDS)) { -#ifdef WLTDLS - if (dhdp->peer_tbl.tdls_peer_count && !(ETHER_ISMULTI(da)) && - is_tdls_destination(dhdp, da)) { - hash = DHD_FLOWRING_HASHINDEX(da, prio); - cur = if_flow_lkup[ifindex].fl_hash[hash]; - while (cur != NULL) { - if (!memcmp(cur->flow_info.da, da, ETHER_ADDR_LEN)) { - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - return cur->flowid; - } - cur = cur->next; - } - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - return FLOWID_INVALID; - } -#endif /* WLTDLS */ - /* For STA non TDLS dest and WDS dest flow ring id is mapped based on prio only */ - cur = if_flow_lkup[ifindex].fl_hash[prio]; - if (cur) { - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - return cur->flowid; - } - } else { - - if (ETHER_ISMULTI(da)) { - ismcast = TRUE; - hash = 0; - } else { - hash = DHD_FLOWRING_HASHINDEX(da, prio); - } - - cur = if_flow_lkup[ifindex].fl_hash[hash]; - - while (cur) { - if ((ismcast && ETHER_ISMULTI(cur->flow_info.da)) || - (!memcmp(cur->flow_info.da, da, ETHER_ADDR_LEN) && - (cur->flow_info.tid == prio))) { - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - return cur->flowid; - } - cur = cur->next; - } - } - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - - DHD_INFO(("%s: cannot find flowid\n", __FUNCTION__)); - return FLOWID_INVALID; -} /* dhd_flowid_find */ - -/** Create unique Flow ID, called when a flow ring is created. */ -static INLINE uint16 -dhd_flowid_alloc(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, char *sa, char *da) -{ - flow_hash_info_t *fl_hash_node, *cur; - if_flow_lkup_t *if_flow_lkup; - int hash; - uint16 flowid; - unsigned long flags; - - fl_hash_node = (flow_hash_info_t *) MALLOCZ(dhdp->osh, sizeof(flow_hash_info_t)); - if (fl_hash_node == NULL) { - DHD_ERROR(("%s: flow_hash_info_t memory allocation failed \n", __FUNCTION__)); - return FLOWID_INVALID; - } - memcpy(fl_hash_node->flow_info.da, da, sizeof(fl_hash_node->flow_info.da)); - - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - ASSERT(dhdp->flowid_allocator != NULL); - flowid = id16_map_alloc(dhdp->flowid_allocator); - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - - if (flowid == FLOWID_INVALID) { - MFREE(dhdp->osh, fl_hash_node, sizeof(flow_hash_info_t)); - DHD_ERROR(("%s: cannot get free flowid \n", __FUNCTION__)); - return FLOWID_INVALID; - } - - fl_hash_node->flowid = flowid; - fl_hash_node->flow_info.tid = prio; - fl_hash_node->flow_info.ifindex = ifindex; - fl_hash_node->next = NULL; - - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - - if ((if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_STA) || - (if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_WDS)) { - /* For STA non TDLS dest and WDS dest we allocate entry based on prio only */ -#ifdef WLTDLS - if (dhdp->peer_tbl.tdls_peer_count && - (is_tdls_destination(dhdp, da))) { - hash = DHD_FLOWRING_HASHINDEX(da, prio); - cur = if_flow_lkup[ifindex].fl_hash[hash]; - if (cur) { - while (cur->next) { - cur = cur->next; - } - cur->next = fl_hash_node; - } else { - if_flow_lkup[ifindex].fl_hash[hash] = fl_hash_node; - } - } else -#endif /* WLTDLS */ - if_flow_lkup[ifindex].fl_hash[prio] = fl_hash_node; - } else { - - /* For bcast/mcast assign first slot in in interface */ - hash = ETHER_ISMULTI(da) ? 0 : DHD_FLOWRING_HASHINDEX(da, prio); - cur = if_flow_lkup[ifindex].fl_hash[hash]; - if (cur) { - while (cur->next) { - cur = cur->next; - } - cur->next = fl_hash_node; - } else - if_flow_lkup[ifindex].fl_hash[hash] = fl_hash_node; - } - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - - DHD_INFO(("%s: allocated flowid %d\n", __FUNCTION__, fl_hash_node->flowid)); - - return fl_hash_node->flowid; -} /* dhd_flowid_alloc */ - -/** Get flow ring ID, if not present try to create one */ -static INLINE int -dhd_flowid_lookup(dhd_pub_t *dhdp, uint8 ifindex, - uint8 prio, char *sa, char *da, uint16 *flowid) -{ - uint16 id; - flow_ring_node_t *flow_ring_node; - flow_ring_table_t *flow_ring_table; - unsigned long flags; - int ret; - bool is_sta_assoc; - - DHD_INFO(("%s\n", __FUNCTION__)); - if (!dhdp->flow_ring_table) { - return BCME_ERROR; - } - - flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; - - id = dhd_flowid_find(dhdp, ifindex, prio, sa, da); - - if (id == FLOWID_INVALID) { - - if_flow_lkup_t *if_flow_lkup; - if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - - if (!if_flow_lkup[ifindex].status) - return BCME_ERROR; - BCM_REFERENCE(is_sta_assoc); -#if defined(PCIE_FULL_DONGLE) - is_sta_assoc = dhd_sta_associated(dhdp, ifindex, (uint8 *)da); - DHD_ERROR(("%s: multi %x ifindex %d role %x assoc %d\n", __FUNCTION__, - ETHER_ISMULTI(da), ifindex, if_flow_lkup[ifindex].role, - is_sta_assoc)); - if (!ETHER_ISMULTI(da) && - ((if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_AP) || - (if_flow_lkup[ifindex].role == WLC_E_IF_ROLE_P2P_GO)) && - (!is_sta_assoc)) - return BCME_ERROR; -#endif /* (linux || LINUX) && PCIE_FULL_DONGLE */ - - id = dhd_flowid_alloc(dhdp, ifindex, prio, sa, da); - if (id == FLOWID_INVALID) { - DHD_ERROR(("%s: alloc flowid ifindex %u status %u\n", - __FUNCTION__, ifindex, if_flow_lkup[ifindex].status)); - return BCME_ERROR; - } - - ASSERT(id < dhdp->num_flow_rings); - - /* register this flowid in dhd_pub */ - dhd_add_flowid(dhdp, ifindex, prio, da, id); - - flow_ring_node = (flow_ring_node_t *) &flow_ring_table[id]; - - DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); - - /* Init Flow info */ - memcpy(flow_ring_node->flow_info.sa, sa, sizeof(flow_ring_node->flow_info.sa)); - memcpy(flow_ring_node->flow_info.da, da, sizeof(flow_ring_node->flow_info.da)); - flow_ring_node->flow_info.tid = prio; - flow_ring_node->flow_info.ifindex = ifindex; - flow_ring_node->active = TRUE; - flow_ring_node->status = FLOW_RING_STATUS_CREATE_PENDING; - -#ifdef DEVICE_TX_STUCK_DETECT - flow_ring_node->tx_cmpl = flow_ring_node->tx_cmpl_prev = OSL_SYSUPTIME(); - flow_ring_node->stuck_count = 0; -#endif /* DEVICE_TX_STUCK_DETECT */ - - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - - /* Create and inform device about the new flow */ - if (dhd_bus_flow_ring_create_request(dhdp->bus, (void *)flow_ring_node) - != BCME_OK) { - DHD_ERROR(("%s: create error %d\n", __FUNCTION__, id)); - return BCME_ERROR; - } - - *flowid = id; - return BCME_OK; - } else { - /* if the Flow id was found in the hash */ - ASSERT(id < dhdp->num_flow_rings); - - flow_ring_node = (flow_ring_node_t *) &flow_ring_table[id]; - DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); - - /* - * If the flow_ring_node is in Open State or Status pending state then - * we can return the Flow id to the caller.If the flow_ring_node is in - * FLOW_RING_STATUS_PENDING this means the creation is in progress and - * hence the packets should be queued. - * - * If the flow_ring_node is in FLOW_RING_STATUS_DELETE_PENDING Or - * FLOW_RING_STATUS_CLOSED, then we should return Error. - * Note that if the flowing is being deleted we would mark it as - * FLOW_RING_STATUS_DELETE_PENDING. Now before Dongle could respond and - * before we mark it as FLOW_RING_STATUS_CLOSED we could get tx packets. - * We should drop the packets in that case. - * The decission to return OK should NOT be based on 'active' variable, beause - * active is made TRUE when a flow_ring_node gets allocated and is made - * FALSE when the flow ring gets removed and does not reflect the True state - * of the Flow ring. - * In case if IDLE_TX_FLOW_MGMT is defined, we have to handle two more flowring - * states. If the flow_ring_node's status is FLOW_RING_STATUS_SUSPENDED, the flowid - * is to be returned and from dhd_bus_txdata, the flowring would be resumed again. - * The status FLOW_RING_STATUS_RESUME_PENDING, is equivalent to - * FLOW_RING_STATUS_CREATE_PENDING. - */ - if (flow_ring_node->status == FLOW_RING_STATUS_DELETE_PENDING || - flow_ring_node->status == FLOW_RING_STATUS_CLOSED) { - *flowid = FLOWID_INVALID; - ret = BCME_ERROR; - } else { - *flowid = id; - ret = BCME_OK; - } - - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - return ret; - } /* Flow Id found in the hash */ -} /* dhd_flowid_lookup */ - -/** - * Assign existing or newly created flowid to an 802.3 packet. This flowid is later on used to - * select the flowring to send the packet to the dongle. - */ -int BCMFASTPATH -dhd_flowid_update(dhd_pub_t *dhdp, uint8 ifindex, uint8 prio, void *pktbuf) -{ - uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); - struct ether_header *eh = (struct ether_header *)pktdata; - uint16 flowid; - - ASSERT(ifindex < DHD_MAX_IFS); - - if (ifindex >= DHD_MAX_IFS) { - return BCME_BADARG; - } - - if (!dhdp->flowid_allocator) { - DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__)); - return BCME_ERROR; - } - - if (dhd_flowid_lookup(dhdp, ifindex, prio, (char *)eh->ether_shost, (char *)eh->ether_dhost, - &flowid) != BCME_OK) { - return BCME_ERROR; - } - - DHD_INFO(("%s: prio %d flowid %d\n", __FUNCTION__, prio, flowid)); - - /* Tag the packet with flowid */ - DHD_PKT_SET_FLOWID(pktbuf, flowid); - return BCME_OK; -} - -void -dhd_flowid_free(dhd_pub_t *dhdp, uint8 ifindex, uint16 flowid) -{ - int hashix; - bool found = FALSE; - flow_hash_info_t *cur, *prev; - if_flow_lkup_t *if_flow_lkup; - unsigned long flags; - - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - - for (hashix = 0; hashix < DHD_FLOWRING_HASH_SIZE; hashix++) { - - cur = if_flow_lkup[ifindex].fl_hash[hashix]; - - if (cur) { - if (cur->flowid == flowid) { - found = TRUE; - } - - prev = NULL; - while (!found && cur) { - if (cur->flowid == flowid) { - found = TRUE; - break; - } - prev = cur; - cur = cur->next; - } - if (found) { - if (!prev) { - if_flow_lkup[ifindex].fl_hash[hashix] = cur->next; - } else { - prev->next = cur->next; - } - - /* deregister flowid from dhd_pub. */ - dhd_del_flowid(dhdp, ifindex, flowid); - - id16_map_free(dhdp->flowid_allocator, flowid); - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - MFREE(dhdp->osh, cur, sizeof(flow_hash_info_t)); - - return; - } - } - } - - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - DHD_ERROR(("%s: could not free flow ring hash entry flowid %d\n", - __FUNCTION__, flowid)); -} /* dhd_flowid_free */ - -/** - * Delete all Flow rings associated with the given interface. Is called when eg the dongle - * indicates that a wireless link has gone down. - */ -void -dhd_flow_rings_delete(dhd_pub_t *dhdp, uint8 ifindex) -{ - uint32 id; - flow_ring_table_t *flow_ring_table; - - DHD_ERROR(("%s: ifindex %u\n", __FUNCTION__, ifindex)); - - ASSERT(ifindex < DHD_MAX_IFS); - if (ifindex >= DHD_MAX_IFS) - return; - - if (!dhdp->flow_ring_table) - return; - - flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; - for (id = 0; id < dhdp->num_flow_rings; id++) { - if (flow_ring_table[id].active && - (flow_ring_table[id].flow_info.ifindex == ifindex) && - (flow_ring_table[id].status == FLOW_RING_STATUS_OPEN)) { - dhd_bus_flow_ring_delete_request(dhdp->bus, - (void *) &flow_ring_table[id]); - } - } -} - -void -dhd_flow_rings_flush(dhd_pub_t *dhdp, uint8 ifindex) -{ - uint32 id; - flow_ring_table_t *flow_ring_table; - - DHD_INFO(("%s: ifindex %u\n", __FUNCTION__, ifindex)); - - ASSERT(ifindex < DHD_MAX_IFS); - if (ifindex >= DHD_MAX_IFS) - return; - - if (!dhdp->flow_ring_table) - return; - flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; - - for (id = 0; id <= dhdp->num_flow_rings; id++) { - if (flow_ring_table[id].active && - (flow_ring_table[id].flow_info.ifindex == ifindex) && - (flow_ring_table[id].status == FLOW_RING_STATUS_OPEN)) { - dhd_bus_flow_ring_flush_request(dhdp->bus, - (void *) &flow_ring_table[id]); - } - } -} - - -/** Delete flow ring(s) for given peer address. Related to AP/AWDL/TDLS functionality. */ -void -dhd_flow_rings_delete_for_peer(dhd_pub_t *dhdp, uint8 ifindex, char *addr) -{ - uint32 id; - flow_ring_table_t *flow_ring_table; - - DHD_ERROR(("%s: ifindex %u\n", __FUNCTION__, ifindex)); - - ASSERT(ifindex < DHD_MAX_IFS); - if (ifindex >= DHD_MAX_IFS) - return; - - if (!dhdp->flow_ring_table) - return; - - flow_ring_table = (flow_ring_table_t *)dhdp->flow_ring_table; - for (id = 0; id < dhdp->num_flow_rings; id++) { - if (flow_ring_table[id].active && - (flow_ring_table[id].flow_info.ifindex == ifindex) && - (!memcmp(flow_ring_table[id].flow_info.da, addr, ETHER_ADDR_LEN)) && - (flow_ring_table[id].status == FLOW_RING_STATUS_OPEN)) { - DHD_ERROR(("%s: deleting flowid %d\n", - __FUNCTION__, flow_ring_table[id].flowid)); - dhd_bus_flow_ring_delete_request(dhdp->bus, - (void *) &flow_ring_table[id]); - } - } -} - -/** Handles interface ADD, CHANGE, DEL indications from the dongle */ -void -dhd_update_interface_flow_info(dhd_pub_t *dhdp, uint8 ifindex, - uint8 op, uint8 role) -{ - if_flow_lkup_t *if_flow_lkup; - unsigned long flags; - - ASSERT(ifindex < DHD_MAX_IFS); - if (ifindex >= DHD_MAX_IFS) - return; - - DHD_ERROR(("%s: ifindex %u op %u role is %u \n", - __FUNCTION__, ifindex, op, role)); - if (!dhdp->flowid_allocator) { - DHD_ERROR(("%s: Flow ring not intited yet \n", __FUNCTION__)); - return; - } - - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - - if (op == WLC_E_IF_ADD || op == WLC_E_IF_CHANGE) { - - if_flow_lkup[ifindex].role = role; - - if (role == WLC_E_IF_ROLE_WDS) { - /** - * WDS role does not send WLC_E_LINK event after interface is up. - * So to create flowrings for WDS, make status as TRUE in WLC_E_IF itself. - * same is true while making the status as FALSE. - * TODO: Fix FW to send WLC_E_LINK for WDS role aswell. So that all the - * interfaces are handled uniformly. - */ - if_flow_lkup[ifindex].status = TRUE; - DHD_INFO(("%s: Mcast Flow ring for ifindex %d role is %d \n", - __FUNCTION__, ifindex, role)); - } - } else if ((op == WLC_E_IF_DEL) && (role == WLC_E_IF_ROLE_WDS)) { - if_flow_lkup[ifindex].status = FALSE; - DHD_INFO(("%s: cleanup all Flow rings for ifindex %d role is %d \n", - __FUNCTION__, ifindex, role)); - } - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); -} - -/** Handles a STA 'link' indication from the dongle */ -int -dhd_update_interface_link_status(dhd_pub_t *dhdp, uint8 ifindex, uint8 status) -{ - if_flow_lkup_t *if_flow_lkup; - unsigned long flags; - - ASSERT(ifindex < DHD_MAX_IFS); - if (ifindex >= DHD_MAX_IFS) - return BCME_BADARG; - - DHD_ERROR(("%s: ifindex %d status %d\n", __FUNCTION__, ifindex, status)); - - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - - if (status) { - if_flow_lkup[ifindex].status = TRUE; - } else { - if_flow_lkup[ifindex].status = FALSE; - } - - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - - return BCME_OK; -} - -/** Update flow priority mapping, called on IOVAR */ -int dhd_update_flow_prio_map(dhd_pub_t *dhdp, uint8 map) -{ - uint16 flowid; - flow_ring_node_t *flow_ring_node; - - if (map > DHD_FLOW_PRIO_LLR_MAP) - return BCME_BADOPTION; - - /* Check if we need to change prio map */ - if (map == dhdp->flow_prio_map_type) - return BCME_OK; - - /* If any ring is active we cannot change priority mapping for flow rings */ - for (flowid = 0; flowid < dhdp->num_flow_rings; flowid++) { - flow_ring_node = DHD_FLOW_RING(dhdp, flowid); - if (flow_ring_node->active) - return BCME_EPERM; - } - - /* Inform firmware about new mapping type */ - if (BCME_OK != dhd_flow_prio_map(dhdp, &map, TRUE)) - return BCME_ERROR; - - /* update internal structures */ - dhdp->flow_prio_map_type = map; - if (dhdp->flow_prio_map_type == DHD_FLOW_PRIO_TID_MAP) - bcopy(prio2tid, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); - else - bcopy(prio2ac, dhdp->flow_prio_map, sizeof(uint8) * NUMPRIO); - - return BCME_OK; -} - -/** Inform firmware on updated flow priority mapping, called on IOVAR */ -int dhd_flow_prio_map(dhd_pub_t *dhd, uint8 *map, bool set) -{ - uint8 iovbuf[24] = {0}; - if (!set) { - bcm_mkiovar("bus:fl_prio_map", NULL, 0, (char*)iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0) < 0) { - DHD_ERROR(("%s: failed to get fl_prio_map\n", __FUNCTION__)); - return BCME_ERROR; - } - *map = iovbuf[0]; - return BCME_OK; - } - bcm_mkiovar("bus:fl_prio_map", (char *)map, 4, (char*)iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { - DHD_ERROR(("%s: failed to set fl_prio_map \n", - __FUNCTION__)); - return BCME_ERROR; - } - return BCME_OK; -}
diff --git a/bcmdhd.1.579.77.41.x/dhd_flowring.h b/bcmdhd.1.579.77.41.x/dhd_flowring.h deleted file mode 100644 index d5faf0a..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_flowring.h +++ /dev/null
@@ -1,275 +0,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-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_flowring.h 672438 2016-11-28 12:35:24Z $ - */ - - -/**************** - * 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 - -#ifdef DHD_EFI -#define DHD_FLOWRING_RX_BUFPOST_PKTSZ 1600 -#else -#define DHD_FLOWRING_RX_BUFPOST_PKTSZ 2048 -#endif - -#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_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_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) - -/* see wlfc_proto.h for tx status details */ -#define DHD_FLOWRING_MAXSTATUS_MSGS 5 -#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; - int dataoff; - dmaaddr_t physaddr; - uint32 pa_len; -} 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; - char sa[ETHER_ADDR_LEN]; - char da[ETHER_ADDR_LEN]; -} 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 DEVICE_TX_STUCK_DETECT - /* Time stamp(msec) when last time a Tx packet completion is received on this flow ring */ - uint32 tx_cmpl; - /* - * Holds the tx_cmpl which was read during the previous - * iteration of the stuck detection algo - */ - uint32 tx_cmpl_prev; - /* counter to decide if this particlur flow is stuck or not */ - uint32 stuck_count; -#endif /* DEVICE_TX_STUCK_DETECT */ - -} 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 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_ */
diff --git a/bcmdhd.1.579.77.41.x/dhd_gpio.c b/bcmdhd.1.579.77.41.x/dhd_gpio.c deleted file mode 100644 index 7413fdb..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_gpio.c +++ /dev/null
@@ -1,414 +0,0 @@ -/* - * Customer code to add GPIO control during WLAN start/stop - * - * Copyright (C) 1999-2016, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_gpio.c 591129 2015-10-07 05:22:14Z $ - */ - -#include <osl.h> -#include <dhd_linux.h> -#include <linux/gpio.h> -#include <dhd_dbg.h> - -#ifdef CUSTOMER_HW_PLATFORM -#include <plat/sdhci.h> -#define sdmmc_channel sdmmc_device_mmc0 -#endif /* CUSTOMER_HW_PLATFORM */ - -#if defined(BUS_POWER_RESTORE) && defined(BCMSDIO) -#include <linux/mmc/core.h> -#include <linux/mmc/card.h> -#include <linux/mmc/host.h> -#include <linux/mmc/sdio_func.h> -#endif /* defined(BUS_POWER_RESTORE) && defined(BCMSDIO) */ -#ifdef CONFIG_HISILICON_PLATFORM -#include <linux/of_gpio.h> -#endif - -#ifdef CUSTOMER_HW_AMLOGIC -#include <linux/amlogic/aml_gpio_consumer.h> -extern int wifi_irq_trigger_level(void); -void sdio_cd(bool present); -extern int wifi_irq_num(void); -extern u8 *wifi_get_mac(void); -#endif - -#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 - -#ifdef CONFIG_HISILICON_PLATFORM -#define DHD_DT_COMPAT_ENTRY "android,bcmdhd_wlan" -#define WIFI_WL_REG_ON_PROPNAME "wl_reg_on" -#define WLAN_REG_ON_GPIO 491 -#endif - -extern int dhd_chip_alive; - -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) { - DHD_INFO(("======== 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) { - DHD_ERROR(("%s: WL_REG_ON didn't output high\n", __FUNCTION__)); - return -EIO; - } - } -#if defined(BUS_POWER_RESTORE) -#if defined(BCMSDIO) - if (adapter->sdio_func && adapter->sdio_func->card && adapter->sdio_func->card->host) { - DHD_INFO(("======== mmc_power_restore_host! ========\n")); - mmc_power_restore_host(adapter->sdio_func->card->host); - } -#elif defined(BCMPCIE) - OSL_SLEEP(50); /* delay needed to be able to restore PCIe configuration registers */ - if (adapter->pci_dev) { - DHD_INFO(("======== 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) - DHD_ERROR(("%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) - if (adapter->sdio_func && adapter->sdio_func->card && adapter->sdio_func->card->host) { - DHD_INFO(("======== mmc_power_save_host! ========\n")); - mmc_power_save_host(adapter->sdio_func->card->host); - } -#elif defined(BCMPCIE) - if (adapter->pci_dev) { - DHD_INFO(("======== 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 */ - DHD_INFO(("======== 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) { - DHD_ERROR(("%s: WL_REG_ON didn't output low\n", __FUNCTION__)); - return -EIO; - } - } - } - - 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) - DHD_INFO(("======== Card detection to detect SDIO card! ========\n")); -#ifdef CUSTOMER_HW_PLATFORM - err = sdhci_force_presence_change(&sdmmc_channel, 1); -#endif /* CUSTOMER_HW_PLATFORM */ -#elif defined(BCMPCIE) - DHD_INFO(("======== Card detection to detect PCIE card! ========\n")); -#endif - } else { -#if defined(BCMSDIO) - DHD_INFO(("======== Card detection to remove SDIO card! ========\n")); -#ifdef CUSTOMER_HW_PLATFORM - err = sdhci_force_presence_change(&sdmmc_channel, 0); -#endif /* CUSTOMER_HW_PLATFORM */ -#elif defined(BCMPCIE) - DHD_INFO(("======== Card detection to remove PCIE card! ========\n")); -#endif - } -#endif /* BUS_POWER_RESTORE */ - -#ifdef CUSTOMER_HW_AMLOGIC - sdio_cd(present); -#endif - - return err; -} - -static int dhd_wlan_get_mac_addr(unsigned char *buf) -{ - int err = 0; - - DHD_INFO(("======== %s ========\n", __FUNCTION__)); -#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 */ -#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 */ - -#ifdef CUSTOMER_HW_AMLOGIC - bcopy((char *)wifi_get_mac(), buf, sizeof(struct ether_addr)); - if (buf[0] == 0xff) { - DHD_ERROR(("custom wifi mac is not set\n")); - err = -1; - } -#endif - - 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; -#endif -#ifdef CONFIG_HISILICON_PLATFORM - char *wlan_node = DHD_DT_COMPAT_ENTRY; - struct device_node *root_node = NULL; -#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) { - DHD_ERROR(("%s: gpio_request(%d) for WL_REG_ON failed\n", - __FUNCTION__, gpio_wl_reg_on)); - gpio_wl_reg_on = -1; - } - } - -#ifdef CONFIG_HISILICON_PLATFORM - root_node = of_find_compatible_node(NULL, NULL, wlan_node); - if (root_node) { - gpio_wl_reg_on = of_get_named_gpio(root_node, WIFI_WL_REG_ON_PROPNAME, 0); - } else { - gpio_wl_reg_on = WLAN_REG_ON_GPIO; - } -#endif - -#ifdef CUSTOMER_OOB - if (gpio_wl_host_wake >= 0) { - err = gpio_request(gpio_wl_host_wake, "bcmdhd"); - if (err < 0) { - DHD_ERROR(("%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) { - DHD_ERROR(("%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) { - DHD_ERROR(("%s: gpio_to_irq(%d) for WL_HOST_WAKE failed\n", - __FUNCTION__, gpio_wl_host_wake)); - gpio_free(gpio_wl_host_wake); - return -1; - } - } -#ifdef CUSTOMER_HW_AMLOGIC - host_oob_irq = wifi_irq_num(); -#endif - DHD_INFO(("%s: host_oob_irq: %d\n", __FUNCTION__, host_oob_irq)); - -#ifdef HW_OOB -#ifdef CUSTOMER_HW_AMLOGIC - if (wifi_irq_trigger_level() == GPIO_IRQ_LOW) - host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_SHAREABLE; - else - host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; -#else -#ifdef HW_OOB_LOW_LEVEL - host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_SHAREABLE; -#else - host_oob_irq_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; -#endif -#endif -#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; - DHD_INFO(("%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 */ - DHD_INFO(("%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) { - DHD_INFO(("%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) { - DHD_INFO(("%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; - - DHD_INFO(("======== %s ========\n", __FUNCTION__)); - err = dhd_wlan_init_gpio(); - return err; -} - -void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter) -{ - DHD_INFO(("======== %s ========\n", __FUNCTION__)); - dhd_wlan_deinit_gpio(); -} -
diff --git a/bcmdhd.1.579.77.41.x/dhd_ip.c b/bcmdhd.1.579.77.41.x/dhd_ip.c deleted file mode 100644 index d8be26c..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_ip.c +++ /dev/null
@@ -1,1334 +0,0 @@ -/* - * IP Packet Parser Module. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_ip.c 700317 2017-05-18 15:13:29Z $ - */ -#include <typedefs.h> -#include <osl.h> - -#include <ethernet.h> -#include <vlan.h> -#include <802.3.h> -#include <bcmip.h> -#include <bcmendian.h> - -#include <dhd_dbg.h> - -#include <dhd_ip.h> - -#ifdef DHDTCPACK_SUPPRESS -#include <dhd_bus.h> -#include <dhd_proto.h> -#include <bcmtcp.h> -#endif /* DHDTCPACK_SUPPRESS */ - -/* special values */ -/* 802.3 llc/snap header */ -static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; - -pkt_frag_t pkt_frag_info(osl_t *osh, void *p) -{ - uint8 *frame; - int length; - uint8 *pt; /* Pointer to type field */ - uint16 ethertype; - struct ipv4_hdr *iph; /* IP frame pointer */ - int ipl; /* IP frame length */ - uint16 iph_frag; - - ASSERT(osh && p); - - frame = PKTDATA(osh, p); - length = PKTLEN(osh, p); - - /* Process Ethernet II or SNAP-encapsulated 802.3 frames */ - if (length < ETHER_HDR_LEN) { - DHD_INFO(("%s: short eth frame (%d)\n", __FUNCTION__, length)); - return DHD_PKT_FRAG_NONE; - } else if (ntoh16(*(uint16 *)(frame + ETHER_TYPE_OFFSET)) >= ETHER_TYPE_MIN) { - /* Frame is Ethernet II */ - pt = frame + ETHER_TYPE_OFFSET; - } else if (length >= ETHER_HDR_LEN + SNAP_HDR_LEN + ETHER_TYPE_LEN && - !bcmp(llc_snap_hdr, frame + ETHER_HDR_LEN, SNAP_HDR_LEN)) { - pt = frame + ETHER_HDR_LEN + SNAP_HDR_LEN; - } else { - DHD_INFO(("%s: non-SNAP 802.3 frame\n", __FUNCTION__)); - return DHD_PKT_FRAG_NONE; - } - - ethertype = ntoh16(*(uint16 *)pt); - - /* Skip VLAN tag, if any */ - if (ethertype == ETHER_TYPE_8021Q) { - pt += VLAN_TAG_LEN; - - if (pt + ETHER_TYPE_LEN > frame + length) { - DHD_INFO(("%s: short VLAN frame (%d)\n", __FUNCTION__, length)); - return DHD_PKT_FRAG_NONE; - } - - ethertype = ntoh16(*(uint16 *)pt); - } - - if (ethertype != ETHER_TYPE_IP) { - DHD_INFO(("%s: non-IP frame (ethertype 0x%x, length %d)\n", - __FUNCTION__, ethertype, length)); - return DHD_PKT_FRAG_NONE; - } - - iph = (struct ipv4_hdr *)(pt + ETHER_TYPE_LEN); - ipl = (uint)(length - (pt + ETHER_TYPE_LEN - frame)); - - /* We support IPv4 only */ - if ((ipl < IPV4_OPTIONS_OFFSET) || (IP_VER(iph) != IP_VER_4)) { - DHD_INFO(("%s: short frame (%d) or non-IPv4\n", __FUNCTION__, ipl)); - return DHD_PKT_FRAG_NONE; - } - - iph_frag = ntoh16(iph->frag); - - if (iph_frag & IPV4_FRAG_DONT) { - return DHD_PKT_FRAG_NONE; - } else if ((iph_frag & IPV4_FRAG_MORE) == 0) { - return DHD_PKT_FRAG_LAST; - } else { - return (iph_frag & IPV4_FRAG_OFFSET_MASK)? DHD_PKT_FRAG_CONT : DHD_PKT_FRAG_FIRST; - } -} - -#ifdef DHDTCPACK_SUPPRESS - -typedef struct { - void *pkt_in_q; /* TCP ACK packet that is already in txq or DelayQ */ - void *pkt_ether_hdr; /* Ethernet header pointer of pkt_in_q */ - int ifidx; - uint8 supp_cnt; - dhd_pub_t *dhdp; - struct timer_list timer; -} tcpack_info_t; - -typedef struct _tdata_psh_info_t { - uint32 end_seq; /* end seq# of a received TCP PSH DATA pkt */ - struct _tdata_psh_info_t *next; /* next pointer of the link chain */ -} tdata_psh_info_t; - -typedef struct { - struct { - uint8 src[IPV4_ADDR_LEN]; /* SRC ip addrs of this TCP stream */ - uint8 dst[IPV4_ADDR_LEN]; /* DST ip addrs of this TCP stream */ - } ip_addr; - struct { - uint8 src[TCP_PORT_LEN]; /* SRC tcp ports of this TCP stream */ - uint8 dst[TCP_PORT_LEN]; /* DST tcp ports of this TCP stream */ - } tcp_port; - tdata_psh_info_t *tdata_psh_info_head; /* Head of received TCP PSH DATA chain */ - tdata_psh_info_t *tdata_psh_info_tail; /* Tail of received TCP PSH DATA chain */ - uint32 last_used_time; /* The last time this tcpdata_info was used(in ms) */ -} tcpdata_info_t; - -/* TCPACK SUPPRESS module */ -typedef struct { - int tcpack_info_cnt; - tcpack_info_t tcpack_info_tbl[TCPACK_INFO_MAXNUM]; /* Info of TCP ACK to send */ - int tcpdata_info_cnt; - tcpdata_info_t tcpdata_info_tbl[TCPDATA_INFO_MAXNUM]; /* Info of received TCP DATA */ - tdata_psh_info_t *tdata_psh_info_pool; /* Pointer to tdata_psh_info elements pool */ - tdata_psh_info_t *tdata_psh_info_free; /* free tdata_psh_info elements chain in pool */ -#ifdef DHDTCPACK_SUP_DBG - int psh_info_enq_num; /* Number of free TCP PSH DATA info elements in pool */ -#endif /* DHDTCPACK_SUP_DBG */ -} tcpack_sup_module_t; - -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) -counter_tbl_t tack_tbl = {"tcpACK", 0, 1000, 10, {0, }, 1}; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - -static void -_tdata_psh_info_pool_enq(tcpack_sup_module_t *tcpack_sup_mod, - tdata_psh_info_t *tdata_psh_info) -{ - if ((tcpack_sup_mod == NULL) || (tdata_psh_info == NULL)) { - DHD_ERROR(("%s %d: ERROR %p %p\n", __FUNCTION__, __LINE__, - tcpack_sup_mod, tdata_psh_info)); - return; - } - - ASSERT(tdata_psh_info->next == NULL); - tdata_psh_info->next = tcpack_sup_mod->tdata_psh_info_free; - tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info; -#ifdef DHDTCPACK_SUP_DBG - tcpack_sup_mod->psh_info_enq_num++; -#endif -} - -static tdata_psh_info_t* -_tdata_psh_info_pool_deq(tcpack_sup_module_t *tcpack_sup_mod) -{ - tdata_psh_info_t *tdata_psh_info = NULL; - - if (tcpack_sup_mod == NULL) { - DHD_ERROR(("%s %d: ERROR %p\n", __FUNCTION__, __LINE__, - tcpack_sup_mod)); - return NULL; - } - - tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free; - if (tdata_psh_info == NULL) - DHD_ERROR(("%s %d: Out of tdata_disc_grp\n", __FUNCTION__, __LINE__)); - else { - tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next; - tdata_psh_info->next = NULL; -#ifdef DHDTCPACK_SUP_DBG - tcpack_sup_mod->psh_info_enq_num--; -#endif /* DHDTCPACK_SUP_DBG */ - } - - return tdata_psh_info; -} - -static int _tdata_psh_info_pool_init(dhd_pub_t *dhdp, - tcpack_sup_module_t *tcpack_sup_mod) -{ - tdata_psh_info_t *tdata_psh_info_pool = NULL; - uint i; - - DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__)); - - if (tcpack_sup_mod == NULL) - return BCME_ERROR; - - ASSERT(tcpack_sup_mod->tdata_psh_info_pool == NULL); - ASSERT(tcpack_sup_mod->tdata_psh_info_free == NULL); - - tdata_psh_info_pool = - MALLOC(dhdp->osh, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); - - if (tdata_psh_info_pool == NULL) - return BCME_NOMEM; - bzero(tdata_psh_info_pool, sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); -#ifdef DHDTCPACK_SUP_DBG - tcpack_sup_mod->psh_info_enq_num = 0; -#endif /* DHDTCPACK_SUP_DBG */ - - /* Enqueue newly allocated tcpdata psh info elements to the pool */ - for (i = 0; i < TCPDATA_PSH_INFO_MAXNUM; i++) - _tdata_psh_info_pool_enq(tcpack_sup_mod, &tdata_psh_info_pool[i]); - - ASSERT(tcpack_sup_mod->tdata_psh_info_free != NULL); - tcpack_sup_mod->tdata_psh_info_pool = tdata_psh_info_pool; - - return BCME_OK; -} - -static void _tdata_psh_info_pool_deinit(dhd_pub_t *dhdp, - tcpack_sup_module_t *tcpack_sup_mod) -{ - uint i; - tdata_psh_info_t *tdata_psh_info; - - DHD_TRACE(("%s %d: Enter\n", __FUNCTION__, __LINE__)); - - if (tcpack_sup_mod == NULL) { - DHD_ERROR(("%s %d: ERROR tcpack_sup_mod NULL!\n", - __FUNCTION__, __LINE__)); - return; - } - - for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) { - tcpdata_info_t *tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i]; - /* Return tdata_psh_info elements allocated to each tcpdata_info to the pool */ - while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) { - tcpdata_info->tdata_psh_info_head = tdata_psh_info->next; - tdata_psh_info->next = NULL; - _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info); - } - tcpdata_info->tdata_psh_info_tail = NULL; - } -#ifdef DHDTCPACK_SUP_DBG - DHD_ERROR(("%s %d: PSH INFO ENQ %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); -#endif /* DHDTCPACK_SUP_DBG */ - - i = 0; - /* Be sure we recollected all tdata_psh_info elements */ - while ((tdata_psh_info = tcpack_sup_mod->tdata_psh_info_free)) { - tcpack_sup_mod->tdata_psh_info_free = tdata_psh_info->next; - tdata_psh_info->next = NULL; - i++; - } - ASSERT(i == TCPDATA_PSH_INFO_MAXNUM); - MFREE(dhdp->osh, tcpack_sup_mod->tdata_psh_info_pool, - sizeof(tdata_psh_info_t) * TCPDATA_PSH_INFO_MAXNUM); - tcpack_sup_mod->tdata_psh_info_pool = NULL; - - return; -} - -static void dhd_tcpack_send( -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) - struct timer_list *t -#else - ulong data -#endif -) -{ - tcpack_sup_module_t *tcpack_sup_mod; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) - tcpack_info_t *cur_tbl = from_timer(cur_tbl, t, timer); -#else - tcpack_info_t *cur_tbl = (tcpack_info_t *)data; -#endif - dhd_pub_t *dhdp; - int ifidx; - void* pkt; - unsigned long flags; - - if (!cur_tbl) { - return; - } - - dhdp = cur_tbl->dhdp; - if (!dhdp) { - return; - } - - flags = dhd_os_tcpacklock(dhdp); - - tcpack_sup_mod = dhdp->tcpack_sup_module; - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", - __FUNCTION__, __LINE__)); - dhd_os_tcpackunlock(dhdp, flags); - return; - } - pkt = cur_tbl->pkt_in_q; - ifidx = cur_tbl->ifidx; - if (!pkt) { - dhd_os_tcpackunlock(dhdp, flags); - return; - } - cur_tbl->pkt_in_q = NULL; - cur_tbl->pkt_ether_hdr = NULL; - cur_tbl->ifidx = 0; - cur_tbl->supp_cnt = 0; - if (--tcpack_sup_mod->tcpack_info_cnt < 0) { - DHD_ERROR(("%s %d: ERROR!!! tcp_ack_info_cnt %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->tcpack_info_cnt)); - } - - dhd_os_tcpackunlock(dhdp, flags); - - dhd_sendpkt(dhdp, ifidx, pkt); -} - -int dhd_tcpack_suppress_set(dhd_pub_t *dhdp, uint8 mode) -{ - int ret = BCME_OK; - unsigned long flags; - tcpack_sup_module_t *tcpack_sup_module; - uint8 invalid_mode = FALSE; - int prev_mode; - int i = 0; - - flags = dhd_os_tcpacklock(dhdp); - tcpack_sup_module = dhdp->tcpack_sup_module; - prev_mode = dhdp->tcpack_sup_mode; - - /* Check a new mode */ - if (prev_mode == mode) { - DHD_ERROR(("%s %d: already set to %d\n", __FUNCTION__, __LINE__, mode)); - goto exit; - } - - invalid_mode |= (mode >= TCPACK_SUP_LAST_MODE); -#ifdef BCMSDIO - invalid_mode |= (mode == TCPACK_SUP_HOLD); -#endif /* BCMSDIO */ -#ifdef BCMPCIE - invalid_mode |= ((mode == TCPACK_SUP_REPLACE) || (mode == TCPACK_SUP_DELAYTX)); -#endif /* BCMPCIE */ - - if (invalid_mode) { - DHD_ERROR(("%s %d: Invalid TCP ACK Suppress mode %d\n", - __FUNCTION__, __LINE__, mode)); - ret = BCME_BADARG; - goto exit; - } - - DHD_TRACE(("%s: TCP ACK Suppress mode %d -> mode %d\n", - __FUNCTION__, dhdp->tcpack_sup_mode, mode)); - - /* Pre-process routines to change a new mode as per previous mode */ - switch (prev_mode) { - case TCPACK_SUP_OFF: - if (tcpack_sup_module == NULL) { - tcpack_sup_module = MALLOC(dhdp->osh, sizeof(tcpack_sup_module_t)); - if (tcpack_sup_module == NULL) { - DHD_ERROR(("%s[%d]: Failed to allocate the new memory for " - "tcpack_sup_module\n", __FUNCTION__, __LINE__)); - dhdp->tcpack_sup_mode = TCPACK_SUP_OFF; - ret = BCME_NOMEM; - goto exit; - } - dhdp->tcpack_sup_module = tcpack_sup_module; - } - bzero(tcpack_sup_module, sizeof(tcpack_sup_module_t)); - break; - case TCPACK_SUP_DELAYTX: - if (tcpack_sup_module) { - /* We won't need tdata_psh_info pool and - * tcpddata_info_tbl anymore - */ - _tdata_psh_info_pool_deinit(dhdp, tcpack_sup_module); - tcpack_sup_module->tcpdata_info_cnt = 0; - bzero(tcpack_sup_module->tcpdata_info_tbl, - sizeof(tcpdata_info_t) * TCPDATA_INFO_MAXNUM); - } - - /* For half duplex bus interface, tx precedes rx by default */ - if (dhdp->bus) { - dhd_bus_set_dotxinrx(dhdp->bus, TRUE); - } - - if (tcpack_sup_module == NULL) { - DHD_ERROR(("%s[%d]: tcpack_sup_module should not be NULL\n", - __FUNCTION__, __LINE__)); - dhdp->tcpack_sup_mode = TCPACK_SUP_OFF; - goto exit; - } - break; - } - - /* Update a new mode */ - dhdp->tcpack_sup_mode = mode; - - /* Process for a new mode */ - switch (mode) { - case TCPACK_SUP_OFF: - ASSERT(tcpack_sup_module != NULL); - /* Clean up timer/data structure for - * any remaining/pending packet or timer. - */ - if (tcpack_sup_module) { - /* Check if previous mode is TCAPACK_SUP_HOLD */ - if (prev_mode == TCPACK_SUP_HOLD) { - for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { - tcpack_info_t *tcpack_info_tbl = - &tcpack_sup_module->tcpack_info_tbl[i]; - del_timer(&tcpack_info_tbl->timer); - if (tcpack_info_tbl->pkt_in_q) { - PKTFREE(dhdp->osh, - tcpack_info_tbl->pkt_in_q, TRUE); - tcpack_info_tbl->pkt_in_q = NULL; - } - } - } - MFREE(dhdp->osh, tcpack_sup_module, sizeof(tcpack_sup_module_t)); - dhdp->tcpack_sup_module = NULL; - } else { - DHD_ERROR(("%s[%d]: tcpack_sup_module should not be NULL\n", - __FUNCTION__, __LINE__)); - } - break; - case TCPACK_SUP_REPLACE: - /* There is nothing to configure for this mode */ - break; - case TCPACK_SUP_DELAYTX: - ret = _tdata_psh_info_pool_init(dhdp, tcpack_sup_module); - if (ret != BCME_OK) { - DHD_ERROR(("%s %d: pool init fail with %d\n", - __FUNCTION__, __LINE__, ret)); - break; - } - if (dhdp->bus) { - dhd_bus_set_dotxinrx(dhdp->bus, FALSE); - } - break; - case TCPACK_SUP_HOLD: - dhdp->tcpack_sup_ratio = CUSTOM_TCPACK_SUPP_RATIO; - dhdp->tcpack_sup_delay = CUSTOM_TCPACK_DELAY_TIME; - for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { - tcpack_info_t *tcpack_info_tbl = - &tcpack_sup_module->tcpack_info_tbl[i]; - tcpack_info_tbl->dhdp = dhdp; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) - timer_setup(&tcpack_info_tbl->timer, dhd_tcpack_send, 0); -#else - init_timer(&tcpack_info_tbl->timer); - tcpack_info_tbl->timer.data = (ulong)tcpack_info_tbl; - tcpack_info_tbl->timer.function = dhd_tcpack_send; -#endif - } - break; - } - -exit: - dhd_os_tcpackunlock(dhdp, flags); - return ret; -} - -void -dhd_tcpack_info_tbl_clean(dhd_pub_t *dhdp) -{ - tcpack_sup_module_t *tcpack_sup_mod = dhdp->tcpack_sup_module; - int i; - unsigned long flags; - - if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) - goto exit; - - flags = dhd_os_tcpacklock(dhdp); - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", - __FUNCTION__, __LINE__)); - dhd_os_tcpackunlock(dhdp, flags); - goto exit; - } - - if (dhdp->tcpack_sup_mode == TCPACK_SUP_HOLD) { - for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { - if (tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q) { - PKTFREE(dhdp->osh, tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q, - TRUE); - tcpack_sup_mod->tcpack_info_tbl[i].pkt_in_q = NULL; - tcpack_sup_mod->tcpack_info_tbl[i].pkt_ether_hdr = NULL; - tcpack_sup_mod->tcpack_info_tbl[i].ifidx = 0; - tcpack_sup_mod->tcpack_info_tbl[i].supp_cnt = 0; - } - } - } else { - tcpack_sup_mod->tcpack_info_cnt = 0; - bzero(tcpack_sup_mod->tcpack_info_tbl, sizeof(tcpack_info_t) * TCPACK_INFO_MAXNUM); - } - - dhd_os_tcpackunlock(dhdp, flags); - - if (dhdp->tcpack_sup_mode == TCPACK_SUP_HOLD) { - for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { - del_timer_sync(&tcpack_sup_mod->tcpack_info_tbl[i].timer); - } - } - -exit: - return; -} - -inline int dhd_tcpack_check_xmit(dhd_pub_t *dhdp, void *pkt) -{ - uint8 i; - tcpack_sup_module_t *tcpack_sup_mod; - tcpack_info_t *tcpack_info_tbl; - int tbl_cnt; - int ret = BCME_OK; - void *pdata; - uint32 pktlen; - unsigned long flags; - - if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) - goto exit; - - pdata = PKTDATA(dhdp->osh, pkt); - pktlen = PKTLEN(dhdp->osh, pkt) - dhd_prot_hdrlen(dhdp, pdata); - - if (pktlen < TCPACKSZMIN || pktlen > TCPACKSZMAX) { - DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", - __FUNCTION__, __LINE__, pktlen)); - goto exit; - } - - flags = dhd_os_tcpacklock(dhdp); - tcpack_sup_mod = dhdp->tcpack_sup_module; - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); - ret = BCME_ERROR; - dhd_os_tcpackunlock(dhdp, flags); - goto exit; - } - tbl_cnt = tcpack_sup_mod->tcpack_info_cnt; - tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; - - ASSERT(tbl_cnt <= TCPACK_INFO_MAXNUM); - - for (i = 0; i < tbl_cnt; i++) { - if (tcpack_info_tbl[i].pkt_in_q == pkt) { - DHD_TRACE(("%s %d: pkt %p sent out. idx %d, tbl_cnt %d\n", - __FUNCTION__, __LINE__, pkt, i, tbl_cnt)); - /* This pkt is being transmitted so remove the tcp_ack_info of it. */ - if (i < tbl_cnt - 1) { - bcopy(&tcpack_info_tbl[tbl_cnt - 1], - &tcpack_info_tbl[i], sizeof(tcpack_info_t)); - } - bzero(&tcpack_info_tbl[tbl_cnt - 1], sizeof(tcpack_info_t)); - if (--tcpack_sup_mod->tcpack_info_cnt < 0) { - DHD_ERROR(("%s %d: ERROR!!! tcp_ack_info_cnt %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->tcpack_info_cnt)); - ret = BCME_ERROR; - } - break; - } - } - dhd_os_tcpackunlock(dhdp, flags); - -exit: - return ret; -} - -static INLINE bool dhd_tcpdata_psh_acked(dhd_pub_t *dhdp, uint8 *ip_hdr, - uint8 *tcp_hdr, uint32 tcp_ack_num) -{ - tcpack_sup_module_t *tcpack_sup_mod; - int i; - tcpdata_info_t *tcpdata_info = NULL; - tdata_psh_info_t *tdata_psh_info = NULL; - bool ret = FALSE; - - if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX) - goto exit; - - tcpack_sup_mod = dhdp->tcpack_sup_module; - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); - goto exit; - } - - DHD_TRACE(("%s %d: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d, ack %u\n", __FUNCTION__, __LINE__, - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]), - tcp_ack_num)); - - for (i = 0; i < tcpack_sup_mod->tcpdata_info_cnt; i++) { - tcpdata_info_t *tcpdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i]; - DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d\n", __FUNCTION__, __LINE__, i, - IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->ip_addr.src)), - IPV4_ADDR_TO_STR(ntoh32_ua(tcpdata_info_tmp->ip_addr.dst)), - ntoh16_ua(tcpdata_info_tmp->tcp_port.src), - ntoh16_ua(tcpdata_info_tmp->tcp_port.dst))); - - /* If either IP address or TCP port number does not match, skip. */ - if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET], - tcpdata_info_tmp->ip_addr.dst, IPV4_ADDR_LEN) == 0 && - memcmp(&ip_hdr[IPV4_DEST_IP_OFFSET], - tcpdata_info_tmp->ip_addr.src, IPV4_ADDR_LEN) == 0 && - memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET], - tcpdata_info_tmp->tcp_port.dst, TCP_PORT_LEN) == 0 && - memcmp(&tcp_hdr[TCP_DEST_PORT_OFFSET], - tcpdata_info_tmp->tcp_port.src, TCP_PORT_LEN) == 0) { - tcpdata_info = tcpdata_info_tmp; - break; - } - } - - if (tcpdata_info == NULL) { - DHD_TRACE(("%s %d: no tcpdata_info!\n", __FUNCTION__, __LINE__)); - goto exit; - } - - if (tcpdata_info->tdata_psh_info_head == NULL) { - DHD_TRACE(("%s %d: No PSH DATA to be acked!\n", __FUNCTION__, __LINE__)); - } - - while ((tdata_psh_info = tcpdata_info->tdata_psh_info_head)) { - if (IS_TCPSEQ_GE(tcp_ack_num, tdata_psh_info->end_seq)) { - DHD_TRACE(("%s %d: PSH ACKED! %u >= %u\n", - __FUNCTION__, __LINE__, tcp_ack_num, tdata_psh_info->end_seq)); - tcpdata_info->tdata_psh_info_head = tdata_psh_info->next; - tdata_psh_info->next = NULL; - _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info); - ret = TRUE; - } else - break; - } - if (tdata_psh_info == NULL) - tcpdata_info->tdata_psh_info_tail = NULL; - -#ifdef DHDTCPACK_SUP_DBG - DHD_TRACE(("%s %d: PSH INFO ENQ %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); -#endif /* DHDTCPACK_SUP_DBG */ - -exit: - return ret; -} - -bool -dhd_tcpack_suppress(dhd_pub_t *dhdp, void *pkt) -{ - uint8 *new_ether_hdr; /* Ethernet header of the new packet */ - uint16 new_ether_type; /* Ethernet type of the new packet */ - uint8 *new_ip_hdr; /* IP header of the new packet */ - uint8 *new_tcp_hdr; /* TCP header of the new packet */ - uint32 new_ip_hdr_len; /* IP header length of the new packet */ - uint32 cur_framelen; - uint32 new_tcp_ack_num; /* TCP acknowledge number of the new packet */ - uint16 new_ip_total_len; /* Total length of IP packet for the new packet */ - uint32 new_tcp_hdr_len; /* TCP header length of the new packet */ - tcpack_sup_module_t *tcpack_sup_mod; - tcpack_info_t *tcpack_info_tbl; - int i; - bool ret = FALSE; - bool set_dotxinrx = TRUE; - unsigned long flags; - - - if (dhdp->tcpack_sup_mode == TCPACK_SUP_OFF) - goto exit; - - new_ether_hdr = PKTDATA(dhdp->osh, pkt); - cur_framelen = PKTLEN(dhdp->osh, pkt); - - if (cur_framelen < TCPACKSZMIN || cur_framelen > TCPACKSZMAX) { - DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", - __FUNCTION__, __LINE__, cur_framelen)); - goto exit; - } - - new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13]; - - if (new_ether_type != ETHER_TYPE_IP) { - DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", - __FUNCTION__, __LINE__, new_ether_type)); - goto exit; - } - - DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, new_ether_type)); - - new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN; - cur_framelen -= ETHER_HDR_LEN; - - ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); - - new_ip_hdr_len = IPV4_HLEN(new_ip_hdr); - if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) { - DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", - __FUNCTION__, __LINE__, IP_VER(new_ip_hdr), IPV4_PROT(new_ip_hdr))); - goto exit; - } - - new_tcp_hdr = new_ip_hdr + new_ip_hdr_len; - cur_framelen -= new_ip_hdr_len; - - ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); - - DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); - - /* is it an ack ? Allow only ACK flag, not to suppress others. */ - if (new_tcp_hdr[TCP_FLAGS_OFFSET] != TCP_FLAG_ACK) { - DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n", - __FUNCTION__, __LINE__, new_tcp_hdr[TCP_FLAGS_OFFSET])); - goto exit; - } - - new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]); - new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]); - - /* This packet has TCP data, so just send */ - if (new_ip_total_len > new_ip_hdr_len + new_tcp_hdr_len) { - DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__, __LINE__)); - goto exit; - } - - ASSERT(new_ip_total_len == new_ip_hdr_len + new_tcp_hdr_len); - - new_tcp_ack_num = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]); - - DHD_TRACE(("%s %d: TCP ACK with zero DATA length" - " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", - __FUNCTION__, __LINE__, - IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]))); - - /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */ - flags = dhd_os_tcpacklock(dhdp); -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - counter_printlog(&tack_tbl); - tack_tbl.cnt[0]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - - tcpack_sup_mod = dhdp->tcpack_sup_module; - tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); - ret = BCME_ERROR; - dhd_os_tcpackunlock(dhdp, flags); - goto exit; - } - - if (dhd_tcpdata_psh_acked(dhdp, new_ip_hdr, new_tcp_hdr, new_tcp_ack_num)) { - /* This TCPACK is ACK to TCPDATA PSH pkt, so keep set_dotxinrx TRUE */ -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[5]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - } else - set_dotxinrx = FALSE; - - for (i = 0; i < tcpack_sup_mod->tcpack_info_cnt; i++) { - void *oldpkt; /* TCPACK packet that is already in txq or DelayQ */ - uint8 *old_ether_hdr, *old_ip_hdr, *old_tcp_hdr; - uint32 old_ip_hdr_len, old_tcp_hdr_len; - uint32 old_tcpack_num; /* TCP ACK number of old TCPACK packet in Q */ - - if ((oldpkt = tcpack_info_tbl[i].pkt_in_q) == NULL) { - DHD_ERROR(("%s %d: Unexpected error!! cur idx %d, ttl cnt %d\n", - __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt)); - break; - } - - if (PKTDATA(dhdp->osh, oldpkt) == NULL) { - DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d, ttl cnt %d\n", - __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpack_info_cnt)); - break; - } - - old_ether_hdr = tcpack_info_tbl[i].pkt_ether_hdr; - old_ip_hdr = old_ether_hdr + ETHER_HDR_LEN; - old_ip_hdr_len = IPV4_HLEN(old_ip_hdr); - old_tcp_hdr = old_ip_hdr + old_ip_hdr_len; - old_tcp_hdr_len = 4 * TCP_HDRLEN(old_tcp_hdr[TCP_HLEN_OFFSET]); - - DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d\n", __FUNCTION__, __LINE__, oldpkt, i, - IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&old_tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&old_tcp_hdr[TCP_DEST_PORT_OFFSET]))); - - /* If either of IP address or TCP port number does not match, skip. - * Note that src/dst addr fields in ip header are contiguous being 8 bytes in total. - * Also, src/dst port fields in TCP header are contiguous being 4 bytes in total. - */ - if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET], - &old_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN * 2) || - memcmp(&new_tcp_hdr[TCP_SRC_PORT_OFFSET], - &old_tcp_hdr[TCP_SRC_PORT_OFFSET], TCP_PORT_LEN * 2)) - continue; - - old_tcpack_num = ntoh32_ua(&old_tcp_hdr[TCP_ACK_NUM_OFFSET]); - - if (IS_TCPSEQ_GT(new_tcp_ack_num, old_tcpack_num)) { - /* New packet has higher TCP ACK number, so it replaces the old packet */ - if (new_ip_hdr_len == old_ip_hdr_len && - new_tcp_hdr_len == old_tcp_hdr_len) { - ASSERT(memcmp(new_ether_hdr, old_ether_hdr, ETHER_HDR_LEN) == 0); - bcopy(new_ip_hdr, old_ip_hdr, new_ip_total_len); - PKTFREE(dhdp->osh, pkt, FALSE); - DHD_TRACE(("%s %d: TCP ACK replace %u -> %u\n", - __FUNCTION__, __LINE__, old_tcpack_num, new_tcp_ack_num)); -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[2]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - ret = TRUE; - } else { -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[6]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - DHD_TRACE(("%s %d: lenth mismatch %d != %d || %d != %d" - " ACK %u -> %u\n", __FUNCTION__, __LINE__, - new_ip_hdr_len, old_ip_hdr_len, - new_tcp_hdr_len, old_tcp_hdr_len, - old_tcpack_num, new_tcp_ack_num)); - } - } else if (new_tcp_ack_num == old_tcpack_num) { - set_dotxinrx = TRUE; - /* TCPACK retransmission */ -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[3]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - } else { - DHD_TRACE(("%s %d: ACK number reverse old %u(0x%p) new %u(0x%p)\n", - __FUNCTION__, __LINE__, old_tcpack_num, oldpkt, - new_tcp_ack_num, pkt)); - } - dhd_os_tcpackunlock(dhdp, flags); - goto exit; - } - - if (i == tcpack_sup_mod->tcpack_info_cnt && i < TCPACK_INFO_MAXNUM) { - /* No TCPACK packet with the same IP addr and TCP port is found - * in tcp_ack_info_tbl. So add this packet to the table. - */ - DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n", - __FUNCTION__, __LINE__, pkt, new_ether_hdr, - tcpack_sup_mod->tcpack_info_cnt)); - - tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_in_q = pkt; - tcpack_info_tbl[tcpack_sup_mod->tcpack_info_cnt].pkt_ether_hdr = new_ether_hdr; - tcpack_sup_mod->tcpack_info_cnt++; -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[1]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - } else { - ASSERT(i == tcpack_sup_mod->tcpack_info_cnt); - DHD_TRACE(("%s %d: No empty tcp ack info tbl\n", - __FUNCTION__, __LINE__)); - } - dhd_os_tcpackunlock(dhdp, flags); - -exit: - /* Unless TCPACK_SUP_DELAYTX, dotxinrx is alwasy TRUE, so no need to set here */ - if (dhdp->tcpack_sup_mode == TCPACK_SUP_DELAYTX && set_dotxinrx) - dhd_bus_set_dotxinrx(dhdp->bus, TRUE); - - return ret; -} - -bool -dhd_tcpdata_info_get(dhd_pub_t *dhdp, void *pkt) -{ - uint8 *ether_hdr; /* Ethernet header of the new packet */ - uint16 ether_type; /* Ethernet type of the new packet */ - uint8 *ip_hdr; /* IP header of the new packet */ - uint8 *tcp_hdr; /* TCP header of the new packet */ - uint32 ip_hdr_len; /* IP header length of the new packet */ - uint32 cur_framelen; - uint16 ip_total_len; /* Total length of IP packet for the new packet */ - uint32 tcp_hdr_len; /* TCP header length of the new packet */ - uint32 tcp_seq_num; /* TCP sequence number of the new packet */ - uint16 tcp_data_len; /* TCP DATA length that excludes IP and TCP headers */ - uint32 end_tcp_seq_num; /* TCP seq number of the last byte in the new packet */ - tcpack_sup_module_t *tcpack_sup_mod; - tcpdata_info_t *tcpdata_info = NULL; - tdata_psh_info_t *tdata_psh_info; - - int i; - bool ret = FALSE; - unsigned long flags; - - if (dhdp->tcpack_sup_mode != TCPACK_SUP_DELAYTX) - goto exit; - - ether_hdr = PKTDATA(dhdp->osh, pkt); - cur_framelen = PKTLEN(dhdp->osh, pkt); - - ether_type = ether_hdr[12] << 8 | ether_hdr[13]; - - if (ether_type != ETHER_TYPE_IP) { - DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", - __FUNCTION__, __LINE__, ether_type)); - goto exit; - } - - DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, ether_type)); - - ip_hdr = ether_hdr + ETHER_HDR_LEN; - cur_framelen -= ETHER_HDR_LEN; - - ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); - - ip_hdr_len = IPV4_HLEN(ip_hdr); - if (IP_VER(ip_hdr) != IP_VER_4 || IPV4_PROT(ip_hdr) != IP_PROT_TCP) { - DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", - __FUNCTION__, __LINE__, IP_VER(ip_hdr), IPV4_PROT(ip_hdr))); - goto exit; - } - - tcp_hdr = ip_hdr + ip_hdr_len; - cur_framelen -= ip_hdr_len; - - ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); - - DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); - - ip_total_len = ntoh16_ua(&ip_hdr[IPV4_PKTLEN_OFFSET]); - tcp_hdr_len = 4 * TCP_HDRLEN(tcp_hdr[TCP_HLEN_OFFSET]); - - /* This packet is mere TCP ACK, so do nothing */ - if (ip_total_len == ip_hdr_len + tcp_hdr_len) { - DHD_TRACE(("%s %d: Do nothing for no data TCP ACK\n", __FUNCTION__, __LINE__)); - goto exit; - } - - ASSERT(ip_total_len > ip_hdr_len + tcp_hdr_len); - - if ((tcp_hdr[TCP_FLAGS_OFFSET] & TCP_FLAG_PSH) == 0) { - DHD_TRACE(("%s %d: Not interested TCP DATA packet\n", __FUNCTION__, __LINE__)); - goto exit; - } - - DHD_TRACE(("%s %d: TCP DATA with nonzero DATA length" - " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d, flag 0x%x\n", - __FUNCTION__, __LINE__, - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]), - tcp_hdr[TCP_FLAGS_OFFSET])); - - flags = dhd_os_tcpacklock(dhdp); - tcpack_sup_mod = dhdp->tcpack_sup_module; - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); - ret = BCME_ERROR; - dhd_os_tcpackunlock(dhdp, flags); - goto exit; - } - - /* Look for tcpdata_info that has the same ip src/dst addrs and tcp src/dst ports */ - i = 0; - while (i < tcpack_sup_mod->tcpdata_info_cnt) { - tcpdata_info_t *tdata_info_tmp = &tcpack_sup_mod->tcpdata_info_tbl[i]; - uint32 now_in_ms = OSL_SYSUPTIME(); - DHD_TRACE(("%s %d: data info[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d\n", __FUNCTION__, __LINE__, i, - IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->ip_addr.src)), - IPV4_ADDR_TO_STR(ntoh32_ua(tdata_info_tmp->ip_addr.dst)), - ntoh16_ua(tdata_info_tmp->tcp_port.src), - ntoh16_ua(tdata_info_tmp->tcp_port.dst))); - - /* If both IP address and TCP port number match, we found it so break. - * Note that src/dst addr fields in ip header are contiguous being 8 bytes in total. - * Also, src/dst port fields in TCP header are contiguous being 4 bytes in total. - */ - if (memcmp(&ip_hdr[IPV4_SRC_IP_OFFSET], - (void *)&tdata_info_tmp->ip_addr, IPV4_ADDR_LEN * 2) == 0 && - memcmp(&tcp_hdr[TCP_SRC_PORT_OFFSET], - (void *)&tdata_info_tmp->tcp_port, TCP_PORT_LEN * 2) == 0) { - tcpdata_info = tdata_info_tmp; - tcpdata_info->last_used_time = now_in_ms; - break; - } - - if (now_in_ms - tdata_info_tmp->last_used_time > TCPDATA_INFO_TIMEOUT) { - tdata_psh_info_t *tdata_psh_info_tmp; - tcpdata_info_t *last_tdata_info; - - while ((tdata_psh_info_tmp = tdata_info_tmp->tdata_psh_info_head)) { - tdata_info_tmp->tdata_psh_info_head = tdata_psh_info_tmp->next; - tdata_psh_info_tmp->next = NULL; - DHD_TRACE(("%s %d: Clean tdata_psh_info(end_seq %u)!\n", - __FUNCTION__, __LINE__, tdata_psh_info_tmp->end_seq)); - _tdata_psh_info_pool_enq(tcpack_sup_mod, tdata_psh_info_tmp); - } -#ifdef DHDTCPACK_SUP_DBG - DHD_ERROR(("%s %d: PSH INFO ENQ %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); -#endif /* DHDTCPACK_SUP_DBG */ - tcpack_sup_mod->tcpdata_info_cnt--; - ASSERT(tcpack_sup_mod->tcpdata_info_cnt >= 0); - - last_tdata_info = - &tcpack_sup_mod->tcpdata_info_tbl[tcpack_sup_mod->tcpdata_info_cnt]; - if (i < tcpack_sup_mod->tcpdata_info_cnt) { - ASSERT(last_tdata_info != tdata_info_tmp); - bcopy(last_tdata_info, tdata_info_tmp, sizeof(tcpdata_info_t)); - } - bzero(last_tdata_info, sizeof(tcpdata_info_t)); - DHD_INFO(("%s %d: tcpdata_info(idx %d) is aged out. ttl cnt is now %d\n", - __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt)); - /* Don't increase "i" here, so that the prev last tcpdata_info is checked */ - } else - i++; - } - - tcp_seq_num = ntoh32_ua(&tcp_hdr[TCP_SEQ_NUM_OFFSET]); - tcp_data_len = ip_total_len - ip_hdr_len - tcp_hdr_len; - end_tcp_seq_num = tcp_seq_num + tcp_data_len; - - if (tcpdata_info == NULL) { - ASSERT(i == tcpack_sup_mod->tcpdata_info_cnt); - if (i >= TCPDATA_INFO_MAXNUM) { - DHD_TRACE(("%s %d: tcp_data_info_tbl FULL! %d %d" - " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", - __FUNCTION__, __LINE__, i, tcpack_sup_mod->tcpdata_info_cnt, - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]))); - dhd_os_tcpackunlock(dhdp, flags); - goto exit; - } - tcpdata_info = &tcpack_sup_mod->tcpdata_info_tbl[i]; - - /* No TCP flow with the same IP addr and TCP port is found - * in tcp_data_info_tbl. So add this flow to the table. - */ - DHD_INFO(("%s %d: Add data info to tbl[%d]: IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->tcpdata_info_cnt, - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]))); - /* Note that src/dst addr fields in ip header are contiguous being 8 bytes in total. - * Also, src/dst port fields in TCP header are contiguous being 4 bytes in total. - */ - bcopy(&ip_hdr[IPV4_SRC_IP_OFFSET], (void *)&tcpdata_info->ip_addr, - IPV4_ADDR_LEN * 2); - bcopy(&tcp_hdr[TCP_SRC_PORT_OFFSET], (void *)&tcpdata_info->tcp_port, - TCP_PORT_LEN * 2); - - tcpdata_info->last_used_time = OSL_SYSUPTIME(); - tcpack_sup_mod->tcpdata_info_cnt++; - } - - ASSERT(tcpdata_info != NULL); - - tdata_psh_info = _tdata_psh_info_pool_deq(tcpack_sup_mod); -#ifdef DHDTCPACK_SUP_DBG - DHD_TRACE(("%s %d: PSH INFO ENQ %d\n", - __FUNCTION__, __LINE__, tcpack_sup_mod->psh_info_enq_num)); -#endif /* DHDTCPACK_SUP_DBG */ - - if (tdata_psh_info == NULL) { - DHD_ERROR(("%s %d: No more free tdata_psh_info!!\n", __FUNCTION__, __LINE__)); - ret = BCME_ERROR; - dhd_os_tcpackunlock(dhdp, flags); - goto exit; - } - tdata_psh_info->end_seq = end_tcp_seq_num; - -#if defined(DEBUG_COUNTER) && defined(DHDTCPACK_SUP_DBG) - tack_tbl.cnt[4]++; -#endif /* DEBUG_COUNTER && DHDTCPACK_SUP_DBG */ - - DHD_TRACE(("%s %d: TCP PSH DATA recvd! end seq %u\n", - __FUNCTION__, __LINE__, tdata_psh_info->end_seq)); - - ASSERT(tdata_psh_info->next == NULL); - - if (tcpdata_info->tdata_psh_info_head == NULL) - tcpdata_info->tdata_psh_info_head = tdata_psh_info; - else { - ASSERT(tcpdata_info->tdata_psh_info_tail); - tcpdata_info->tdata_psh_info_tail->next = tdata_psh_info; - } - tcpdata_info->tdata_psh_info_tail = tdata_psh_info; - - dhd_os_tcpackunlock(dhdp, flags); - -exit: - return ret; -} - -bool -dhd_tcpack_hold(dhd_pub_t *dhdp, void *pkt, int ifidx) -{ - uint8 *new_ether_hdr; /* Ethernet header of the new packet */ - uint16 new_ether_type; /* Ethernet type of the new packet */ - uint8 *new_ip_hdr; /* IP header of the new packet */ - uint8 *new_tcp_hdr; /* TCP header of the new packet */ - uint32 new_ip_hdr_len; /* IP header length of the new packet */ - uint32 cur_framelen; - uint32 new_tcp_ack_num; /* TCP acknowledge number of the new packet */ - uint16 new_ip_total_len; /* Total length of IP packet for the new packet */ - uint32 new_tcp_hdr_len; /* TCP header length of the new packet */ - tcpack_sup_module_t *tcpack_sup_mod; - tcpack_info_t *tcpack_info_tbl; - int i, free_slot = TCPACK_INFO_MAXNUM; - bool hold = FALSE; - unsigned long flags; - - if (dhdp->tcpack_sup_mode != TCPACK_SUP_HOLD) { - goto exit; - } - - if (dhdp->tcpack_sup_ratio == 1) { - goto exit; - } - - new_ether_hdr = PKTDATA(dhdp->osh, pkt); - cur_framelen = PKTLEN(dhdp->osh, pkt); - - if (cur_framelen < TCPACKSZMIN || cur_framelen > TCPACKSZMAX) { - DHD_TRACE(("%s %d: Too short or long length %d to be TCP ACK\n", - __FUNCTION__, __LINE__, cur_framelen)); - goto exit; - } - - new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13]; - - if (new_ether_type != ETHER_TYPE_IP) { - DHD_TRACE(("%s %d: Not a IP packet 0x%x\n", - __FUNCTION__, __LINE__, new_ether_type)); - goto exit; - } - - DHD_TRACE(("%s %d: IP pkt! 0x%x\n", __FUNCTION__, __LINE__, new_ether_type)); - - new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN; - cur_framelen -= ETHER_HDR_LEN; - - ASSERT(cur_framelen >= IPV4_MIN_HEADER_LEN); - - new_ip_hdr_len = IPV4_HLEN(new_ip_hdr); - if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) { - DHD_TRACE(("%s %d: Not IPv4 nor TCP! ip ver %d, prot %d\n", - __FUNCTION__, __LINE__, IP_VER(new_ip_hdr), IPV4_PROT(new_ip_hdr))); - goto exit; - } - - new_tcp_hdr = new_ip_hdr + new_ip_hdr_len; - cur_framelen -= new_ip_hdr_len; - - ASSERT(cur_framelen >= TCP_MIN_HEADER_LEN); - - DHD_TRACE(("%s %d: TCP pkt!\n", __FUNCTION__, __LINE__)); - - /* is it an ack ? Allow only ACK flag, not to suppress others. */ - if (new_tcp_hdr[TCP_FLAGS_OFFSET] != TCP_FLAG_ACK) { - DHD_TRACE(("%s %d: Do not touch TCP flag 0x%x\n", - __FUNCTION__, __LINE__, new_tcp_hdr[TCP_FLAGS_OFFSET])); - goto exit; - } - - new_ip_total_len = ntoh16_ua(&new_ip_hdr[IPV4_PKTLEN_OFFSET]); - new_tcp_hdr_len = 4 * TCP_HDRLEN(new_tcp_hdr[TCP_HLEN_OFFSET]); - - /* This packet has TCP data, so just send */ - if (new_ip_total_len > new_ip_hdr_len + new_tcp_hdr_len) { - DHD_TRACE(("%s %d: Do nothing for TCP DATA\n", __FUNCTION__, __LINE__)); - goto exit; - } - - ASSERT(new_ip_total_len == new_ip_hdr_len + new_tcp_hdr_len); - - new_tcp_ack_num = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]); - - DHD_TRACE(("%s %d: TCP ACK with zero DATA length" - " IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR" TCP port %d %d\n", - __FUNCTION__, __LINE__, - IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&new_ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]))); - - /* Look for tcp_ack_info that has the same ip src/dst addrs and tcp src/dst ports */ - flags = dhd_os_tcpacklock(dhdp); - - tcpack_sup_mod = dhdp->tcpack_sup_module; - tcpack_info_tbl = tcpack_sup_mod->tcpack_info_tbl; - - if (!tcpack_sup_mod) { - DHD_ERROR(("%s %d: tcpack suppress module NULL!!\n", __FUNCTION__, __LINE__)); - dhd_os_tcpackunlock(dhdp, flags); - goto exit; - } - - hold = TRUE; - - for (i = 0; i < TCPACK_INFO_MAXNUM; i++) { - void *oldpkt; /* TCPACK packet that is already in txq or DelayQ */ - uint8 *old_ether_hdr, *old_ip_hdr, *old_tcp_hdr; - uint32 old_ip_hdr_len; - uint32 old_tcpack_num; /* TCP ACK number of old TCPACK packet in Q */ - - if ((oldpkt = tcpack_info_tbl[i].pkt_in_q) == NULL) { - if (free_slot == TCPACK_INFO_MAXNUM) { - free_slot = i; - } - continue; - } - - if (PKTDATA(dhdp->osh, oldpkt) == NULL) { - DHD_ERROR(("%s %d: oldpkt data NULL!! cur idx %d\n", - __FUNCTION__, __LINE__, i)); - hold = FALSE; - dhd_os_tcpackunlock(dhdp, flags); - goto exit; - } - - old_ether_hdr = tcpack_info_tbl[i].pkt_ether_hdr; - old_ip_hdr = old_ether_hdr + ETHER_HDR_LEN; - old_ip_hdr_len = IPV4_HLEN(old_ip_hdr); - old_tcp_hdr = old_ip_hdr + old_ip_hdr_len; - - DHD_TRACE(("%s %d: oldpkt %p[%d], IP addr "IPV4_ADDR_STR" "IPV4_ADDR_STR - " TCP port %d %d\n", __FUNCTION__, __LINE__, oldpkt, i, - IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_SRC_IP_OFFSET])), - IPV4_ADDR_TO_STR(ntoh32_ua(&old_ip_hdr[IPV4_DEST_IP_OFFSET])), - ntoh16_ua(&old_tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&old_tcp_hdr[TCP_DEST_PORT_OFFSET]))); - - /* If either of IP address or TCP port number does not match, skip. */ - if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET], - &old_ip_hdr[IPV4_SRC_IP_OFFSET], IPV4_ADDR_LEN * 2) || - memcmp(&new_tcp_hdr[TCP_SRC_PORT_OFFSET], - &old_tcp_hdr[TCP_SRC_PORT_OFFSET], TCP_PORT_LEN * 2)) { - continue; - } - - old_tcpack_num = ntoh32_ua(&old_tcp_hdr[TCP_ACK_NUM_OFFSET]); - - if (IS_TCPSEQ_GE(new_tcp_ack_num, old_tcpack_num)) { - tcpack_info_tbl[i].supp_cnt++; - if (tcpack_info_tbl[i].supp_cnt >= dhdp->tcpack_sup_ratio) { - tcpack_info_tbl[i].pkt_in_q = NULL; - tcpack_info_tbl[i].pkt_ether_hdr = NULL; - tcpack_info_tbl[i].ifidx = 0; - tcpack_info_tbl[i].supp_cnt = 0; - hold = FALSE; - } else { - tcpack_info_tbl[i].pkt_in_q = pkt; - tcpack_info_tbl[i].pkt_ether_hdr = new_ether_hdr; - tcpack_info_tbl[i].ifidx = ifidx; - } - PKTFREE(dhdp->osh, oldpkt, TRUE); - } else { - PKTFREE(dhdp->osh, pkt, TRUE); - } - dhd_os_tcpackunlock(dhdp, flags); - - if (!hold) { - del_timer_sync(&tcpack_info_tbl[i].timer); - } - goto exit; - } - - if (free_slot < TCPACK_INFO_MAXNUM) { - /* No TCPACK packet with the same IP addr and TCP port is found - * in tcp_ack_info_tbl. So add this packet to the table. - */ - DHD_TRACE(("%s %d: Add pkt 0x%p(ether_hdr 0x%p) to tbl[%d]\n", - __FUNCTION__, __LINE__, pkt, new_ether_hdr, - free_slot)); - - tcpack_info_tbl[free_slot].pkt_in_q = pkt; - tcpack_info_tbl[free_slot].pkt_ether_hdr = new_ether_hdr; - tcpack_info_tbl[free_slot].ifidx = ifidx; - tcpack_info_tbl[free_slot].supp_cnt = 1; - mod_timer(&tcpack_sup_mod->tcpack_info_tbl[free_slot].timer, - jiffies + msecs_to_jiffies(dhdp->tcpack_sup_delay)); - tcpack_sup_mod->tcpack_info_cnt++; - } else { - DHD_TRACE(("%s %d: No empty tcp ack info tbl\n", - __FUNCTION__, __LINE__)); - } - dhd_os_tcpackunlock(dhdp, flags); - -exit: - return hold; -} -#endif /* DHDTCPACK_SUPPRESS */
diff --git a/bcmdhd.1.579.77.41.x/dhd_ip.h b/bcmdhd.1.579.77.41.x/dhd_ip.h deleted file mode 100644 index 240d852..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_ip.h +++ /dev/null
@@ -1,85 +0,0 @@ -/* - * Header file describing the common ip parser function. - * - * Provides type definitions and function prototypes used to parse ip packet. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_ip.h 536854 2015-02-24 13:17:29Z $ - */ - -#ifndef _dhd_ip_h_ -#define _dhd_ip_h_ - -#ifdef DHDTCPACK_SUPPRESS -#include <dngl_stats.h> -#include <bcmutils.h> -#include <dhd.h> -#endif /* DHDTCPACK_SUPPRESS */ - -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 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_ */
diff --git a/bcmdhd.1.579.77.41.x/dhd_linux.c b/bcmdhd.1.579.77.41.x/dhd_linux.c deleted file mode 100644 index 438b6a2..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_linux.c +++ /dev/null
@@ -1,22090 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), Linux-specific network interface - * Basically selected code segments from usb-cdc.c and usb-rndis.c - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_linux.c 710862 2017-07-14 07:43:59Z $ - */ - -#include <typedefs.h> -#include <linuxver.h> -#include <osl.h> -#ifdef SHOW_LOGTRACE -#include <linux/syscalls.h> -#include <event_log.h> -#endif /* SHOW_LOGTRACE */ - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/inetdevice.h> -#include <linux/rtnetlink.h> -#include <linux/etherdevice.h> -#include <linux/random.h> -#include <linux/spinlock.h> -#include <linux/ethtool.h> -#include <linux/fcntl.h> -#include <linux/fs.h> -#include <linux/ip.h> -#include <linux/reboot.h> -#include <linux/notifier.h> -#include <net/addrconf.h> -#ifdef ENABLE_ADAPTIVE_SCHED -#include <linux/cpufreq.h> -#endif /* ENABLE_ADAPTIVE_SCHED */ - -#include <asm/uaccess.h> -#include <asm/unaligned.h> - -#include <epivers.h> -#include <bcmutils.h> -#include <bcmendian.h> -#include <bcmdevs.h> - - -#include <ethernet.h> -#include <bcmevent.h> -#include <vlan.h> -#include <802.3.h> - -#include <dngl_stats.h> -#include <dhd_linux_wq.h> -#include <dhd.h> -#include <dhd_linux.h> -#ifdef DHD_WET -#include <dhd_wet.h> -#endif /* DHD_WET */ -#ifdef PCIE_FULL_DONGLE -#include <dhd_flowring.h> -#endif -#include <dhd_bus.h> -#include <dhd_proto.h> -#include <dhd_config.h> -#ifdef WL_ESCAN -#include <wl_escan.h> -#endif -#include <dhd_dbg.h> -#include <dhd_debug.h> -#ifdef CONFIG_HAS_WAKELOCK -#include <linux/wakelock.h> -#endif -#ifdef WL_CFG80211 -#include <wl_cfg80211.h> -#endif -#ifdef PNO_SUPPORT -#include <dhd_pno.h> -#endif -#ifdef RTT_SUPPORT -#include <dhd_rtt.h> -#endif -#ifdef DHD_TIMESYNC -#include <dhd_timesync.h> -#endif /* DHD_TIMESYNC */ -#ifdef WIFI_STATS -#include <linux/time.h> -#include <linux/rtc.h> -#endif /* WIFI_STATS */ - -#ifdef CONFIG_COMPAT -#include <linux/compat.h> -#endif - -#if defined(CONFIG_SOC_EXYNOS8895) -#include <linux/exynos-pci-ctrl.h> -#endif /* CONFIG_SOC_EXYNOS8895 */ - -#ifdef DHD_WMF -#include <dhd_wmf_linux.h> -#endif /* DHD_WMF */ - -#ifdef DHD_L2_FILTER -#include <bcmicmp.h> -#include <bcm_l2_filter.h> -#include <dhd_l2_filter.h> -#endif /* DHD_L2_FILTER */ - -#ifdef DHD_PSTA -#include <dhd_psta.h> -#endif /* DHD_PSTA */ - -#ifdef BCOL_TCPKA_SYNC -bcol_tcpka_sync_t tcpka_sync; -#include <dhd_bcol_tcpka_pub.h> -#include <net/tcp.h> -#endif /* BCOL_TCPKA_SYNC */ - -#ifdef DHDTCPACK_SUPPRESS -#include <dhd_ip.h> -#endif /* DHDTCPACK_SUPPRESS */ -#include <dhd_daemon.h> -#ifdef DHD_PKT_LOGGING -#include <dhd_pktlog.h> -#endif /* DHD_PKT_LOGGING */ -#if defined(STAT_REPORT) -#include <wl_statreport.h> -#endif /* STAT_REPORT */ -#ifdef DHD_DEBUG_PAGEALLOC -typedef void (*page_corrupt_cb_t)(void *handle, void *addr_corrupt, size_t len); -void dhd_page_corrupt_cb(void *handle, void *addr_corrupt, size_t len); -extern void register_page_corrupt_cb(page_corrupt_cb_t cb, void* handle); -#endif /* DHD_DEBUG_PAGEALLOC */ -#ifdef SCHED_WAKE -extern int dhd_sched_wake_setup(dhd_pub_t *dhdp, uint32 reason); -#endif /* SCHED_WAKE */ - -#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 -#if !defined(DHD_LB_SECONDARY_CPUS) -#define DHD_LB_SECONDARY_CPUS 0xFE /* Little CPU coreids mask */ -#endif - -#define HIST_BIN_SIZE 9 - -static void dhd_rx_napi_dispatcher_fn(struct work_struct * work); - -#if defined(DHD_LB_TXP) -static void dhd_lb_tx_handler(unsigned long data); -static void dhd_tx_dispatcher_work(struct work_struct * work); -static void dhd_tx_dispatcher_fn(dhd_pub_t *dhdp); -static void dhd_lb_tx_dispatch(dhd_pub_t *dhdp); - -/* 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 HOFFLOAD_MODULES -#include <linux/firmware.h> -#endif - -#ifdef WLMEDIA_HTSF -#include <linux/time.h> -#include <htsf.h> - -#define HTSF_MINLEN 200 /* min. packet length to timestamp */ -#define HTSF_BUS_DELAY 150 /* assume a fix propagation in us */ -#define TSMAX 1000 /* max no. of timing record kept */ -#define NUMBIN 34 - -static uint32 tsidx = 0; -static uint32 htsf_seqnum = 0; -uint32 tsfsync; -struct timeval tsync; -static uint32 tsport = 5010; - -typedef struct histo_ { - uint32 bin[NUMBIN]; -} histo_t; - -#if !ISPOWEROF2(DHD_SDALIGN) -#error DHD_SDALIGN is not a power of 2! -#endif - -static histo_t vi_d1, vi_d2, vi_d3, vi_d4; -#endif /* WLMEDIA_HTSF */ - -#ifdef WL_MONITOR -#include <bcmmsgbuf.h> -#include <bcmwifi_monitor.h> -#endif - -#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 STBLINUX -#ifdef quote_str -#undef quote_str -#endif /* quote_str */ -#ifdef to_str -#undef to_str -#endif /* quote_str */ -#define to_str(s) #s -#define quote_str(s) to_str(s) - -static char *driver_target = "driver_target: "quote_str(BRCM_DRIVER_TARGET); -#endif /* STBLINUX */ - -#ifdef TCPKA_REPAIR -static int dhd_tcpka_repair_pkt_check(dhd_pub_t *dhdp, void *pkt, - tcpka_conn_repair_t *info, const char *func); -static void dhd_tcpka_repair_pkt_sendup(dhd_pub_t *dhdp); -static void dhd_tcpka_reset(dhd_pub_t *dhd, struct net_device *dev); -static void dhd_tcpka_repair_pkt_sendup_action( -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) - struct timer_list *t -#else - ulong data -#endif -); -#endif /* TCPKA_REPAIR */ -#ifdef WIFI_STATS -wifi_fw_stats_t g_wstats; -#endif /* WIFI_STATS */ - -#if defined(SOFTAP) -extern bool ap_cfg_running; -extern bool ap_fw_loaded; -#endif - -#ifdef DHD_8021X_DUMP -extern void dhd_dump_eapol_4way_message(char *ifname, char *dump_data, bool direction); -#endif /* DHD_8021X_DUMP */ - -#ifdef FIX_CPU_MIN_CLOCK -#include <linux/pm_qos.h> -#endif /* FIX_CPU_MIN_CLOCK */ - -#ifdef SET_RANDOM_MAC_SOFTAP -#ifndef CONFIG_DHD_SET_RANDOM_MAC_VAL -#define CONFIG_DHD_SET_RANDOM_MAC_VAL 0x001A11 -#endif -static u32 vendor_oui = CONFIG_DHD_SET_RANDOM_MAC_VAL; -#endif /* SET_RANDOM_MAC_SOFTAP */ - -#ifdef ENABLE_ADAPTIVE_SCHED -#define DEFAULT_CPUFREQ_THRESH 1000000 /* threshold frequency : 1000000 = 1GHz */ -#ifndef CUSTOM_CPUFREQ_THRESH -#define CUSTOM_CPUFREQ_THRESH DEFAULT_CPUFREQ_THRESH -#endif /* CUSTOM_CPUFREQ_THRESH */ -#endif /* ENABLE_ADAPTIVE_SCHED */ - -/* enable HOSTIP cache update from the host side when an eth0:N is up */ -#define AOE_IP_ALIAS_SUPPORT 1 - -#ifdef BCM_FD_AGGR -#include <bcm_rpc.h> -#include <bcm_rpc_tp.h> -#endif -#ifdef PROP_TXSTATUS -#include <wlfc_proto.h> -#include <dhd_wlfc.h> -#endif - -#include <wl_android.h> - -/* Maximum STA per radio */ -#define DHD_MAX_STA 32 - - - -const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 }; -const uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; -#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]] - -#ifdef ARP_OFFLOAD_SUPPORT -void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx); -static int dhd_inetaddr_notifier_call(struct notifier_block *this, - unsigned long event, void *ptr); -static struct notifier_block dhd_inetaddr_notifier = { - .notifier_call = dhd_inetaddr_notifier_call -}; -/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be - * created in kernel notifier link list (with 'next' pointing to itself) - */ -static bool dhd_inetaddr_notifier_registered = FALSE; -#endif /* ARP_OFFLOAD_SUPPORT */ - -#if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT) -int dhd_inet6addr_notifier_call(struct notifier_block *this, - unsigned long event, void *ptr); -static struct notifier_block dhd_inet6addr_notifier = { - .notifier_call = dhd_inet6addr_notifier_call -}; -/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be - * created in kernel notifier link list (with 'next' pointing to itself) - */ -static bool dhd_inet6addr_notifier_registered = FALSE; -#endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) -#include <linux/suspend.h> -volatile bool dhd_mmc_suspend = FALSE; -DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ - -#if defined(OOB_INTR_ONLY) || defined(FORCE_WOWLAN) -extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -static void dhd_hang_process(void *dhd_info, void *event_data, u8 event); -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -MODULE_LICENSE("GPL and additional rights"); -#endif /* LinuxVer */ - -#if defined(MULTIPLE_SUPPLICANT) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -DEFINE_MUTEX(_dhd_mutex_lock_); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ -#endif - -#ifdef CONFIG_BCM_DETECT_CONSECUTIVE_HANG -#define MAX_CONSECUTIVE_HANG_COUNTS 5 -#endif /* CONFIG_BCM_DETECT_CONSECUTIVE_HANG */ - -#include <dhd_bus.h> - -#ifdef DHD_ULP -#include <dhd_ulp.h> -#endif /* DHD_ULP */ - -#ifdef BCM_FD_AGGR -#define DBUS_RX_BUFFER_SIZE_DHD(net) (BCM_RPC_TP_DNGL_AGG_MAX_BYTE) -#else -#ifndef PROP_TXSTATUS -#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen) -#else -#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128) -#endif -#endif /* BCM_FD_AGGR */ - -#ifdef PROP_TXSTATUS -extern bool dhd_wlfc_skip_fc(void * dhdp, uint8 idx); -extern void dhd_wlfc_plat_init(void *dhd); -extern void dhd_wlfc_plat_deinit(void *dhd); -#endif /* PROP_TXSTATUS */ -extern uint sd_f2_blocksize; -extern int dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size); - -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) -const char * -print_tainted() -{ - return ""; -} -#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */ - -/* Linux wireless extension support */ -#if defined(WL_WIRELESS_EXT) -#include <wl_iw.h> -extern wl_iw_extra_params_t g_wl_iw_params; -#endif /* defined(WL_WIRELESS_EXT) */ - -#ifdef CONFIG_PARTIALSUSPEND_SLP -#include <linux/partialsuspend_slp.h> -#define CONFIG_HAS_EARLYSUSPEND -#define DHD_USE_EARLYSUSPEND -#define register_early_suspend register_pre_suspend -#define unregister_early_suspend unregister_pre_suspend -#define early_suspend pre_suspend -#define EARLY_SUSPEND_LEVEL_BLANK_SCREEN 50 -#else -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) -#include <linux/earlysuspend.h> -#endif /* defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) */ -#endif /* CONFIG_PARTIALSUSPEND_SLP */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) -#include <linux/nl80211.h> -#endif /* OEM_ANDROID && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */ - -#if defined(BCMPCIE) -extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd, int *dtim_period, int *bcn_interval); -#else -extern int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd); -#endif /* OEM_ANDROID && BCMPCIE */ - -#ifdef PKT_FILTER_SUPPORT -extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); -extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); -extern void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id); -#endif - -#if defined(PKT_FILTER_SUPPORT) && defined(APF) -static int __dhd_apf_add_filter(struct net_device *ndev, uint32 filter_id, - u8* program, uint32 program_len); -static int __dhd_apf_config_filter(struct net_device *ndev, uint32 filter_id, - uint32 mode, uint32 enable); -static int __dhd_apf_delete_filter(struct net_device *ndev, uint32 filter_id); -#endif /* PKT_FILTER_SUPPORT && APF */ - - - -static INLINE int argos_register_notifier_init(struct net_device *net) { return 0;} -static INLINE int argos_register_notifier_deinit(void) { return 0;} - -#if defined(BT_OVER_SDIO) -extern void wl_android_set_wifi_on_flag(bool enable); -#endif /* BT_OVER_SDIO */ - - -#if defined(TRAFFIC_MGMT_DWM) -void traffic_mgmt_pkt_set_prio(dhd_pub_t *dhdp, void * pktbuf); -#endif - -#ifdef DHD_FW_COREDUMP -static void dhd_mem_dump(void *dhd_info, void *event_info, u8 event); -#endif /* DHD_FW_COREDUMP */ -#ifdef DHD_LOG_DUMP -#define DLD_BUFFER_NUM 2 -/* [0]: General, [1]: Special */ -struct dhd_log_dump_buf g_dld_buf[DLD_BUFFER_NUM]; -static const int dld_buf_size[] = { - (1024 * 1024), /* DHD_LOG_DUMP_BUFFER_SIZE */ - (8 * 1024) /* DHD_LOG_DUMP_BUFFER_EX_SIZE */ -}; -static void dhd_log_dump_init(dhd_pub_t *dhd); -static void dhd_log_dump_deinit(dhd_pub_t *dhd); -static void dhd_log_dump(void *handle, void *event_info, u8 event); -void dhd_schedule_log_dump(dhd_pub_t *dhdp); -static int do_dhd_log_dump(dhd_pub_t *dhdp); -#endif /* DHD_LOG_DUMP */ - -#ifdef DHD_DEBUG_UART -#include <linux/kmod.h> -#define DHD_DEBUG_UART_EXEC_PATH "/system/bin/wldu" -static void dhd_debug_uart_exec_rd(void *handle, void *event_info, u8 event); -static void dhd_debug_uart_exec(dhd_pub_t *dhdp, char *cmd); -#endif /* DHD_DEBUG_UART */ - -static int dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused); -static struct notifier_block dhd_reboot_notifier = { - .notifier_call = dhd_reboot_callback, - .priority = 1, -}; - -#ifdef BCMPCIE -static int is_reboot = 0; -#endif /* BCMPCIE */ - -dhd_pub_t *g_dhd_pub = NULL; - -atomic_t exit_in_progress = ATOMIC_INIT(0); - -typedef struct dhd_if_event { - struct list_head list; - wl_event_data_if_t event; - char name[IFNAMSIZ+1]; - uint8 mac[ETHER_ADDR_LEN]; -} dhd_if_event_t; - -/* Interface control information */ -typedef struct dhd_if { - struct dhd_info *info; /* back pointer to dhd_info */ - /* OS/stack specifics */ - struct net_device *net; - int idx; /* iface idx in dongle */ - uint subunit; /* subunit */ - uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */ - bool set_macaddress; - bool set_multicast; - uint8 bssidx; /* bsscfg index for the interface */ - bool attached; /* Delayed attachment when unset */ - bool txflowcontrol; /* Per interface flow control indicator */ - char name[IFNAMSIZ+1]; /* linux interface name */ - char dngl_name[IFNAMSIZ+1]; /* corresponding dongle interface name */ - struct net_device_stats stats; -#ifdef DHD_WMF - dhd_wmf_t wmf; /* per bsscfg wmf setting */ - bool wmf_psta_disable; /* enable/disable MC pkt to each mac - * of MC group behind PSTA - */ -#endif /* DHD_WMF */ -#ifdef PCIE_FULL_DONGLE - struct list_head sta_list; /* sll of associated stations */ -#if !defined(BCM_GMAC3) - spinlock_t sta_list_lock; /* lock for manipulating sll */ -#endif /* ! BCM_GMAC3 */ -#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; -#endif /* DHD_L2_FILTER */ -#ifdef DHD_MCAST_REGEN - bool mcast_regen_bss_enable; -#endif - bool rx_pkt_chainable; /* set all rx packet to chainable config by default */ - cumm_ctr_t cumm_ctr; /* cummulative queue length of child flowrings */ -} dhd_if_t; - -#ifdef WLMEDIA_HTSF -typedef struct { - uint32 low; - uint32 high; -} tsf_t; - -typedef struct { - uint32 last_cycle; - uint32 last_sec; - uint32 last_tsf; - uint32 coef; /* scaling factor */ - uint32 coefdec1; /* first decimal */ - uint32 coefdec2; /* second decimal */ -} htsf_t; - -typedef struct { - uint32 t1; - uint32 t2; - uint32 t3; - uint32 t4; -} tstamp_t; - -static tstamp_t ts[TSMAX]; -static tstamp_t maxdelayts; -static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0; - -#endif /* WLMEDIA_HTSF */ - -struct ipv6_work_info_t { - uint8 if_idx; - char ipv6_addr[IPV6_ADDR_LEN]; - unsigned long event; -}; -static void dhd_process_daemon_msg(struct sk_buff *skb); -static void dhd_destroy_to_notifier_skt(void); -static int dhd_create_to_notifier_skt(void); -static struct sock *nl_to_event_sk = NULL; -int sender_pid = 0; -static bool show_firstpkt = FALSE; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) -struct netlink_kernel_cfg g_cfg = { - .groups = 1, - .input = dhd_process_daemon_msg, -}; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) */ - -typedef struct dhd_dump { - uint8 *buf; - int bufsize; -} dhd_dump_t; - - -/* When Perimeter locks are deployed, any blocking calls must be preceeded - * with a PERIM UNLOCK and followed by a PERIM LOCK. - * Examples of blocking calls are: schedule_timeout(), down_interruptible(), - * wait_event_timeout(). - */ - -/* 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; - dhd_if_t *iflist[DHD_MAX_IFS]; /* for supporting multiple interfaces */ - - 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 */ - char reg_path[PATH_MAX]; /* path to reg 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 */ -#ifdef WLMEDIA_HTSF - htsf_t htsf; -#endif - wait_queue_head_t ioctl_resp_wait; - wait_queue_head_t d3ack_wait; - wait_queue_head_t dhd_bus_busy_state_wait; - uint32 default_wd_interval; - - struct timer_list timer; - bool wd_timer_valid; -#ifdef TCPKA_REPAIR - struct timer_list tcpka_rp_timer; -#endif /* TCPKA_REPAIR */ -#ifdef DHD_PCIE_RUNTIMEPM - struct timer_list rpm_timer; - bool rpm_timer_valid; - tsk_ctl_t thr_rpm_ctl; -#endif /* DHD_PCIE_RUNTIMEPM */ - struct tasklet_struct tasklet; - spinlock_t sdlock; - spinlock_t txqlock; - spinlock_t rxqlock; - 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) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - 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 && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - /* 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 */ -#endif - 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 BCM_FD_AGGR - void *rpc_th; - void *rpc_osh; - struct timer_list rpcth_timer; - bool rpcth_timer_active; - uint8 fdaggr; -#endif -#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 - 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 -#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; - - /* 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; - - /* - * 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; - - /* 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 */ - -#ifdef SHOW_LOGTRACE - struct work_struct event_log_dispatcher_work; -#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; -#ifdef SHOW_LOGTRACE - struct sk_buff_head evt_trace_queue ____cacheline_aligned; -#endif - 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 */ - monitor_info_t *monitor_info; -#endif /* WL_MONITOR */ - uint32 shub_enable; -#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 DHD_DEBUG_UART - bool duart_execute; -#endif -#ifdef PCIE_INB_DW - wait_queue_head_t ds_exit_wait; -#endif /* PCIE_INB_DW */ -#ifdef TCPKA_REPAIR - struct work_struct tcpka_reset_work; -#endif /* TCPKA_REPAIR */ -} dhd_info_t; - -#ifdef WL_MONITOR -#define MONPKT_EXTRA_LEN 48 -#endif - -#define DHDIF_FWDER(dhdif) FALSE - -#if defined(BT_OVER_SDIO) -/* Flag to indicate if driver is initialized */ -uint dhd_driver_init_done = TRUE; -#else -/* Flag to indicate if driver is initialized */ -uint dhd_driver_init_done = FALSE; -#endif -/* Flag to indicate if we should download firmware on driver load */ -uint dhd_download_fw_on_driverload = TRUE; - -/* Definitions to provide path to the firmware and nvram - * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt" - */ -char firmware_path[MOD_PARAM_PATHLEN]; -char nvram_path[MOD_PARAM_PATHLEN]; -char clm_path[MOD_PARAM_PATHLEN]; -char config_path[MOD_PARAM_PATHLEN]; -char reg_path[MOD_PARAM_PATHLEN]; -#ifdef DHD_UCODE_DOWNLOAD -char ucode_path[MOD_PARAM_PATHLEN]; -#endif /* DHD_UCODE_DOWNLOAD */ - -module_param_string(clm_path, clm_path, MOD_PARAM_PATHLEN, 0660); - - -/* backup buffer for firmware and nvram path */ -char fw_bak_path[MOD_PARAM_PATHLEN]; -char nv_bak_path[MOD_PARAM_PATHLEN]; - -/* information string to keep firmware, chio, cheip version info visiable from log */ -char info_string[MOD_PARAM_INFOLEN]; -module_param_string(info_string, info_string, MOD_PARAM_INFOLEN, 0444); -int op_mode = 0; -int disable_proptx = 0; -module_param(op_mode, int, 0644); -extern int wl_control_wl_start(struct net_device *dev); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (defined(BCMLXSDMMC) || defined(BCMDBUS)) -struct semaphore dhd_registration_sem; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ - -/* deferred handlers */ -static void dhd_ifadd_event_handler(void *handle, void *event_info, u8 event); -static void dhd_ifdel_event_handler(void *handle, void *event_info, u8 event); -static void dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event); -static void dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event); - -#ifdef DHD_UPDATE_INTF_MAC -static void dhd_ifupdate_event_handler(void *handle, void *event_info, u8 event); -#endif /* DHD_UPDATE_INTF_MAC */ -#if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT) -static void dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event); -#endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ -#ifdef WL_CFG80211 -extern void dhd_netdev_free(struct net_device *ndev); -#endif /* WL_CFG80211 */ - -#if (defined(DHD_WET) || defined(DHD_MCAST_REGEN) || defined(DHD_L2_FILTER)) -/* update rx_pkt_chainable state of dhd interface */ -static void dhd_update_rx_pkt_chainable_state(dhd_pub_t* dhdp, uint32 idx); -#endif /* DHD_WET || DHD_MCAST_REGEN || DHD_L2_FILTER */ - -#ifdef HOFFLOAD_MODULES -char dhd_hmem_module_string[MOD_PARAM_SRLEN]; -module_param_string(dhd_hmem_module_string, dhd_hmem_module_string, MOD_PARAM_SRLEN, 0660); -#endif -/* Error bits */ -module_param(dhd_msg_level, int, 0); -#if defined(WL_WIRELESS_EXT) -module_param(iw_msg_level, int, 0); -#endif -#ifdef WL_CFG80211 -module_param(wl_dbg_level, int, 0); -#endif -module_param(android_msg_level, int, 0); -module_param(config_msg_level, int, 0); - -#ifdef ARP_OFFLOAD_SUPPORT -/* ARP offload enable */ -uint dhd_arp_enable = TRUE; -module_param(dhd_arp_enable, uint, 0); - -/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */ - -#ifdef ENABLE_ARP_SNOOP_MODE -uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY | ARP_OL_SNOOP | ARP_OL_HOST_AUTO_REPLY; -#else -uint dhd_arp_mode = ARP_OL_AGENT | ARP_OL_PEER_AUTO_REPLY; -#endif /* ENABLE_ARP_SNOOP_MODE */ - -module_param(dhd_arp_mode, uint, 0); -#endif /* ARP_OFFLOAD_SUPPORT */ - -/* Disable Prop tx */ -module_param(disable_proptx, int, 0644); -/* load firmware and/or nvram values from the filesystem */ -module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660); -module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0660); -module_param_string(config_path, config_path, MOD_PARAM_PATHLEN, 0660); -module_param_string(reg_path, reg_path, MOD_PARAM_PATHLEN, 0660); -#ifdef DHD_UCODE_DOWNLOAD -module_param_string(ucode_path, ucode_path, MOD_PARAM_PATHLEN, 0660); -#endif /* DHD_UCODE_DOWNLOAD */ - -/* Watchdog interval */ - -/* extend watchdog expiration to 2 seconds when DPC is running */ -#define WATCHDOG_EXTEND_INTERVAL (2000) - -uint dhd_watchdog_ms = CUSTOM_DHD_WATCHDOG_MS; -module_param(dhd_watchdog_ms, uint, 0); - -#ifdef DHD_PCIE_RUNTIMEPM -uint dhd_runtimepm_ms = CUSTOM_DHD_RUNTIME_MS; -#endif /* DHD_PCIE_RUNTIMEPMT */ -#if defined(DHD_DEBUG) -/* Console poll interval */ -uint dhd_console_ms = 0; -module_param(dhd_console_ms, uint, 0644); -#else -uint dhd_console_ms = 0; -#endif /* DHD_DEBUG */ - -uint dhd_slpauto = TRUE; -module_param(dhd_slpauto, uint, 0); - -#ifdef PKT_FILTER_SUPPORT -/* Global Pkt filter enable control */ -uint dhd_pkt_filter_enable = TRUE; -module_param(dhd_pkt_filter_enable, uint, 0); -#endif - -/* Pkt filter init setup */ -uint dhd_pkt_filter_init = 0; -module_param(dhd_pkt_filter_init, uint, 0); - -/* Pkt filter mode control */ -#ifdef GAN_LITE_NAT_KEEPALIVE_FILTER -uint dhd_master_mode = FALSE; -#else -#ifdef PF_SETUP_COMMAND -uint dhd_master_mode = - PKT_FILTER_MODE_FORWARD_ON_MATCH | PKT_FILTER_MODE_PKT_FORWARD_DEFAULT; -#else -uint dhd_master_mode = FALSE; -#endif /* PF_SETUP_COMMAND */ -#endif /* GAN_LITE_NAT_KEEPALIVE_FILTER */ -module_param(dhd_master_mode, uint, 0); - -int dhd_watchdog_prio = 0; -module_param(dhd_watchdog_prio, int, 0); - -/* DPC thread priority */ -int dhd_dpc_prio = CUSTOM_DPC_PRIO_SETTING; -module_param(dhd_dpc_prio, int, 0); - -/* RX frame thread priority */ -int dhd_rxf_prio = CUSTOM_RXF_PRIO_SETTING; -module_param(dhd_rxf_prio, int, 0); - -#if !defined(BCMDBUS) -extern int dhd_dongle_ramsize; -module_param(dhd_dongle_ramsize, int, 0); -#endif /* !BCMDBUS */ - -#ifdef WL_CFG80211 -int passive_channel_skip = 0; -module_param(passive_channel_skip, int, (S_IRUSR|S_IWUSR)); -#endif /* WL_CFG80211 */ - -/* Keep track of number of instances */ -static int dhd_found = 0; -static int instance_base = 0; /* Starting instance number */ -module_param(instance_base, int, 0644); - -#if defined(DHD_LB_RXP) && defined(PCIE_FULL_DONGLE) -static int dhd_napi_weight = 32; -module_param(dhd_napi_weight, int, 0644); -#endif /* DHD_LB_RXP && PCIE_FULL_DONGLE */ - -#ifdef PCIE_FULL_DONGLE -extern int h2d_max_txpost; -module_param(h2d_max_txpost, int, 0644); -#endif /* PCIE_FULL_DONGLE */ - -#ifdef SDIO_TRAITS_STATS -extern uint sdio_traits_stats; -module_param(sdio_traits_stats, uint, 0644); -#endif /* SDIO_TRAITS_STATS */ - -#ifdef DHD_DHCP_DUMP -struct bootp_fmt { - struct iphdr ip_header; - struct udphdr udp_header; - uint8 op; - uint8 htype; - uint8 hlen; - uint8 hops; - uint32 transaction_id; - uint16 secs; - uint16 flags; - uint32 client_ip; - uint32 assigned_ip; - uint32 server_ip; - uint32 relay_ip; - uint8 hw_address[16]; - uint8 server_name[64]; - uint8 file_name[128]; - uint8 options[312]; -}; - -static const uint8 bootp_magic_cookie[4] = { 99, 130, 83, 99 }; -static const char dhcp_ops[][10] = { - "NA", "REQUEST", "REPLY" -}; -static const char dhcp_types[][10] = { - "NA", "DISCOVER", "OFFER", "REQUEST", "DECLINE", "ACK", "NAK", "RELEASE", "INFORM" -}; -static void dhd_dhcp_dump(char *ifname, uint8 *pktdata, bool tx); -#endif /* DHD_DHCP_DUMP */ - -#ifdef DHD_ICMP_DUMP -#include <net/icmp.h> -static void dhd_icmp_dump(char *ifname, uint8 *pktdata, bool tx); -#endif /* DHD_ICMP_DUMP */ - -/* Functions to manage sysfs interface for dhd */ -static int dhd_sysfs_init(struct kobject *kobj); -static void dhd_sysfs_exit(struct kobject *kobj); -struct kobject dhd_sysfs_kobj; - -enum dhd_driver_state { - DHD_DRIVER_STATE_DOWN, - DHD_DRIVER_STATE_WARM_PARTIAL, - DHD_DRIVER_STATE_WARM, - DHD_DRIVER_STATE_COMPLETE, - DHD_DRIVER_STATE_ISOLATED, - DHD_DRIVER_STATE_PENDING_WAKE, - DHD_DRIVER_STATE_HANGED, - DHD_DRIVER_STATE_BUS, -}; - -static int dhd_module_init_work(void); -static void dhd_module_exit_work(void); -static struct mutex dhd_drv_action_lock; -static atomic_t dhd_drv_state = ATOMIC_INIT(DHD_DRIVER_STATE_DOWN); -static atomic_t dhd_hang_state = ATOMIC_INIT(DHD_STATUS_RECOVERED); -static char *get_dhd_drv_state_str(int state); -int dhd_get_driver_state(void); -bool dhd_driver_in_hang_state(void); -static void dhd_change_driver_state(int new_state); -extern int dhdsdio_padsiso_enable(dhd_pub_t *dhdp, bool enable); -static struct ether_addr g_dev_addr = {{0, 0, 0, 0, 0, 0}}; -wl_country_t g_last_cspec = {{0}, 0, {0}}; -#ifdef RELOAD_WIFI -static uint32 fw_reload_new_backoff = 0; -#endif /* RELOAD_WIFI */ - -#ifdef SHOW_LOGTRACE -#if defined(CUSTOMER_HW4_DEBUG) -static char *logstrs_path = PLATFORM_PATH"logstrs.bin"; -static char *st_str_file_path = PLATFORM_PATH"rtecdc.bin"; -static char *map_file_path = PLATFORM_PATH"rtecdc.map"; -static char *rom_st_str_file_path = PLATFORM_PATH"roml.bin"; -static char *rom_map_file_path = PLATFORM_PATH"roml.map"; -#elif defined(CUSTOMER_HW2) -static char *logstrs_path = "/data/misc/wifi/logstrs.bin"; -static char *st_str_file_path = "/data/misc/wifi/rtecdc.bin"; -static char *map_file_path = "/data/misc/wifi/rtecdc.map"; -static char *rom_st_str_file_path = "/data/misc/wifi/roml.bin"; -static char *rom_map_file_path = "/data/misc/wifi/roml.map"; -#else -static char *logstrs_path = "/installmedia/logstrs.bin"; -static char *st_str_file_path = "/installmedia/rtecdc.bin"; -static char *map_file_path = "/installmedia/rtecdc.map"; -static char *rom_st_str_file_path = "/installmedia/roml.bin"; -static char *rom_map_file_path = "/installmedia/roml.map"; -#endif /* CUSTOMER_HW4_DEBUG || CUSTOMER_HW2 */ -static char *ram_file_str = "rtecdc"; -static char *rom_file_str = "roml"; - -module_param(logstrs_path, charp, S_IRUGO); -module_param(st_str_file_path, charp, S_IRUGO); -module_param(map_file_path, charp, S_IRUGO); -module_param(rom_st_str_file_path, charp, S_IRUGO); -module_param(rom_map_file_path, charp, S_IRUGO); - -static int dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp); -static int dhd_read_map(osl_t *osh, char *fname, uint32 *ramstart, uint32 *rodata_start, - uint32 *rodata_end); -static int dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, - char *map_file); -#endif /* SHOW_LOGTRACE */ -static void dhd_postinit_ioctls(dhd_pub_t *dhd, struct net_device *dev); - -#if defined(DHD_LB) - -static void -dhd_lb_set_default_cpus(dhd_info_t *dhd) -{ - /* Default CPU allocation for the jobs */ - atomic_set(&dhd->rx_napi_cpu, 1); - atomic_set(&dhd->rx_compl_cpu, 2); - atomic_set(&dhd->tx_compl_cpu, 2); - atomic_set(&dhd->tx_cpu, 2); - atomic_set(&dhd->net_tx_cpu, 0); -} - -static void -dhd_cpumasks_deinit(dhd_info_t *dhd) -{ - free_cpumask_var(dhd->cpumask_curr_avail); - free_cpumask_var(dhd->cpumask_primary); - free_cpumask_var(dhd->cpumask_primary_new); - free_cpumask_var(dhd->cpumask_secondary); - free_cpumask_var(dhd->cpumask_secondary_new); -} - -static int -dhd_cpumasks_init(dhd_info_t *dhd) -{ - int id; - uint32 cpus, num_cpus = num_possible_cpus(); - int ret = 0; - - DHD_ERROR(("%s CPU masks primary(big)=0x%x secondary(little)=0x%x\n", __FUNCTION__, - DHD_LB_PRIMARY_CPUS, DHD_LB_SECONDARY_CPUS)); - - if (!alloc_cpumask_var(&dhd->cpumask_curr_avail, GFP_KERNEL) || - !alloc_cpumask_var(&dhd->cpumask_primary, GFP_KERNEL) || - !alloc_cpumask_var(&dhd->cpumask_primary_new, GFP_KERNEL) || - !alloc_cpumask_var(&dhd->cpumask_secondary, GFP_KERNEL) || - !alloc_cpumask_var(&dhd->cpumask_secondary_new, GFP_KERNEL)) { - DHD_ERROR(("%s Failed to init cpumasks\n", __FUNCTION__)); - ret = -ENOMEM; - goto fail; - } - - cpumask_copy(dhd->cpumask_curr_avail, cpu_online_mask); - cpumask_clear(dhd->cpumask_primary); - cpumask_clear(dhd->cpumask_secondary); - - if (num_cpus > 32) { - DHD_ERROR(("%s max cpus must be 32, %d too big\n", __FUNCTION__, num_cpus)); - ASSERT(0); - } - - cpus = DHD_LB_PRIMARY_CPUS; - for (id = 0; id < num_cpus; id++) { - if (isset(&cpus, id)) - cpumask_set_cpu(id, dhd->cpumask_primary); - } - - cpus = DHD_LB_SECONDARY_CPUS; - for (id = 0; id < num_cpus; id++) { - if (isset(&cpus, id)) - cpumask_set_cpu(id, dhd->cpumask_secondary); - } - - return ret; -fail: - dhd_cpumasks_deinit(dhd); - return ret; -} - -/* - * The CPU Candidacy Algorithm - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * The available CPUs for selection are divided into two groups - * Primary Set - A CPU mask that carries the First Choice CPUs - * Secondary Set - A CPU mask that carries the Second Choice CPUs. - * - * There are two types of Job, that needs to be assigned to - * the CPUs, from one of the above mentioned CPU group. The Jobs are - * 1) Rx Packet Processing - napi_cpu - * 2) Completion Processiong (Tx, RX) - compl_cpu - * - * To begin with both napi_cpu and compl_cpu are on CPU0. Whenever a CPU goes - * on-line/off-line the CPU candidacy algorithm is triggerd. The candidacy - * algo tries to pickup the first available non boot CPU (CPU0) for napi_cpu. - * If there are more processors free, it assigns one to compl_cpu. - * It also tries to ensure that both napi_cpu and compl_cpu are not on the same - * CPU, as much as possible. - * - * By design, both Tx and Rx completion jobs are run on the same CPU core, as it - * would allow Tx completion skb's to be released into a local free pool from - * which the rx buffer posts could have been serviced. it is important to note - * that a Tx packet may not have a large enough buffer for rx posting. - */ -void dhd_select_cpu_candidacy(dhd_info_t *dhd) -{ - uint32 primary_available_cpus; /* count of primary available cpus */ - uint32 secondary_available_cpus; /* count of secondary available cpus */ - uint32 napi_cpu = 0; /* cpu selected for napi rx processing */ - uint32 compl_cpu = 0; /* cpu selected for completion jobs */ - uint32 tx_cpu = 0; /* cpu selected for tx processing job */ - - cpumask_clear(dhd->cpumask_primary_new); - cpumask_clear(dhd->cpumask_secondary_new); - - /* - * Now select from the primary mask. Even if a Job is - * already running on a CPU in secondary group, we still move - * to primary CPU. So no conditional checks. - */ - cpumask_and(dhd->cpumask_primary_new, dhd->cpumask_primary, - dhd->cpumask_curr_avail); - - cpumask_and(dhd->cpumask_secondary_new, dhd->cpumask_secondary, - dhd->cpumask_curr_avail); - - primary_available_cpus = cpumask_weight(dhd->cpumask_primary_new); - - if (primary_available_cpus > 0) { - napi_cpu = cpumask_first(dhd->cpumask_primary_new); - - /* If no further CPU is available, - * cpumask_next returns >= nr_cpu_ids - */ - tx_cpu = cpumask_next(napi_cpu, dhd->cpumask_primary_new); - if (tx_cpu >= nr_cpu_ids) - tx_cpu = 0; - - /* In case there are no more CPUs, do completions & Tx in same CPU */ - compl_cpu = cpumask_next(tx_cpu, dhd->cpumask_primary_new); - if (compl_cpu >= nr_cpu_ids) - compl_cpu = tx_cpu; - } - - DHD_INFO(("%s After primary CPU check napi_cpu %d compl_cpu %d tx_cpu %d\n", - __FUNCTION__, napi_cpu, compl_cpu, tx_cpu)); - - /* -- Now check for the CPUs from the secondary mask -- */ - secondary_available_cpus = cpumask_weight(dhd->cpumask_secondary_new); - - DHD_INFO(("%s Available secondary cpus %d nr_cpu_ids %d\n", - __FUNCTION__, secondary_available_cpus, nr_cpu_ids)); - - if (secondary_available_cpus > 0) { - /* At this point if napi_cpu is unassigned it means no CPU - * is online from Primary Group - */ - if (napi_cpu == 0) { - napi_cpu = cpumask_first(dhd->cpumask_secondary_new); - tx_cpu = cpumask_next(napi_cpu, dhd->cpumask_secondary_new); - compl_cpu = cpumask_next(tx_cpu, dhd->cpumask_secondary_new); - } else if (tx_cpu == 0) { - tx_cpu = cpumask_first(dhd->cpumask_secondary_new); - compl_cpu = cpumask_next(tx_cpu, dhd->cpumask_secondary_new); - } else if (compl_cpu == 0) { - compl_cpu = cpumask_first(dhd->cpumask_secondary_new); - } - - /* If no CPU was available for tx processing, choose CPU 0 */ - if (tx_cpu >= nr_cpu_ids) - tx_cpu = 0; - - /* If no CPU was available for completion, choose CPU 0 */ - if (compl_cpu >= nr_cpu_ids) - compl_cpu = 0; - } - if ((primary_available_cpus == 0) && - (secondary_available_cpus == 0)) { - /* No CPUs available from primary or secondary mask */ - napi_cpu = 1; - compl_cpu = 0; - tx_cpu = 2; - } - - DHD_INFO(("%s After secondary CPU check napi_cpu %d compl_cpu %d tx_cpu %d\n", - __FUNCTION__, napi_cpu, compl_cpu, tx_cpu)); - - ASSERT(napi_cpu < nr_cpu_ids); - ASSERT(compl_cpu < nr_cpu_ids); - ASSERT(tx_cpu < nr_cpu_ids); - - atomic_set(&dhd->rx_napi_cpu, napi_cpu); - atomic_set(&dhd->tx_compl_cpu, compl_cpu); - atomic_set(&dhd->rx_compl_cpu, compl_cpu); - atomic_set(&dhd->tx_cpu, tx_cpu); - - return; -} - -/* - * Function to handle CPU Hotplug notifications. - * One of the task it does is to trigger the CPU Candidacy algorithm - * for load balancing. - */ -int -dhd_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) -{ - unsigned long int cpu = (unsigned long int)hcpu; - -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - dhd_info_t *dhd = container_of(nfb, dhd_info_t, cpu_notifier); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - - if (!dhd || !(dhd->dhd_state & DHD_ATTACH_STATE_LB_ATTACH_DONE)) { - DHD_INFO(("%s(): LB data is not initialized yet.\n", - __FUNCTION__)); - return NOTIFY_BAD; - } - - switch (action) - { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - DHD_LB_STATS_INCR(dhd->cpu_online_cnt[cpu]); - cpumask_set_cpu(cpu, dhd->cpumask_curr_avail); - dhd_select_cpu_candidacy(dhd); - break; - - case CPU_DOWN_PREPARE: - case CPU_DOWN_PREPARE_FROZEN: - DHD_LB_STATS_INCR(dhd->cpu_offline_cnt[cpu]); - cpumask_clear_cpu(cpu, dhd->cpumask_curr_avail); - dhd_select_cpu_candidacy(dhd); - break; - default: - break; - } - - return NOTIFY_OK; -} - -#if defined(DHD_LB_STATS) -void dhd_lb_stats_init(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - int i, j, num_cpus = num_possible_cpus(); - int alloc_size = sizeof(uint32) * num_cpus; - - if (dhdp == NULL) { - DHD_ERROR(("%s(): Invalid argument dhd pubb pointer is NULL \n", - __FUNCTION__)); - return; - } - - dhd = dhdp->info; - if (dhd == NULL) { - DHD_ERROR(("%s(): DHD pointer is NULL \n", __FUNCTION__)); - return; - } - - DHD_LB_STATS_CLR(dhd->dhd_dpc_cnt); - DHD_LB_STATS_CLR(dhd->napi_sched_cnt); - - dhd->napi_percpu_run_cnt = (uint32 *)MALLOC(dhdp->osh, alloc_size); - if (!dhd->napi_percpu_run_cnt) { - DHD_ERROR(("%s(): napi_percpu_run_cnt malloc failed \n", - __FUNCTION__)); - return; - } - for (i = 0; i < num_cpus; i++) - DHD_LB_STATS_CLR(dhd->napi_percpu_run_cnt[i]); - - DHD_LB_STATS_CLR(dhd->rxc_sched_cnt); - - dhd->rxc_percpu_run_cnt = (uint32 *)MALLOC(dhdp->osh, alloc_size); - if (!dhd->rxc_percpu_run_cnt) { - DHD_ERROR(("%s(): rxc_percpu_run_cnt malloc failed \n", - __FUNCTION__)); - return; - } - for (i = 0; i < num_cpus; i++) - DHD_LB_STATS_CLR(dhd->rxc_percpu_run_cnt[i]); - - DHD_LB_STATS_CLR(dhd->txc_sched_cnt); - - dhd->txc_percpu_run_cnt = (uint32 *)MALLOC(dhdp->osh, alloc_size); - if (!dhd->txc_percpu_run_cnt) { - DHD_ERROR(("%s(): txc_percpu_run_cnt malloc failed \n", - __FUNCTION__)); - return; - } - for (i = 0; i < num_cpus; i++) - DHD_LB_STATS_CLR(dhd->txc_percpu_run_cnt[i]); - - dhd->cpu_online_cnt = (uint32 *)MALLOC(dhdp->osh, alloc_size); - if (!dhd->cpu_online_cnt) { - DHD_ERROR(("%s(): cpu_online_cnt malloc failed \n", - __FUNCTION__)); - return; - } - for (i = 0; i < num_cpus; i++) - DHD_LB_STATS_CLR(dhd->cpu_online_cnt[i]); - - dhd->cpu_offline_cnt = (uint32 *)MALLOC(dhdp->osh, alloc_size); - if (!dhd->cpu_offline_cnt) { - DHD_ERROR(("%s(): cpu_offline_cnt malloc failed \n", - __FUNCTION__)); - return; - } - for (i = 0; i < num_cpus; i++) - DHD_LB_STATS_CLR(dhd->cpu_offline_cnt[i]); - - dhd->txp_percpu_run_cnt = (uint32 *)MALLOC(dhdp->osh, alloc_size); - if (!dhd->txp_percpu_run_cnt) { - DHD_ERROR(("%s(): txp_percpu_run_cnt malloc failed \n", - __FUNCTION__)); - return; - } - for (i = 0; i < num_cpus; i++) - DHD_LB_STATS_CLR(dhd->txp_percpu_run_cnt[i]); - - dhd->tx_start_percpu_run_cnt = (uint32 *)MALLOC(dhdp->osh, alloc_size); - if (!dhd->tx_start_percpu_run_cnt) { - DHD_ERROR(("%s(): tx_start_percpu_run_cnt malloc failed \n", - __FUNCTION__)); - return; - } - for (i = 0; i < num_cpus; i++) - DHD_LB_STATS_CLR(dhd->tx_start_percpu_run_cnt[i]); - - for (j = 0; j < HIST_BIN_SIZE; j++) { - dhd->napi_rx_hist[j] = (uint32 *)MALLOC(dhdp->osh, alloc_size); - if (!dhd->napi_rx_hist[j]) { - DHD_ERROR(("%s(): dhd->napi_rx_hist[%d] malloc failed \n", - __FUNCTION__, j)); - return; - } - for (i = 0; i < num_cpus; i++) { - DHD_LB_STATS_CLR(dhd->napi_rx_hist[j][i]); - } - } -#ifdef DHD_LB_TXC - for (j = 0; j < HIST_BIN_SIZE; j++) { - dhd->txc_hist[j] = (uint32 *)MALLOC(dhdp->osh, alloc_size); - if (!dhd->txc_hist[j]) { - DHD_ERROR(("%s(): dhd->txc_hist[%d] malloc failed \n", - __FUNCTION__, j)); - return; - } - for (i = 0; i < num_cpus; i++) { - DHD_LB_STATS_CLR(dhd->txc_hist[j][i]); - } - } -#endif /* DHD_LB_TXC */ -#ifdef DHD_LB_RXC - for (j = 0; j < HIST_BIN_SIZE; j++) { - dhd->rxc_hist[j] = (uint32 *)MALLOC(dhdp->osh, alloc_size); - if (!dhd->rxc_hist[j]) { - DHD_ERROR(("%s(): dhd->rxc_hist[%d] malloc failed \n", - __FUNCTION__, j)); - return; - } - for (i = 0; i < num_cpus; i++) { - DHD_LB_STATS_CLR(dhd->rxc_hist[j][i]); - } - } -#endif /* DHD_LB_RXC */ - return; -} - -void dhd_lb_stats_deinit(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - int j, num_cpus = num_possible_cpus(); - int alloc_size = sizeof(uint32) * num_cpus; - - if (dhdp == NULL) { - DHD_ERROR(("%s(): Invalid argument dhd pubb pointer is NULL \n", - __FUNCTION__)); - return; - } - - dhd = dhdp->info; - if (dhd == NULL) { - DHD_ERROR(("%s(): DHD pointer is NULL \n", __FUNCTION__)); - return; - } - - if (dhd->napi_percpu_run_cnt) { - MFREE(dhdp->osh, dhd->napi_percpu_run_cnt, alloc_size); - dhd->napi_percpu_run_cnt = NULL; - } - if (dhd->rxc_percpu_run_cnt) { - MFREE(dhdp->osh, dhd->rxc_percpu_run_cnt, alloc_size); - dhd->rxc_percpu_run_cnt = NULL; - } - if (dhd->txc_percpu_run_cnt) { - MFREE(dhdp->osh, dhd->txc_percpu_run_cnt, alloc_size); - dhd->txc_percpu_run_cnt = NULL; - } - if (dhd->cpu_online_cnt) { - MFREE(dhdp->osh, dhd->cpu_online_cnt, alloc_size); - dhd->cpu_online_cnt = NULL; - } - if (dhd->cpu_offline_cnt) { - MFREE(dhdp->osh, dhd->cpu_offline_cnt, alloc_size); - dhd->cpu_offline_cnt = NULL; - } - - if (dhd->txp_percpu_run_cnt) { - MFREE(dhdp->osh, dhd->txp_percpu_run_cnt, alloc_size); - dhd->txp_percpu_run_cnt = NULL; - } - if (dhd->tx_start_percpu_run_cnt) { - MFREE(dhdp->osh, dhd->tx_start_percpu_run_cnt, alloc_size); - dhd->tx_start_percpu_run_cnt = NULL; - } - - for (j = 0; j < HIST_BIN_SIZE; j++) { - if (dhd->napi_rx_hist[j]) { - MFREE(dhdp->osh, dhd->napi_rx_hist[j], alloc_size); - dhd->napi_rx_hist[j] = NULL; - } -#ifdef DHD_LB_TXC - if (dhd->txc_hist[j]) { - MFREE(dhdp->osh, dhd->txc_hist[j], alloc_size); - dhd->txc_hist[j] = NULL; - } -#endif /* DHD_LB_TXC */ -#ifdef DHD_LB_RXC - if (dhd->rxc_hist[j]) { - MFREE(dhdp->osh, dhd->rxc_hist[j], alloc_size); - dhd->rxc_hist[j] = NULL; - } -#endif /* DHD_LB_RXC */ - } - - return; -} - -static void dhd_lb_stats_dump_histo( - struct bcmstrbuf *strbuf, uint32 **hist) -{ - int i, j; - uint32 *per_cpu_total; - uint32 total = 0; - uint32 num_cpus = num_possible_cpus(); - - per_cpu_total = (uint32 *)kmalloc(sizeof(uint32) * num_cpus, GFP_ATOMIC); - if (!per_cpu_total) { - DHD_ERROR(("%s(): dhd->per_cpu_total malloc failed \n", __FUNCTION__)); - return; - } - bzero(per_cpu_total, sizeof(uint32) * num_cpus); - - bcm_bprintf(strbuf, "CPU: \t\t"); - for (i = 0; i < num_cpus; i++) - bcm_bprintf(strbuf, "%d\t", i); - bcm_bprintf(strbuf, "\nBin\n"); - - for (i = 0; i < HIST_BIN_SIZE; i++) { - bcm_bprintf(strbuf, "%d:\t\t", 1<<i); - for (j = 0; j < num_cpus; j++) { - bcm_bprintf(strbuf, "%d\t", hist[i][j]); - } - bcm_bprintf(strbuf, "\n"); - } - bcm_bprintf(strbuf, "Per CPU Total \t"); - total = 0; - for (i = 0; i < num_cpus; i++) { - for (j = 0; j < HIST_BIN_SIZE; j++) { - per_cpu_total[i] += (hist[j][i] * (1<<j)); - } - bcm_bprintf(strbuf, "%d\t", per_cpu_total[i]); - total += per_cpu_total[i]; - } - bcm_bprintf(strbuf, "\nTotal\t\t%d \n", total); - - kfree(per_cpu_total); - return; -} - -static inline void dhd_lb_stats_dump_cpu_array(struct bcmstrbuf *strbuf, uint32 *p) -{ - int i, num_cpus = num_possible_cpus(); - - bcm_bprintf(strbuf, "CPU: \t"); - for (i = 0; i < num_cpus; i++) - bcm_bprintf(strbuf, "%d\t", i); - bcm_bprintf(strbuf, "\n"); - - bcm_bprintf(strbuf, "Val: \t"); - for (i = 0; i < num_cpus; i++) - bcm_bprintf(strbuf, "%u\t", *(p+i)); - bcm_bprintf(strbuf, "\n"); - return; -} - -void dhd_lb_stats_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -{ - dhd_info_t *dhd; - - if (dhdp == NULL || strbuf == NULL) { - DHD_ERROR(("%s(): Invalid argument dhdp %p strbuf %p \n", - __FUNCTION__, dhdp, strbuf)); - return; - } - - dhd = dhdp->info; - if (dhd == NULL) { - DHD_ERROR(("%s(): DHD pointer is NULL \n", __FUNCTION__)); - return; - } - - bcm_bprintf(strbuf, "\ncpu_online_cnt:\n"); - dhd_lb_stats_dump_cpu_array(strbuf, dhd->cpu_online_cnt); - - bcm_bprintf(strbuf, "\ncpu_offline_cnt:\n"); - dhd_lb_stats_dump_cpu_array(strbuf, dhd->cpu_offline_cnt); - - bcm_bprintf(strbuf, "\nsched_cnt: dhd_dpc %u napi %u rxc %u txc %u\n", - dhd->dhd_dpc_cnt, dhd->napi_sched_cnt, dhd->rxc_sched_cnt, - dhd->txc_sched_cnt); - -#ifdef DHD_LB_RXP - bcm_bprintf(strbuf, "\nnapi_percpu_run_cnt:\n"); - dhd_lb_stats_dump_cpu_array(strbuf, dhd->napi_percpu_run_cnt); - bcm_bprintf(strbuf, "\nNAPI Packets Received Histogram:\n"); - dhd_lb_stats_dump_histo(strbuf, dhd->napi_rx_hist); -#endif /* DHD_LB_RXP */ - -#ifdef DHD_LB_RXC - bcm_bprintf(strbuf, "\nrxc_percpu_run_cnt:\n"); - dhd_lb_stats_dump_cpu_array(strbuf, dhd->rxc_percpu_run_cnt); - bcm_bprintf(strbuf, "\nRX Completions (Buffer Post) Histogram:\n"); - dhd_lb_stats_dump_histo(strbuf, dhd->rxc_hist); -#endif /* DHD_LB_RXC */ - -#ifdef DHD_LB_TXC - bcm_bprintf(strbuf, "\ntxc_percpu_run_cnt:\n"); - dhd_lb_stats_dump_cpu_array(strbuf, dhd->txc_percpu_run_cnt); - bcm_bprintf(strbuf, "\nTX Completions (Buffer Free) Histogram:\n"); - dhd_lb_stats_dump_histo(strbuf, dhd->txc_hist); -#endif /* DHD_LB_TXC */ - -#ifdef DHD_LB_TXP - bcm_bprintf(strbuf, "\ntxp_percpu_run_cnt:\n"); - dhd_lb_stats_dump_cpu_array(strbuf, dhd->txp_percpu_run_cnt); - - bcm_bprintf(strbuf, "\ntx_start_percpu_run_cnt:\n"); - dhd_lb_stats_dump_cpu_array(strbuf, dhd->tx_start_percpu_run_cnt); -#endif /* DHD_LB_TXP */ - - bcm_bprintf(strbuf, "\nCPU masks primary(big)=0x%x secondary(little)=0x%x\n", - DHD_LB_PRIMARY_CPUS, DHD_LB_SECONDARY_CPUS); - - bcm_bprintf(strbuf, "napi_cpu %x tx_cpu %x\n", - atomic_read(&dhd->rx_napi_cpu), atomic_read(&dhd->tx_cpu)); - -} - -/* Given a number 'n' returns 'm' that is next larger power of 2 after n */ -static inline uint32 next_larger_power2(uint32 num) -{ - num--; - num |= (num >> 1); - num |= (num >> 2); - num |= (num >> 4); - num |= (num >> 8); - num |= (num >> 16); - - return (num + 1); -} - -static void dhd_lb_stats_update_histo(uint32 **bin, uint32 count, uint32 cpu) -{ - uint32 bin_power; - uint32 *p; - bin_power = next_larger_power2(count); - - switch (bin_power) { - case 1: p = bin[0] + cpu; break; - case 2: p = bin[1] + cpu; break; - case 4: p = bin[2] + cpu; break; - case 8: p = bin[3] + cpu; break; - case 16: p = bin[4] + cpu; break; - case 32: p = bin[5] + cpu; break; - case 64: p = bin[6] + cpu; break; - case 128: p = bin[7] + cpu; break; - default : p = bin[8] + cpu; break; - } - - *p = *p + 1; - return; -} - -extern void dhd_lb_stats_update_napi_histo(dhd_pub_t *dhdp, uint32 count) -{ - int cpu; - dhd_info_t *dhd = dhdp->info; - - cpu = get_cpu(); - put_cpu(); - dhd_lb_stats_update_histo(dhd->napi_rx_hist, count, cpu); - - return; -} - -extern void dhd_lb_stats_update_txc_histo(dhd_pub_t *dhdp, uint32 count) -{ - int cpu; - dhd_info_t *dhd = dhdp->info; - - cpu = get_cpu(); - put_cpu(); - dhd_lb_stats_update_histo(dhd->txc_hist, count, cpu); - - return; -} - -extern void dhd_lb_stats_update_rxc_histo(dhd_pub_t *dhdp, uint32 count) -{ - int cpu; - dhd_info_t *dhd = dhdp->info; - - cpu = get_cpu(); - put_cpu(); - dhd_lb_stats_update_histo(dhd->rxc_hist, count, cpu); - - return; -} - -extern void dhd_lb_stats_txc_percpu_cnt_incr(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = dhdp->info; - DHD_LB_STATS_PERCPU_ARR_INCR(dhd->txc_percpu_run_cnt); -} - -extern void dhd_lb_stats_rxc_percpu_cnt_incr(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = dhdp->info; - DHD_LB_STATS_PERCPU_ARR_INCR(dhd->rxc_percpu_run_cnt); -} -#endif /* DHD_LB_STATS */ - -#endif /* DHD_LB */ - -#if defined(DISABLE_FRAMEBURST_VSDB) && defined(USE_WFA_CERT_CONF) -int g_frameburst = 1; -#endif /* DISABLE_FRAMEBURST_VSDB && USE_WFA_CERT_CONF */ - -static int dhd_get_pend_8021x_cnt(dhd_info_t *dhd); - -/* DHD Perimiter lock only used in router with bypass forwarding. */ -#define DHD_PERIM_RADIO_INIT() do { /* noop */ } while (0) -#define DHD_PERIM_LOCK_TRY(unit, flag) do { /* noop */ } while (0) -#define DHD_PERIM_UNLOCK_TRY(unit, flag) do { /* noop */ } while (0) - -#ifdef PCIE_FULL_DONGLE -#if defined(BCM_GMAC3) -#define DHD_IF_STA_LIST_LOCK_INIT(ifp) do { /* noop */ } while (0) -#define DHD_IF_STA_LIST_LOCK(ifp, flags) ({ BCM_REFERENCE(flags); }) -#define DHD_IF_STA_LIST_UNLOCK(ifp, flags) ({ BCM_REFERENCE(flags); }) - -#if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) -#define DHD_IF_WMF_UCFORWARD_LOCK(dhd, ifp, slist) ({ BCM_REFERENCE(slist); &(ifp)->sta_list; }) -#define DHD_IF_WMF_UCFORWARD_UNLOCK(dhd, slist) ({ BCM_REFERENCE(slist); }) -#endif /* DHD_IGMP_UCQUERY || DHD_UCAST_UPNP */ - -#else /* ! BCM_GMAC3 */ -#define DHD_IF_STA_LIST_LOCK_INIT(ifp) spin_lock_init(&(ifp)->sta_list_lock) -#define DHD_IF_STA_LIST_LOCK(ifp, flags) \ - spin_lock_irqsave(&(ifp)->sta_list_lock, (flags)) -#define DHD_IF_STA_LIST_UNLOCK(ifp, flags) \ - spin_unlock_irqrestore(&(ifp)->sta_list_lock, (flags)) - -#if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) -static struct list_head * dhd_sta_list_snapshot(dhd_info_t *dhd, dhd_if_t *ifp, - struct list_head *snapshot_list); -static void dhd_sta_list_snapshot_free(dhd_info_t *dhd, struct list_head *snapshot_list); -#define DHD_IF_WMF_UCFORWARD_LOCK(dhd, ifp, slist) ({ dhd_sta_list_snapshot(dhd, ifp, slist); }) -#define DHD_IF_WMF_UCFORWARD_UNLOCK(dhd, slist) ({ dhd_sta_list_snapshot_free(dhd, slist); }) -#endif /* DHD_IGMP_UCQUERY || DHD_UCAST_UPNP */ - -#endif /* ! BCM_GMAC3 */ -#endif /* PCIE_FULL_DONGLE */ - -/* Control fw roaming */ -uint dhd_roam_disable = 0; - -#ifdef BCMDBGFS -extern void dhd_dbgfs_init(dhd_pub_t *dhdp); -extern void dhd_dbgfs_remove(void); -#endif - - -/* Control radio state */ -uint dhd_radio_up = 1; - -/* Network inteface name */ -char iface_name[IFNAMSIZ] = {'\0'}; -module_param_string(iface_name, iface_name, IFNAMSIZ, 0); - -/* The following are specific to the SDIO dongle */ - -/* IOCTL response timeout */ -int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT; - -/* DS Exit response timeout */ -int ds_exit_timeout_msec = DS_EXIT_TIMEOUT; - -/* Idle timeout for backplane clock */ -int dhd_idletime = DHD_IDLETIME_TICKS; -module_param(dhd_idletime, int, 0); - -/* Use polling */ -uint dhd_poll = FALSE; -module_param(dhd_poll, uint, 0); - -/* Use interrupts */ -uint dhd_intr = TRUE; -module_param(dhd_intr, uint, 0); - -/* SDIO Drive Strength (in milliamps) */ -uint dhd_sdiod_drive_strength = 6; -module_param(dhd_sdiod_drive_strength, uint, 0); - -#ifdef BCMSDIO -/* Tx/Rx bounds */ -extern uint dhd_txbound; -extern uint dhd_rxbound; -module_param(dhd_txbound, uint, 0); -module_param(dhd_rxbound, uint, 0); - -/* Deferred transmits */ -extern uint dhd_deferred_tx; -module_param(dhd_deferred_tx, uint, 0); - -#endif /* BCMSDIO */ - - -#ifdef SDTEST -/* Echo packet generator (pkts/s) */ -uint dhd_pktgen = 0; -module_param(dhd_pktgen, uint, 0); - -/* Echo packet len (0 => sawtooth, max 2040) */ -uint dhd_pktgen_len = 0; -module_param(dhd_pktgen_len, uint, 0); -#endif /* SDTEST */ - - - -#ifndef BCMDBUS -/* Allow delayed firmware download for debug purpose */ -int allow_delay_fwdl = FALSE; -module_param(allow_delay_fwdl, int, 0); -#endif /* !BCMDBUS */ - -#ifdef HAL_API -int dhd_tcpka_sess_active = 0; -module_param(dhd_tcpka_sess_active, int, 0444); -#endif /* HAL_API */ - -int dhd_chip_alive = 0; -module_param(dhd_chip_alive, int, 0); - -void sdio_set_chip_alive(bool chip_alive); - -int dhd_load_mode = DHD_LOAD_MODE_WARM; -module_param(dhd_load_mode, int, 0644); - -static char *load_mode; -module_param(load_mode, charp, 0); - -extern char dhd_version[]; -extern char fw_version[]; -extern char clm_version[]; - -int dhd_net_bus_devreset(struct net_device *dev, uint8 flag); -static void dhd_net_if_lock_local(dhd_info_t *dhd); -static void dhd_net_if_unlock_local(dhd_info_t *dhd); -static void dhd_suspend_lock(dhd_pub_t *dhdp); -static void dhd_suspend_unlock(dhd_pub_t *dhdp); - -#ifdef WLMEDIA_HTSF -void htsf_update(dhd_info_t *dhd, void *data); -tsf_t prev_tsf, cur_tsf; - -uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx); -static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx); -static void dhd_dump_latency(void); -static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf); -static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf); -static void dhd_dump_htsfhisto(histo_t *his, char *s); -#endif /* WLMEDIA_HTSF */ - -/* Monitor interface */ -int dhd_monitor_init(void *dhd_pub); -int dhd_monitor_uninit(void); - - -#if defined(WL_WIRELESS_EXT) -struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); -#endif /* defined(WL_WIRELESS_EXT) */ - -#ifndef BCMDBUS -static void dhd_dpc(ulong data); -#endif /* !BCMDBUS */ -/* forward decl */ -extern int dhd_wait_pend8021x(struct net_device *dev); -void dhd_os_wd_timer_extend(void *bus, bool extend); - -#ifdef TOE -#ifndef BDC -#error TOE requires BDC -#endif /* !BDC */ -static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol); -static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); -#endif /* TOE */ - -static int dhd_wl_host_event(dhd_info_t *dhd, int ifidx, void *pktdata, uint16 pktlen, - wl_event_msg_t *event_ptr, void **data_ptr); - -#if defined(CONFIG_PM_SLEEP) -static int dhd_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) -{ - int ret = NOTIFY_DONE; - bool suspend = FALSE; - -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - dhd_info_t *dhdinfo = (dhd_info_t*)container_of(nfb, struct dhd_info, pm_notifier); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - - BCM_REFERENCE(dhdinfo); - BCM_REFERENCE(suspend); - - switch (action) { - case PM_HIBERNATION_PREPARE: - case PM_SUSPEND_PREPARE: - suspend = TRUE; - break; - - case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: - suspend = FALSE; - break; - } - -#if defined(SUPPORT_P2P_GO_PS) && defined(PROP_TXSTATUS) - if (suspend) { - DHD_OS_WAKE_LOCK_WAIVE(&dhdinfo->pub); - dhd_wlfc_suspend(&dhdinfo->pub); - DHD_OS_WAKE_LOCK_RESTORE(&dhdinfo->pub); - } else { - dhd_wlfc_resume(&dhdinfo->pub); - } -#endif /* defined(SUPPORT_P2P_GO_PS) && defined(PROP_TXSTATUS) */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \ - KERNEL_VERSION(2, 6, 39)) - dhd_mmc_suspend = suspend; - smp_mb(); -#endif - - return ret; -} - -/* to make sure we won't register the same notifier twice, otherwise a loop is likely to be - * created in kernel notifier link list (with 'next' pointing to itself) - */ -static bool dhd_pm_notifier_registered = FALSE; - -extern int register_pm_notifier(struct notifier_block *nb); -extern int unregister_pm_notifier(struct notifier_block *nb); -#endif /* CONFIG_PM_SLEEP */ - -/* Request scheduling of the bus rx frame */ -static void dhd_sched_rxf(dhd_pub_t *dhdp, void *skb); -static void dhd_os_rxflock(dhd_pub_t *pub); -static void dhd_os_rxfunlock(dhd_pub_t *pub); - -/** priv_link is the link between netdev and the dhdif and dhd_info structs. */ -typedef struct dhd_dev_priv { - dhd_info_t * dhd; /* cached pointer to dhd_info in netdevice priv */ - dhd_if_t * ifp; /* cached pointer to dhd_if in netdevice priv */ - int ifidx; /* interface index */ - void * lkup; -} dhd_dev_priv_t; - -#define DHD_DEV_PRIV_SIZE (sizeof(dhd_dev_priv_t)) -#define DHD_DEV_PRIV(dev) ((dhd_dev_priv_t *)DEV_PRIV(dev)) -#define DHD_DEV_INFO(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->dhd) -#define DHD_DEV_IFP(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifp) -#define DHD_DEV_IFIDX(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->ifidx) -#define DHD_DEV_LKUP(dev) (((dhd_dev_priv_t *)DEV_PRIV(dev))->lkup) - -#if defined(DHD_OF_SUPPORT) -extern int dhd_wlan_init(void); -#endif /* defined(DHD_OF_SUPPORT) */ -/** Clear the dhd net_device's private structure. */ -static inline void -dhd_dev_priv_clear(struct net_device * dev) -{ - dhd_dev_priv_t * dev_priv; - ASSERT(dev != (struct net_device *)NULL); - dev_priv = DHD_DEV_PRIV(dev); - dev_priv->dhd = (dhd_info_t *)NULL; - dev_priv->ifp = (dhd_if_t *)NULL; - dev_priv->ifidx = DHD_BAD_IF; - dev_priv->lkup = (void *)NULL; -} - -/** Setup the dhd net_device's private structure. */ -static inline void -dhd_dev_priv_save(struct net_device * dev, dhd_info_t * dhd, dhd_if_t * ifp, - int ifidx) -{ - dhd_dev_priv_t * dev_priv; - ASSERT(dev != (struct net_device *)NULL); - dev_priv = DHD_DEV_PRIV(dev); - dev_priv->dhd = dhd; - dev_priv->ifp = ifp; - dev_priv->ifidx = ifidx; -} - -#ifdef PCIE_FULL_DONGLE - -/** Dummy objects are defined with state representing bad|down. - * Performance gains from reducing branch conditionals, instruction parallelism, - * dual issue, reducing load shadows, avail of larger pipelines. - * Use DHD_XXX_NULL instead of (dhd_xxx_t *)NULL, whenever an object pointer - * is accessed via the dhd_sta_t. - */ - -/* Dummy dhd_info object */ -dhd_info_t dhd_info_null = { -#if defined(BCM_GMAC3) - .fwdh = FWDER_NULL, -#endif - .pub = { - .info = &dhd_info_null, -#ifdef DHDTCPACK_SUPPRESS - .tcpack_sup_mode = TCPACK_SUP_REPLACE, -#endif /* DHDTCPACK_SUPPRESS */ -#if defined(TRAFFIC_MGMT_DWM) - .dhd_tm_dwm_tbl = { .dhd_dwm_enabled = TRUE }, -#endif - .up = FALSE, - .busstate = DHD_BUS_DOWN - } -}; -#define DHD_INFO_NULL (&dhd_info_null) -#define DHD_PUB_NULL (&dhd_info_null.pub) - -/* Dummy netdevice object */ -struct net_device dhd_net_dev_null = { - .reg_state = NETREG_UNREGISTERED -}; -#define DHD_NET_DEV_NULL (&dhd_net_dev_null) - -/* Dummy dhd_if object */ -dhd_if_t dhd_if_null = { -#if defined(BCM_GMAC3) - .fwdh = FWDER_NULL, -#endif -#ifdef WMF - .wmf = { .wmf_enable = TRUE }, -#endif - .info = DHD_INFO_NULL, - .net = DHD_NET_DEV_NULL, - .idx = DHD_BAD_IF -}; -#define DHD_IF_NULL (&dhd_if_null) - -#define DHD_STA_NULL ((dhd_sta_t *)NULL) - -/** Interface STA list management. */ - -/** Fetch the dhd_if object, given the interface index in the dhd. */ -static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx); - -/** Alloc/Free a dhd_sta object from the dhd instances' sta_pool. */ -static void dhd_sta_free(dhd_pub_t *pub, dhd_sta_t *sta); -static dhd_sta_t * dhd_sta_alloc(dhd_pub_t * dhdp); - -/* Delete a dhd_sta or flush all dhd_sta in an interface's sta_list. */ -static void dhd_if_del_sta_list(dhd_if_t * ifp); -static void dhd_if_flush_sta(dhd_if_t * ifp); - -/* Construct/Destruct a sta pool. */ -static int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta); -static void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta); -/* Clear the pool of dhd_sta_t objects for built-in type driver */ -static void dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta); - - -/* Return interface pointer */ -static inline dhd_if_t *dhd_get_ifp(dhd_pub_t *dhdp, uint32 ifidx) -{ - ASSERT(ifidx < DHD_MAX_IFS); - - if (ifidx >= DHD_MAX_IFS) - return NULL; - - return dhdp->info->iflist[ifidx]; -} - -/** Reset a dhd_sta object and free into the dhd pool. */ -static void -dhd_sta_free(dhd_pub_t * dhdp, dhd_sta_t * sta) -{ - int prio; - - ASSERT((sta != DHD_STA_NULL) && (sta->idx != ID16_INVALID)); - - ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL)); - - /* - * Flush and free all packets in all flowring's queues belonging to sta. - * Packets in flow ring will be flushed later. - */ - for (prio = 0; prio < (int)NUMPRIO; prio++) { - uint16 flowid = sta->flowid[prio]; - - if (flowid != FLOWID_INVALID) { - unsigned long flags; - flow_queue_t * queue = dhd_flow_queue(dhdp, flowid); - flow_ring_node_t * flow_ring_node; - -#ifdef DHDTCPACK_SUPPRESS - /* Clean tcp_ack_info_tbl in order to prevent access to flushed pkt, - * when there is a newly coming packet from network stack. - */ - dhd_tcpack_info_tbl_clean(dhdp); -#endif /* DHDTCPACK_SUPPRESS */ - - flow_ring_node = dhd_flow_ring_node(dhdp, flowid); - DHD_FLOWRING_LOCK(flow_ring_node->lock, flags); - flow_ring_node->status = FLOW_RING_STATUS_STA_FREEING; - - if (!DHD_FLOW_QUEUE_EMPTY(queue)) { - void * pkt; - while ((pkt = dhd_flow_queue_dequeue(dhdp, queue)) != NULL) { - PKTFREE(dhdp->osh, pkt, TRUE); - } - } - - DHD_FLOWRING_UNLOCK(flow_ring_node->lock, flags); - ASSERT(DHD_FLOW_QUEUE_EMPTY(queue)); - } - - sta->flowid[prio] = FLOWID_INVALID; - } - - id16_map_free(dhdp->staid_allocator, sta->idx); - DHD_CUMM_CTR_INIT(&sta->cumm_ctr); - sta->ifp = DHD_IF_NULL; /* dummy dhd_if object */ - sta->ifidx = DHD_BAD_IF; - bzero(sta->ea.octet, ETHER_ADDR_LEN); - INIT_LIST_HEAD(&sta->list); - sta->idx = ID16_INVALID; /* implying free */ -} - -/** Allocate a dhd_sta object from the dhd pool. */ -static dhd_sta_t * -dhd_sta_alloc(dhd_pub_t * dhdp) -{ - uint16 idx; - dhd_sta_t * sta; - dhd_sta_pool_t * sta_pool; - - ASSERT((dhdp->staid_allocator != NULL) && (dhdp->sta_pool != NULL)); - - idx = id16_map_alloc(dhdp->staid_allocator); - if (idx == ID16_INVALID) { - DHD_ERROR(("%s: cannot get free staid\n", __FUNCTION__)); - return DHD_STA_NULL; - } - - sta_pool = (dhd_sta_pool_t *)(dhdp->sta_pool); - sta = &sta_pool[idx]; - - ASSERT((sta->idx == ID16_INVALID) && - (sta->ifp == DHD_IF_NULL) && (sta->ifidx == DHD_BAD_IF)); - - DHD_CUMM_CTR_INIT(&sta->cumm_ctr); - - sta->idx = idx; /* implying allocated */ - - return sta; -} - -/** Delete all STAs in an interface's STA list. */ -static void -dhd_if_del_sta_list(dhd_if_t *ifp) -{ - dhd_sta_t *sta, *next; - unsigned long flags; - - DHD_IF_STA_LIST_LOCK(ifp, flags); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - list_for_each_entry_safe(sta, next, &ifp->sta_list, list) { -#if defined(BCM_GMAC3) - if (ifp->fwdh) { - /* Remove sta from WOFA forwarder. */ - fwder_deassoc(ifp->fwdh, (uint16 *)(sta->ea.octet), (uintptr_t)sta); - } -#endif /* BCM_GMAC3 */ - list_del(&sta->list); - dhd_sta_free(&ifp->info->pub, sta); - } -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - DHD_IF_STA_LIST_UNLOCK(ifp, flags); - - return; -} - -/** Router/GMAC3: Flush all station entries in the forwarder's WOFA database. */ -static void -dhd_if_flush_sta(dhd_if_t * ifp) -{ -#if defined(BCM_GMAC3) - - if (ifp && (ifp->fwdh != FWDER_NULL)) { - dhd_sta_t *sta, *next; - unsigned long flags; - - DHD_IF_STA_LIST_LOCK(ifp, flags); - - list_for_each_entry_safe(sta, next, &ifp->sta_list, list) { - /* Remove any sta entry from WOFA forwarder. */ - fwder_flush(ifp->fwdh, (uintptr_t)sta); - } - - DHD_IF_STA_LIST_UNLOCK(ifp, flags); - } -#endif /* BCM_GMAC3 */ -} - -/** Construct a pool of dhd_sta_t objects to be used by interfaces. */ -static int -dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta) -{ - int idx, prio, sta_pool_memsz; - dhd_sta_t * sta; - dhd_sta_pool_t * sta_pool; - void * staid_allocator; - - ASSERT(dhdp != (dhd_pub_t *)NULL); - ASSERT((dhdp->staid_allocator == NULL) && (dhdp->sta_pool == NULL)); - - /* dhd_sta objects per radio are managed in a table. id#0 reserved. */ - staid_allocator = id16_map_init(dhdp->osh, max_sta, 1); - if (staid_allocator == NULL) { - DHD_ERROR(("%s: sta id allocator init failure\n", __FUNCTION__)); - return BCME_ERROR; - } - - /* Pre allocate a pool of dhd_sta objects (one extra). */ - sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); /* skip idx 0 */ - sta_pool = (dhd_sta_pool_t *)MALLOC(dhdp->osh, sta_pool_memsz); - if (sta_pool == NULL) { - DHD_ERROR(("%s: sta table alloc failure\n", __FUNCTION__)); - id16_map_fini(dhdp->osh, staid_allocator); - return BCME_ERROR; - } - - dhdp->sta_pool = sta_pool; - dhdp->staid_allocator = staid_allocator; - - /* Initialize all sta(s) for the pre-allocated free pool. */ - bzero((uchar *)sta_pool, sta_pool_memsz); - for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */ - sta = &sta_pool[idx]; - sta->idx = id16_map_alloc(staid_allocator); - ASSERT(sta->idx <= max_sta); - } - /* Now place them into the pre-allocated free pool. */ - for (idx = 1; idx <= max_sta; idx++) { - sta = &sta_pool[idx]; - for (prio = 0; prio < (int)NUMPRIO; prio++) { - sta->flowid[prio] = FLOWID_INVALID; /* Flow rings do not exist */ - } - dhd_sta_free(dhdp, sta); - } - - return BCME_OK; -} - -/** Destruct the pool of dhd_sta_t objects. - * Caller must ensure that no STA objects are currently associated with an if. - */ -static void -dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta) -{ - dhd_sta_pool_t * sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool; - - if (sta_pool) { - int idx; - int sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); - for (idx = 1; idx <= max_sta; idx++) { - ASSERT(sta_pool[idx].ifp == DHD_IF_NULL); - ASSERT(sta_pool[idx].idx == ID16_INVALID); - } - MFREE(dhdp->osh, dhdp->sta_pool, sta_pool_memsz); - dhdp->sta_pool = NULL; - } - - id16_map_fini(dhdp->osh, dhdp->staid_allocator); - dhdp->staid_allocator = NULL; -} - -/* Clear the pool of dhd_sta_t objects for built-in type driver */ -static void -dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta) -{ - int idx, prio, sta_pool_memsz; - dhd_sta_t * sta; - dhd_sta_pool_t * sta_pool; - void *staid_allocator; - - if (!dhdp) { - DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); - return; - } - - sta_pool = (dhd_sta_pool_t *)dhdp->sta_pool; - staid_allocator = dhdp->staid_allocator; - - if (!sta_pool) { - DHD_ERROR(("%s: sta_pool is NULL\n", __FUNCTION__)); - return; - } - - if (!staid_allocator) { - DHD_ERROR(("%s: staid_allocator is NULL\n", __FUNCTION__)); - return; - } - - /* clear free pool */ - sta_pool_memsz = ((max_sta + 1) * sizeof(dhd_sta_t)); - bzero((uchar *)sta_pool, sta_pool_memsz); - - /* dhd_sta objects per radio are managed in a table. id#0 reserved. */ - id16_map_clear(staid_allocator, max_sta, 1); - - /* Initialize all sta(s) for the pre-allocated free pool. */ - for (idx = max_sta; idx >= 1; idx--) { /* skip sta_pool[0] */ - sta = &sta_pool[idx]; - sta->idx = id16_map_alloc(staid_allocator); - ASSERT(sta->idx <= max_sta); - } - /* Now place them into the pre-allocated free pool. */ - for (idx = 1; idx <= max_sta; idx++) { - sta = &sta_pool[idx]; - for (prio = 0; prio < (int)NUMPRIO; prio++) { - sta->flowid[prio] = FLOWID_INVALID; /* Flow rings do not exist */ - } - dhd_sta_free(dhdp, sta); - } -} - -/** Find STA with MAC address ea in an interface's STA list. */ -dhd_sta_t * -dhd_find_sta(void *pub, int ifidx, void *ea) -{ - dhd_sta_t *sta; - dhd_if_t *ifp; - unsigned long flags; - - ASSERT(ea != NULL); - ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); - if (ifp == NULL) - return DHD_STA_NULL; - - DHD_IF_STA_LIST_LOCK(ifp, flags); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - list_for_each_entry(sta, &ifp->sta_list, list) { - if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) { - DHD_INFO(("%s: found STA " MACDBG "\n", - __FUNCTION__, MAC2STRDBG((char *)ea))); - DHD_IF_STA_LIST_UNLOCK(ifp, flags); - return sta; - } - } -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - DHD_IF_STA_LIST_UNLOCK(ifp, flags); - - return DHD_STA_NULL; -} - -/** Add STA into the interface's STA list. */ -dhd_sta_t * -dhd_add_sta(void *pub, int ifidx, void *ea) -{ - dhd_sta_t *sta; - dhd_if_t *ifp; - unsigned long flags; - - ASSERT(ea != NULL); - ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); - if (ifp == NULL) - return DHD_STA_NULL; - - sta = dhd_sta_alloc((dhd_pub_t *)pub); - if (sta == DHD_STA_NULL) { - DHD_ERROR(("%s: Alloc failed\n", __FUNCTION__)); - return DHD_STA_NULL; - } - - memcpy(sta->ea.octet, ea, ETHER_ADDR_LEN); - - /* link the sta and the dhd interface */ - sta->ifp = ifp; - sta->ifidx = ifidx; -#ifdef DHD_WMF - sta->psta_prim = NULL; -#endif - INIT_LIST_HEAD(&sta->list); - - DHD_IF_STA_LIST_LOCK(ifp, flags); - - list_add_tail(&sta->list, &ifp->sta_list); - -#if defined(BCM_GMAC3) - if (ifp->fwdh) { - ASSERT(ISALIGNED(ea, 2)); - /* Add sta to WOFA forwarder. */ - fwder_reassoc(ifp->fwdh, (uint16 *)ea, (uintptr_t)sta); - } -#endif /* BCM_GMAC3 */ - - DHD_IF_STA_LIST_UNLOCK(ifp, flags); - - return sta; -} - -/** Delete all STAs from the interface's STA list. */ -void -dhd_del_all_sta(void *pub, int ifidx) -{ - dhd_sta_t *sta, *next; - dhd_if_t *ifp; - unsigned long flags; - - ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); - if (ifp == NULL) - return; - - DHD_IF_STA_LIST_LOCK(ifp, flags); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - list_for_each_entry_safe(sta, next, &ifp->sta_list, list) { -#if defined(BCM_GMAC3) - if (ifp->fwdh) { /* Found a sta, remove from WOFA forwarder. */ - ASSERT(ISALIGNED(sta->ea.octet, 2)); - fwder_deassoc(ifp->fwdh, (uint16 *)sta->ea.octet, (uintptr_t)sta); - } -#endif /* BCM_GMAC3 */ - - list_del(&sta->list); - dhd_sta_free(&ifp->info->pub, sta); -#ifdef DHD_L2_FILTER - if (ifp->parp_enable) { - /* clear Proxy ARP cache of specific Ethernet Address */ - bcm_l2_filter_arp_table_update(((dhd_pub_t*)pub)->osh, - ifp->phnd_arp_table, FALSE, - sta->ea.octet, FALSE, ((dhd_pub_t*)pub)->tickcnt); - } -#endif /* DHD_L2_FILTER */ - } -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - DHD_IF_STA_LIST_UNLOCK(ifp, flags); - - return; -} - -/** Delete STA from the interface's STA list. */ -void -dhd_del_sta(void *pub, int ifidx, void *ea) -{ - dhd_sta_t *sta, *next; - dhd_if_t *ifp; - unsigned long flags; - char macstr[ETHER_ADDR_STR_LEN]; - - ASSERT(ea != NULL); - ifp = dhd_get_ifp((dhd_pub_t *)pub, ifidx); - if (ifp == NULL) - return; - - DHD_IF_STA_LIST_LOCK(ifp, flags); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - list_for_each_entry_safe(sta, next, &ifp->sta_list, list) { - if (!memcmp(sta->ea.octet, ea, ETHER_ADDR_LEN)) { -#if defined(BCM_GMAC3) - if (ifp->fwdh) { /* Found a sta, remove from WOFA forwarder. */ - ASSERT(ISALIGNED(ea, 2)); - fwder_deassoc(ifp->fwdh, (uint16 *)ea, (uintptr_t)sta); - } -#endif /* BCM_GMAC3 */ - DHD_MAC_TO_STR(((char *)ea), macstr); - DHD_ERROR(("%s: Deleting STA %s\n", __FUNCTION__, macstr)); - list_del(&sta->list); - dhd_sta_free(&ifp->info->pub, sta); - } - } -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - DHD_IF_STA_LIST_UNLOCK(ifp, flags); -#ifdef DHD_L2_FILTER - if (ifp->parp_enable) { - /* clear Proxy ARP cache of specific Ethernet Address */ - bcm_l2_filter_arp_table_update(((dhd_pub_t*)pub)->osh, ifp->phnd_arp_table, FALSE, - ea, FALSE, ((dhd_pub_t*)pub)->tickcnt); - } -#endif /* DHD_L2_FILTER */ - return; -} - -/** Add STA if it doesn't exist. Not reentrant. */ -dhd_sta_t* -dhd_findadd_sta(void *pub, int ifidx, void *ea) -{ - dhd_sta_t *sta; - - sta = dhd_find_sta(pub, ifidx, ea); - - if (!sta) { - /* Add entry */ - sta = dhd_add_sta(pub, ifidx, ea); - } - - return sta; -} - -#if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) -#if !defined(BCM_GMAC3) -static struct list_head * -dhd_sta_list_snapshot(dhd_info_t *dhd, dhd_if_t *ifp, struct list_head *snapshot_list) -{ - unsigned long flags; - dhd_sta_t *sta, *snapshot; - - INIT_LIST_HEAD(snapshot_list); - - DHD_IF_STA_LIST_LOCK(ifp, flags); - - list_for_each_entry(sta, &ifp->sta_list, list) { - /* allocate one and add to snapshot */ - snapshot = (dhd_sta_t *)MALLOC(dhd->pub.osh, sizeof(dhd_sta_t)); - if (snapshot == NULL) { - DHD_ERROR(("%s: Cannot allocate memory\n", __FUNCTION__)); - continue; - } - - memcpy(snapshot->ea.octet, sta->ea.octet, ETHER_ADDR_LEN); - - INIT_LIST_HEAD(&snapshot->list); - list_add_tail(&snapshot->list, snapshot_list); - } - - DHD_IF_STA_LIST_UNLOCK(ifp, flags); - - return snapshot_list; -} - -static void -dhd_sta_list_snapshot_free(dhd_info_t *dhd, struct list_head *snapshot_list) -{ - dhd_sta_t *sta, *next; - - list_for_each_entry_safe(sta, next, snapshot_list, list) { - list_del(&sta->list); - MFREE(dhd->pub.osh, sta, sizeof(dhd_sta_t)); - } -} -#endif /* !BCM_GMAC3 */ -#endif /* DHD_IGMP_UCQUERY || DHD_UCAST_UPNP */ - -#else -static inline void dhd_if_flush_sta(dhd_if_t * ifp) { } -static inline void dhd_if_del_sta_list(dhd_if_t *ifp) {} -static inline int dhd_sta_pool_init(dhd_pub_t *dhdp, int max_sta) { return BCME_OK; } -static inline void dhd_sta_pool_fini(dhd_pub_t *dhdp, int max_sta) {} -static inline void dhd_sta_pool_clear(dhd_pub_t *dhdp, int max_sta) {} -dhd_sta_t *dhd_findadd_sta(void *pub, int ifidx, void *ea) { return NULL; } -dhd_sta_t *dhd_find_sta(void *pub, int ifidx, void *ea) { return NULL; } -void dhd_del_sta(void *pub, int ifidx, void *ea) {} -#endif /* PCIE_FULL_DONGLE */ - - - -#if defined(DHD_LB) - -#if defined(DHD_LB_TXC) || defined(DHD_LB_RXC) || defined(DHD_LB_TXP) -/** - * dhd_tasklet_schedule - Function that runs in IPI context of the destination - * CPU and schedules a tasklet. - * @tasklet: opaque pointer to the tasklet - */ -INLINE void -dhd_tasklet_schedule(void *tasklet) -{ - tasklet_schedule((struct tasklet_struct *)tasklet); -} -/** - * dhd_tasklet_schedule_on - Executes the passed takslet in a given CPU - * @tasklet: tasklet to be scheduled - * @on_cpu: cpu core id - * - * If the requested cpu is online, then an IPI is sent to this cpu via the - * smp_call_function_single with no wait and the tasklet_schedule function - * will be invoked to schedule the specified tasklet on the requested CPU. - */ -INLINE void -dhd_tasklet_schedule_on(struct tasklet_struct *tasklet, int on_cpu) -{ - const int wait = 0; - smp_call_function_single(on_cpu, - dhd_tasklet_schedule, (void *)tasklet, wait); -} - -/** - * dhd_work_schedule_on - Executes the passed work in a given CPU - * @work: work to be scheduled - * @on_cpu: cpu core id - * - * If the requested cpu is online, then an IPI is sent to this cpu via the - * schedule_work_on and the work function - * will be invoked to schedule the specified work on the requested CPU. - */ - -INLINE void -dhd_work_schedule_on(struct work_struct *work, int on_cpu) -{ - schedule_work_on(on_cpu, work); -} -#endif /* DHD_LB_TXC || DHD_LB_RXC || DHD_LB_TXP */ - -#if defined(DHD_LB_TXC) -/** - * dhd_lb_tx_compl_dispatch - load balance by dispatching the tx_compl_tasklet - * on another cpu. The tx_compl_tasklet will take care of DMA unmapping and - * freeing the packets placed in the tx_compl workq - */ -void -dhd_lb_tx_compl_dispatch(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = dhdp->info; - int curr_cpu, on_cpu; - - if (dhd->rx_napi_netdev == NULL) { - DHD_ERROR(("%s: dhd->rx_napi_netdev is NULL\n", __FUNCTION__)); - return; - } - - DHD_LB_STATS_INCR(dhd->txc_sched_cnt); - /* - * If the destination CPU is NOT online or is same as current CPU - * no need to schedule the work - */ - curr_cpu = get_cpu(); - put_cpu(); - - on_cpu = atomic_read(&dhd->tx_compl_cpu); - - if ((on_cpu == curr_cpu) || (!cpu_online(on_cpu))) { - dhd_tasklet_schedule(&dhd->tx_compl_tasklet); - } else { - schedule_work(&dhd->tx_compl_dispatcher_work); - } -} - -static void dhd_tx_compl_dispatcher_fn(struct work_struct * work) -{ - struct dhd_info *dhd = - container_of(work, struct dhd_info, tx_compl_dispatcher_work); - int cpu; - - get_online_cpus(); - cpu = atomic_read(&dhd->tx_compl_cpu); - if (!cpu_online(cpu)) - dhd_tasklet_schedule(&dhd->tx_compl_tasklet); - else - dhd_tasklet_schedule_on(&dhd->tx_compl_tasklet, cpu); - put_online_cpus(); -} -#endif /* DHD_LB_TXC */ - -#if defined(DHD_LB_RXC) -/** - * dhd_lb_rx_compl_dispatch - load balance by dispatching the rx_compl_tasklet - * on another cpu. The rx_compl_tasklet will take care of reposting rx buffers - * in the H2D RxBuffer Post common ring, by using the recycled pktids that were - * placed in the rx_compl workq. - * - * @dhdp: pointer to dhd_pub object - */ -void -dhd_lb_rx_compl_dispatch(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = dhdp->info; - int curr_cpu, on_cpu; - - if (dhd->rx_napi_netdev == NULL) { - DHD_ERROR(("%s: dhd->rx_napi_netdev is NULL\n", __FUNCTION__)); - return; - } - - DHD_LB_STATS_INCR(dhd->rxc_sched_cnt); - /* - * If the destination CPU is NOT online or is same as current CPU - * no need to schedule the work - */ - curr_cpu = get_cpu(); - put_cpu(); - on_cpu = atomic_read(&dhd->rx_compl_cpu); - - if ((on_cpu == curr_cpu) || (!cpu_online(on_cpu))) { - dhd_tasklet_schedule(&dhd->rx_compl_tasklet); - } else { - dhd_rx_compl_dispatcher_fn(dhdp); - } -} - -static void dhd_rx_compl_dispatcher_fn(dhd_pub_t *dhdp) -{ - struct dhd_info *dhd = dhdp->info; - int cpu; - - preempt_disable(); - cpu = atomic_read(&dhd->rx_compl_cpu); - if (!cpu_online(cpu)) - dhd_tasklet_schedule(&dhd->rx_compl_tasklet); - else { - dhd_tasklet_schedule_on(&dhd->rx_compl_tasklet, cpu); - } - preempt_enable(); -} -#endif /* DHD_LB_RXC */ - -#if defined(DHD_LB_TXP) -static void dhd_tx_dispatcher_work(struct work_struct * work) -{ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - struct dhd_info *dhd = - container_of(work, struct dhd_info, tx_dispatcher_work); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - dhd_tasklet_schedule(&dhd->tx_tasklet); -} - -static void dhd_tx_dispatcher_fn(dhd_pub_t *dhdp) -{ - int cpu; - int net_tx_cpu; - dhd_info_t *dhd = dhdp->info; - - preempt_disable(); - cpu = atomic_read(&dhd->tx_cpu); - net_tx_cpu = atomic_read(&dhd->net_tx_cpu); - - /* - * Now if the NET_TX has pushed the packet in the same - * CPU that is chosen for Tx processing, seperate it out - * i.e run the TX processing tasklet in compl_cpu - */ - if (net_tx_cpu == cpu) - cpu = atomic_read(&dhd->tx_compl_cpu); - - if (!cpu_online(cpu)) { - /* - * Ooohh... but the Chosen CPU is not online, - * Do the job in the current CPU itself. - */ - dhd_tasklet_schedule(&dhd->tx_tasklet); - } else { - /* - * Schedule tx_dispatcher_work to on the cpu which - * in turn will schedule tx_tasklet. - */ - dhd_work_schedule_on(&dhd->tx_dispatcher_work, cpu); - } - preempt_enable(); -} - -/** - * dhd_lb_tx_dispatch - load balance by dispatching the tx_tasklet - * on another cpu. The tx_tasklet will take care of actually putting - * the skbs into appropriate flow ring and ringing H2D interrupt - * - * @dhdp: pointer to dhd_pub object - */ -static void -dhd_lb_tx_dispatch(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = dhdp->info; - int curr_cpu; - - curr_cpu = get_cpu(); - put_cpu(); - - /* Record the CPU in which the TX request from Network stack came */ - atomic_set(&dhd->net_tx_cpu, curr_cpu); - - /* Schedule the work to dispatch ... */ - dhd_tx_dispatcher_fn(dhdp); - -} -#endif /* DHD_LB_TXP */ - -#if defined(DHD_LB_RXP) -/** - * dhd_napi_poll - Load balance napi poll function to process received - * packets and send up the network stack using netif_receive_skb() - * - * @napi: napi object in which context this poll function is invoked - * @budget: number of packets to be processed. - * - * Fetch the dhd_info given the rx_napi_struct. Move all packets from the - * rx_napi_queue into a local rx_process_queue (lock and queue move and unlock). - * Dequeue each packet from head of rx_process_queue, fetch the ifid from the - * packet tag and sendup. - */ -static int -dhd_napi_poll(struct napi_struct *napi, int budget) -{ - int ifid; - const int pkt_count = 1; - const int chan = 0; - struct sk_buff * skb; - unsigned long flags; - struct dhd_info *dhd; - int processed = 0; - struct sk_buff_head rx_process_queue; - -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - dhd = container_of(napi, struct dhd_info, rx_napi_struct); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - - DHD_INFO(("%s napi_queue<%d> budget<%d>\n", - __FUNCTION__, skb_queue_len(&dhd->rx_napi_queue), budget)); - __skb_queue_head_init(&rx_process_queue); - - /* extract the entire rx_napi_queue into local rx_process_queue */ - spin_lock_irqsave(&dhd->rx_napi_queue.lock, flags); - skb_queue_splice_tail_init(&dhd->rx_napi_queue, &rx_process_queue); - spin_unlock_irqrestore(&dhd->rx_napi_queue.lock, flags); - - while ((skb = __skb_dequeue(&rx_process_queue)) != NULL) { - OSL_PREFETCH(skb->data); - - ifid = DHD_PKTTAG_IFID((dhd_pkttag_fr_t *)PKTTAG(skb)); - - DHD_INFO(("%s dhd_rx_frame pkt<%p> ifid<%d>\n", - __FUNCTION__, skb, ifid)); - - dhd_rx_frame(&dhd->pub, ifid, skb, pkt_count, chan); - processed++; - } - - DHD_LB_STATS_UPDATE_NAPI_HISTO(&dhd->pub, processed); - - DHD_INFO(("%s processed %d\n", __FUNCTION__, processed)); - napi_complete(napi); - - return budget - 1; -} - -/** - * dhd_napi_schedule - Place the napi struct into the current cpus softnet napi - * poll list. This function may be invoked via the smp_call_function_single - * from a remote CPU. - * - * This function will essentially invoke __raise_softirq_irqoff(NET_RX_SOFTIRQ) - * after the napi_struct is added to the softnet data's poll_list - * - * @info: pointer to a dhd_info struct - */ -static void -dhd_napi_schedule(void *info) -{ - dhd_info_t *dhd = (dhd_info_t *)info; - - DHD_INFO(("%s rx_napi_struct<%p> on cpu<%d>\n", - __FUNCTION__, &dhd->rx_napi_struct, atomic_read(&dhd->rx_napi_cpu))); - - /* add napi_struct to softnet data poll list and raise NET_RX_SOFTIRQ */ - if (napi_schedule_prep(&dhd->rx_napi_struct)) { - __napi_schedule(&dhd->rx_napi_struct); - DHD_LB_STATS_PERCPU_ARR_INCR(dhd->napi_percpu_run_cnt); - } - - /* - * If the rx_napi_struct was already running, then we let it complete - * processing all its packets. The rx_napi_struct may only run on one - * core at a time, to avoid out-of-order handling. - */ -} - -/** - * dhd_napi_schedule_on - API to schedule on a desired CPU core a NET_RX_SOFTIRQ - * action after placing the dhd's rx_process napi object in the the remote CPU's - * softnet data's poll_list. - * - * @dhd: dhd_info which has the rx_process napi object - * @on_cpu: desired remote CPU id - */ -static INLINE int -dhd_napi_schedule_on(dhd_info_t *dhd, int on_cpu) -{ - int wait = 0; /* asynchronous IPI */ - DHD_INFO(("%s dhd<%p> napi<%p> on_cpu<%d>\n", - __FUNCTION__, dhd, &dhd->rx_napi_struct, on_cpu)); - - if (smp_call_function_single(on_cpu, dhd_napi_schedule, dhd, wait)) { - DHD_ERROR(("%s smp_call_function_single on_cpu<%d> failed\n", - __FUNCTION__, on_cpu)); - } - - DHD_LB_STATS_INCR(dhd->napi_sched_cnt); - - return 0; -} - -/* - * Call get_online_cpus/put_online_cpus around dhd_napi_schedule_on - * Why should we do this? - * The candidacy algorithm is run from the call back function - * registered to CPU hotplug notifier. This call back happens from Worker - * context. The dhd_napi_schedule_on is also from worker context. - * Note that both of this can run on two different CPUs at the same time. - * So we can possibly have a window where a given CPUn is being brought - * down from CPUm while we try to run a function on CPUn. - * To prevent this its better have the whole code to execute an SMP - * function under get_online_cpus. - * This function call ensures that hotplug mechanism does not kick-in - * until we are done dealing with online CPUs - * If the hotplug worker is already running, no worries because the - * candidacy algo would then reflect the same in dhd->rx_napi_cpu. - * - * The below mentioned code structure is proposed in - * https://www.kernel.org/doc/Documentation/cpu-hotplug.txt - * for the question - * Q: I need to ensure that a particular cpu is not removed when there is some - * work specific to this cpu is in progress - * - * According to the documentation calling get_online_cpus is NOT required, if - * we are running from tasklet context. Since dhd_rx_napi_dispatcher_fn can - * run from Work Queue context we have to call these functions - */ -static void dhd_rx_napi_dispatcher_fn(struct work_struct * work) -{ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - struct dhd_info *dhd = - container_of(work, struct dhd_info, rx_napi_dispatcher_work); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - int cpu; - - get_online_cpus(); - cpu = atomic_read(&dhd->rx_napi_cpu); - - if (!cpu_online(cpu)) - dhd_napi_schedule(dhd); - else - dhd_napi_schedule_on(dhd, cpu); - - put_online_cpus(); -} - -/** - * dhd_lb_rx_napi_dispatch - load balance by dispatching the rx_napi_struct - * to run on another CPU. The rx_napi_struct's poll function will retrieve all - * the packets enqueued into the rx_napi_queue and sendup. - * The producer's rx packet queue is appended to the rx_napi_queue before - * dispatching the rx_napi_struct. - */ -void -dhd_lb_rx_napi_dispatch(dhd_pub_t *dhdp) -{ - unsigned long flags; - dhd_info_t *dhd = dhdp->info; - int curr_cpu; - int on_cpu; - - if (dhd->rx_napi_netdev == NULL) { - DHD_ERROR(("%s: dhd->rx_napi_netdev is NULL\n", __FUNCTION__)); - return; - } - - DHD_INFO(("%s append napi_queue<%d> pend_queue<%d>\n", __FUNCTION__, - skb_queue_len(&dhd->rx_napi_queue), skb_queue_len(&dhd->rx_pend_queue))); - - /* append the producer's queue of packets to the napi's rx process queue */ - spin_lock_irqsave(&dhd->rx_napi_queue.lock, flags); - skb_queue_splice_tail_init(&dhd->rx_pend_queue, &dhd->rx_napi_queue); - spin_unlock_irqrestore(&dhd->rx_napi_queue.lock, flags); - - /* - * If the destination CPU is NOT online or is same as current CPU - * no need to schedule the work - */ - curr_cpu = get_cpu(); - put_cpu(); - - on_cpu = atomic_read(&dhd->rx_napi_cpu); - if ((on_cpu == curr_cpu) || (!cpu_online(on_cpu))) { - dhd_napi_schedule(dhd); - } else { - schedule_work(&dhd->rx_napi_dispatcher_work); - } -} - -/** - * dhd_lb_rx_pkt_enqueue - Enqueue the packet into the producer's queue - */ -void -dhd_lb_rx_pkt_enqueue(dhd_pub_t *dhdp, void *pkt, int ifidx) -{ - dhd_info_t *dhd = dhdp->info; - - DHD_INFO(("%s enqueue pkt<%p> ifidx<%d> pend_queue<%d>\n", __FUNCTION__, - pkt, ifidx, skb_queue_len(&dhd->rx_pend_queue))); - DHD_PKTTAG_SET_IFID((dhd_pkttag_fr_t *)PKTTAG(pkt), ifidx); - __skb_queue_tail(&dhd->rx_pend_queue, pkt); -} -#endif /* DHD_LB_RXP */ - -#endif /* DHD_LB */ - - -/** Returns dhd iflist index corresponding the the bssidx provided by apps */ -int dhd_bssidx2idx(dhd_pub_t *dhdp, uint32 bssidx) -{ - dhd_if_t *ifp; - dhd_info_t *dhd = dhdp->info; - int i; - - ASSERT(bssidx < DHD_MAX_IFS); - ASSERT(dhdp); - - for (i = 0; i < DHD_MAX_IFS; i++) { - ifp = dhd->iflist[i]; - if (ifp && (ifp->bssidx == bssidx)) { - DHD_TRACE(("Index manipulated for %s from %d to %d\n", - ifp->name, bssidx, i)); - break; - } - } - return i; -} - -static inline int dhd_rxf_enqueue(dhd_pub_t *dhdp, void* skb) -{ - uint32 store_idx; - uint32 sent_idx; - - if (!skb) { - DHD_ERROR(("dhd_rxf_enqueue: NULL skb!!!\n")); - return BCME_ERROR; - } - - dhd_os_rxflock(dhdp); - store_idx = dhdp->store_idx; - sent_idx = dhdp->sent_idx; - if (dhdp->skbbuf[store_idx] != NULL) { - /* Make sure the previous packets are processed */ - dhd_os_rxfunlock(dhdp); -#ifdef RXF_DEQUEUE_ON_BUSY - DHD_TRACE(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n", - skb, store_idx, sent_idx)); - return BCME_BUSY; -#else /* RXF_DEQUEUE_ON_BUSY */ - DHD_ERROR(("dhd_rxf_enqueue: pktbuf not consumed %p, store idx %d sent idx %d\n", - skb, store_idx, sent_idx)); - /* removed msleep here, should use wait_event_timeout if we - * want to give rx frame thread a chance to run - */ -#if defined(WAIT_DEQUEUE) - OSL_SLEEP(1); -#endif - return BCME_ERROR; -#endif /* RXF_DEQUEUE_ON_BUSY */ - } - DHD_TRACE(("dhd_rxf_enqueue: Store SKB %p. idx %d -> %d\n", - skb, store_idx, (store_idx + 1) & (MAXSKBPEND - 1))); - dhdp->skbbuf[store_idx] = skb; - dhdp->store_idx = (store_idx + 1) & (MAXSKBPEND - 1); - dhd_os_rxfunlock(dhdp); - - return BCME_OK; -} - -static inline void* dhd_rxf_dequeue(dhd_pub_t *dhdp) -{ - uint32 store_idx; - uint32 sent_idx; - void *skb; - - dhd_os_rxflock(dhdp); - - store_idx = dhdp->store_idx; - sent_idx = dhdp->sent_idx; - skb = dhdp->skbbuf[sent_idx]; - - if (skb == NULL) { - dhd_os_rxfunlock(dhdp); - DHD_ERROR(("dhd_rxf_dequeue: Dequeued packet is NULL, store idx %d sent idx %d\n", - store_idx, sent_idx)); - return NULL; - } - - dhdp->skbbuf[sent_idx] = NULL; - dhdp->sent_idx = (sent_idx + 1) & (MAXSKBPEND - 1); - - DHD_TRACE(("dhd_rxf_dequeue: netif_rx_ni(%p), sent idx %d\n", - skb, sent_idx)); - - dhd_os_rxfunlock(dhdp); - - return skb; -} - -int dhd_process_cid_mac(dhd_pub_t *dhdp, bool prepost) -{ - if (prepost) { /* pre process */ - dhd_read_cis(dhdp); - dhd_check_module_cid(dhdp); - dhd_check_module_mac(dhdp); - dhd_set_macaddr_from_file(dhdp); - } else { /* post process */ - dhd_write_macaddr(&dhdp->mac); - dhd_clear_cis(dhdp); - } - - return 0; -} - -// terence 20160615: fix building error if ARP_OFFLOAD_SUPPORT removed -#if defined(PKT_FILTER_SUPPORT) -#if defined(ARP_OFFLOAD_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER) -static bool -_turn_on_arp_filter(dhd_pub_t *dhd, int op_mode_param) -{ - bool _apply = FALSE; - /* In case of IBSS mode, apply arp pkt filter */ - if (op_mode_param & DHD_FLAG_IBSS_MODE) { - _apply = TRUE; - goto exit; - } - /* In case of P2P GO or GC, apply pkt filter to pass arp pkt to host */ - if (op_mode_param & (DHD_FLAG_P2P_GC_MODE | DHD_FLAG_P2P_GO_MODE)) { - _apply = TRUE; - goto exit; - } - -exit: - return _apply; -} -#endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */ - -void -dhd_set_packet_filter(dhd_pub_t *dhd) -{ - int i; - - DHD_TRACE(("%s: enter\n", __FUNCTION__)); - if (dhd_pkt_filter_enable) { - for (i = 0; i < dhd->pktfilter_count; i++) { - dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); - } -#ifdef PF_SETUP_COMMAND - for (i = DHD_RESERVED_STATIC_FILTER_NUM; - i < DHD_RESERVED_STATIC_FILTER_NUM + dhd->pktfilter_count_ext; i++) { - dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); - } -#endif /* PF_SETUP_COMMAND */ - } -} - -static void -dhd_packet_filter_clear_stats(dhd_pub_t *dhd) -{ - int ext_pf_cnt = DHD_RESERVED_STATIC_FILTER_NUM + dhd->pktfilter_count_ext; - int i, id, ret; - - /* default rules */ - for (i = 0; i < dhd->pktfilter_count; i++) { - if (dhd->pktfilter[i]) { - sscanf(dhd->pktfilter[i], "%d %*s", &id); - - ret = dhd_wl_ioctl_set_intiovar(dhd, "pkt_filter_clear_stats", id, - WLC_SET_VAR, TRUE, 0); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to clear pf %d stats, ret=%d\n", - __FUNCTION__, id, ret)); - } - } - } - - for (i = DHD_RESERVED_STATIC_FILTER_NUM; i < ext_pf_cnt; i++) { - if (dhd->pktfilter[i]) { - sscanf(dhd->pktfilter[i], "%d %*s", &id); - - ret = dhd_wl_ioctl_set_intiovar(dhd, "pkt_filter_clear_stats", id, - WLC_SET_VAR, TRUE, 0); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to clear pf %d stats, ret=%d\n", - __FUNCTION__, id, ret)); - } - } - } - -#ifdef BCOL_TCPKA_SYNC - for (i = TCPKA_DEFAULT_SESS_ID; i <= TCPKA_MAX_SESSION; i++) { - id = PF_FOR_TCPKA_ID_BASE + i; - - ret = dhd_wl_ioctl_set_intiovar(dhd, "pkt_filter_clear_stats", id, - WLC_SET_VAR, TRUE, 0); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to clear pf %d stats, ret=%d\n", - __FUNCTION__, id, ret)); - } - } -#endif /* BCOL_TCPKA_SYNC */ -} - -void -dhd_enable_packet_filter(int value, dhd_pub_t *dhd) -{ - int i; -#ifdef PF_SETUP_COMMAND - int ret = BCME_OK; -#endif /* PF_SETUP_COMMAND */ - - DHD_TRACE(("%s: enter, value = %d\n", __FUNCTION__, value)); - if ((dhd->op_mode & DHD_FLAG_HOSTAP_MODE) && value) { - DHD_ERROR(("%s: DHD_FLAG_HOSTAP_MODE\n", __FUNCTION__)); - return; - } - /* 1 - Enable packet filter, only allow unicast packet to send up */ - /* 0 - Disable packet filter */ - if (dhd_pkt_filter_enable && (!value || - (dhd_support_sta_mode(dhd) && !dhd->dhcp_in_progress))) - { - for (i = 0; i < dhd->pktfilter_count; i++) { -// terence 20160615: fix building error if ARP_OFFLOAD_SUPPORT removed -#if defined(ARP_OFFLOAD_SUPPORT) && !defined(GAN_LITE_NAT_KEEPALIVE_FILTER) - if (value && (i == DHD_ARP_FILTER_NUM) && - !_turn_on_arp_filter(dhd, dhd->op_mode)) { - DHD_TRACE(("Do not turn on ARP white list pkt filter:" - "val %d, cnt %d, op_mode 0x%x\n", - value, i, dhd->op_mode)); - continue; - } -#endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */ - dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], - value, dhd_master_mode); - } - } - -#ifdef PF_SETUP_COMMAND - if (value) { - dhd_master_mode = PKT_FILTER_MODE_FORWARD_ON_MATCH | - PKT_FILTER_MODE_PKT_FORWARD_OFF_DEFAULT; - } else { - dhd_master_mode = PKT_FILTER_MODE_FORWARD_ON_MATCH | - PKT_FILTER_MODE_PKT_FORWARD_DEFAULT; - } - - ret = dhd_wl_ioctl_set_intiovar(dhd, "pkt_filter_mode", dhd_master_mode, - WLC_SET_VAR, TRUE, 0); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to set master mode, ret=%d\n", - __FUNCTION__, ret)); - } - - if (value) { - struct net_device *dev = dhd_idx2net(dhd, 0); - dhd_packet_filter_clear_stats(dhd); - if (tcpka_sync.tcpka_sync_mode == BCOL_TCPKA_SYNC_MODE_OFF) { - DHD_ERROR(("%s: Reset tcpka and pkt filters\n", __func__)); - dhd_tcpka_reset(dhd, dev); - } - } - -#endif /* PF_SETUP_COMMAND */ -} - -#ifdef PF_SETUP_COMMAND -static int -dhd_packet_filter_sync_op(struct net_device *dev, - wl_pkt_filter_list_t *list) -{ - int ret = BCME_OK, i, j; - unsigned int filter_len; - wl_pkt_filter_t *filterp; - - filterp = list->filter; - for (i = 0; i < list->num; i++) { - uint type = dtoh32(filterp->type); - if (type != WL_PKT_FILTER_TYPE_PATTERN_LIST_MATCH) { - char filter[MAX_FILTER_CONFIG_LEN]; - pf_config_t pf_cfg; - memset(filter ,0, sizeof(filter)); - memset(&pf_cfg ,0, sizeof(pf_cfg)); - sprintf(filter, "%d %d %d %d", - dtoh32(filterp->id), - dtoh32(filterp->negate_match), - dtoh32(filterp->type), - dtoh32(filterp->u.pattern.offset)); - sprintf(filter, "%s 0x", filter); - for (j = 0; j < dtoh32(filterp->u.pattern.size_bytes); j++) - sprintf(filter, "%s%02x", filter, - filterp->u.pattern.mask_and_pattern[j]); - sprintf(filter, "%s 0x", filter); - for (; j < 2 * dtoh32(filterp->u.pattern.size_bytes); j++) - sprintf(filter, "%s%02x", filter, - filterp->u.pattern.mask_and_pattern[j]); - filter_len = WL_PKT_FILTER_PATTERN_FIXED_LEN + - 2 * dtoh32(filterp->u.pattern.size_bytes); - DHD_INFO(("Filter: %s", filter)); - if (dtoh32(filterp->id) >= DHD_FILTER_NUMBER_START) { - pf_cfg.id = dtoh32(filterp->id); - pf_cfg.addremove = TRUE; - pf_cfg.len = strlen(filter); - memcpy(&pf_cfg.config, &filter, sizeof(pf_cfg.config)); - dhd_packet_filter_add_remove_ext(dev, TRUE, - pf_cfg.id, &pf_cfg, TRUE); - } - } - filter_len += WL_PKT_FILTER_FIXED_LEN; - filterp = (wl_pkt_filter_t *) ((uint8 *)filterp + filter_len); - filterp = ALIGN_ADDR(filterp, sizeof(uint32)); - } - return ret; -} - -int -dhd_packet_filter_sync(struct net_device *dev) -{ - dhd_info_t *dhd_info = DHD_DEV_INFO(dev); - dhd_pub_t *dhd = &dhd_info->pub; - int ret = BCME_OK, buf_len = WLC_IOCTL_MEDLEN; - uint32 enable = 0; - char *resp_buf = NULL; - wl_pkt_filter_list_t *list; - - DHD_TRACE(("%s: Inn\n", __func__)); - resp_buf = kzalloc(buf_len, GFP_KERNEL); - if (!resp_buf) { - DHD_ERROR(("%s: resp_buf memory alloc failed\n", __func__)); - return -ENOMEM; - } - /* Remove filters in dhd */ - dhd_packet_filter_add_remove_ext(dev, false, -1, NULL, TRUE); - - list = (wl_pkt_filter_list_t *)resp_buf; - - memset(resp_buf, 0, buf_len); - ret = dhd_getiovar(dhd, 0, "pkt_filter_list", (char *)&enable, - sizeof(enable), (char **)&list, buf_len); - if (ret) { - DHD_ERROR(("%s: get pkt filter disabled list failed, ret = %d\n", - __func__, ret)); - goto exit; - } - - DHD_INFO(("Num filters disabled: %d\n", list->num)); - dhd_packet_filter_sync_op(dev, list); - - enable = 1; - memset(resp_buf, 0, buf_len); - ret = dhd_getiovar(dhd, 0, "pkt_filter_list", (char *)&enable, - sizeof(enable), (char **)&list, buf_len); - if (ret) { - DHD_ERROR(("%s: get pkt filter enabled list failed, ret = %d\n", - __func__, ret)); - goto exit; - } - - DHD_INFO(("Num filters enabled: %d\n", list->num)); - dhd_packet_filter_sync_op(dev, list); - DHD_TRACE(("%s: done\n", __func__)); - -exit: - if (resp_buf) - kfree(resp_buf); - return ret; -} - -int -dhd_packet_filter_add_remove_ext(struct net_device *dev, - bool add, int pf_id, pf_config_t *pf_cfg, bool sync) -{ - dhd_info_t *dhd_info = DHD_DEV_INFO(dev); - dhd_pub_t *dhd = &dhd_info->pub; - char *pf_str; - int ret = BCME_OK, i, fid; - int ext_pf_cnt = DHD_RESERVED_STATIC_FILTER_NUM + dhd->pktfilter_count_ext; - - /* Add filter */ - if (add) { - if (pf_id == 0) { - for (i = DHD_RESERVED_STATIC_FILTER_NUM; i < ext_pf_cnt; i++) { - int id = 0; - char tmp[MAX_FILTER_CONFIG_LEN]; - - memset(&tmp, 0, sizeof(tmp)); - - if (dhd->pktfilter[i]) { - char* head_of_content = strchr(dhd->pktfilter[i], ' ') + 1; - size_t len_of_content = (dhd->pktfilter[i] + - MAX_FILTER_CONFIG_LEN - head_of_content); - - sscanf(dhd->pktfilter[i], "%d %*s", &id); - memcpy(tmp, head_of_content, len_of_content); - DHD_INFO(("comparing %s, len = %d with %s\n", - tmp, (int)strlen(tmp), pf_cfg->config)); - if (strncasecmp(tmp, pf_cfg->config, strlen(tmp)) == 0) { - memcpy(tmp, pf_cfg->config, sizeof(tmp)); - DHD_INFO(("Assign existed id %d to %s\n", id, tmp)); - pf_cfg->id = id; - sprintf(pf_cfg->config, "%d %s", id, tmp); - return ret; - } - } - } - - for (fid = DHD_FILTER_NUMBER_START; - fid < (DHD_FILTER_NUMBER_START + (100 - DHD_RESERVED_STATIC_FILTER_NUM)); - fid++) { - bool found = FALSE; - for (i = DHD_RESERVED_STATIC_FILTER_NUM; i < ext_pf_cnt; i++) { - int id = 0; - if (dhd->pktfilter[i]) { - sscanf(dhd->pktfilter[i], "%d %*s", &id); - if (fid == id) { - found = TRUE; - break; - } - } - } - - if (!found) { - char tmp[MAX_FILTER_CONFIG_LEN]; - memcpy(tmp, pf_cfg->config, sizeof(tmp)); - DHD_INFO(("Assign id %d to %s\n", fid, tmp)); - pf_cfg->id = fid; - sprintf(pf_cfg->config, "%d %s", fid, tmp); - break; - } - } - } - if (!(pf_str = MALLOC(dhd->osh, strlen(pf_cfg->config) + 1))) { - DHD_ERROR(("%s: malloc failed\n", __FUNCTION__)); - return BCME_NOMEM; - } - memcpy(pf_str, pf_cfg->config, strlen(pf_cfg->config) + 1); - DHD_INFO(("%s: Adding filter [%d] %s\n", __FUNCTION__, - ext_pf_cnt, pf_str)); - dhd->pktfilter[ext_pf_cnt] = pf_str; - if (!sync) - dhd_pktfilter_offload_set(dhd, pf_str); - dhd->pktfilter_count_ext++; - } else { /* Delete filter */ - bool found = false; - DHD_INFO(("%s: Removing filter %d, pf count %d, sync %d\n", - __FUNCTION__, pf_id, dhd->pktfilter_count_ext, sync)); - - if ((pf_id >= 0) && (pf_id < DHD_FILTER_NUMBER_START)) { - DHD_ERROR(("%s: Can not remove default rule\n", __FUNCTION__)); - return BCME_BADARG; - } - - for (i = DHD_RESERVED_STATIC_FILTER_NUM; i < ext_pf_cnt; i++) { - if (!found && dhd->pktfilter[i]) { - int id; - pf_str = dhd->pktfilter[i]; - sscanf(pf_str, "%d ", &id); - DHD_INFO(("%s: Checking filter [%d] %s\n", - __FUNCTION__, i, pf_str)); - - if (pf_id < 0) { // Free all exist filters - DHD_INFO(("%s: Free filter %d\n", __FUNCTION__, id)); - if (!sync) - dhd_pktfilter_offload_delete(dhd, id); - MFREE(dhd->osh, pf_str, strlen(pf_str) + 1); - dhd->pktfilter[i] = NULL; - dhd->pktfilter_count_ext--; - } - - if (id == pf_id) { - DHD_INFO(("%s: Found filter %d @ index %d\n", - __FUNCTION__, id, i)); - found = true; - if (!sync) - dhd_pktfilter_offload_delete(dhd, id); - MFREE(dhd->osh, pf_str, strlen(pf_str) + 1); - dhd->pktfilter[i] = NULL; - dhd->pktfilter_count_ext--; - } - } - - if (found) { - if (i == (ext_pf_cnt - 1) && - dhd->pktfilter[i] != NULL) { - DHD_INFO(("%s: Clear filter [%s] @ %d\n", __FUNCTION__, - dhd->pktfilter[i], i)); - dhd->pktfilter[i] = NULL; - } else { - char *next = dhd->pktfilter[i+1]; - DHD_INFO(("%s: Moving filter [%s] from %d to %d\n", - __FUNCTION__, next, i+1, i)); - dhd->pktfilter[i] = next; - } - } - } - } - return ret; -} -#endif /* PF_SETUP_COMMAND */ - -int -dhd_packet_filter_add_remove(dhd_pub_t *dhdp, int add_remove, int num) -{ - char *filterp = NULL; - int filter_id = 0; - - switch (num) { - case DHD_BROADCAST_FILTER_NUM: - filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF"; - filter_id = 101; - break; - case DHD_MULTICAST4_FILTER_NUM: - filter_id = 102; - if (FW_SUPPORTED((dhdp), pf6)) { - if (dhdp->pktfilter[num] != NULL) { - dhd_pktfilter_offload_delete(dhdp, filter_id); - dhdp->pktfilter[num] = NULL; - } - if (!add_remove) { - filterp = DISCARD_IPV4_MCAST; - add_remove = 1; - break; - } - } - filterp = "102 0 0 0 0xFFFFFF 0x01005E"; - break; - case DHD_MULTICAST6_FILTER_NUM: - filter_id = 103; - if (FW_SUPPORTED((dhdp), pf6)) { - if (dhdp->pktfilter[num] != NULL) { - dhd_pktfilter_offload_delete(dhdp, filter_id); - dhdp->pktfilter[num] = NULL; - } - if (!add_remove) { - filterp = DISCARD_IPV6_MCAST; - add_remove = 1; - break; - } - } - filterp = "103 0 0 0 0xFFFF 0x3333"; - break; - case DHD_MDNS_FILTER_NUM: - filterp = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB"; - filter_id = 104; - break; - case DHD_ARP_FILTER_NUM: - filterp = "105 0 0 12 0xFFFF 0x0806"; - filter_id = 105; - break; - case DHD_BROADCAST_ARP_FILTER_NUM: - filterp = "106 0 0 0 0xFFFFFFFFFFFF0000000000000806" - " 0xFFFFFFFFFFFF0000000000000806"; - filter_id = 106; - break; - default: - return -EINVAL; - } - - /* Add filter */ - if (add_remove) { - dhdp->pktfilter[num] = filterp; - dhd_pktfilter_offload_set(dhdp, dhdp->pktfilter[num]); - } else { /* Delete filter */ - if (dhdp->pktfilter[num]) { - dhd_pktfilter_offload_delete(dhdp, filter_id); - dhdp->pktfilter[num] = NULL; - } - } - - return 0; -} -#endif /* PKT_FILTER_SUPPORT */ - -static int dhd_set_suspend(int value, dhd_pub_t *dhd) -{ - int power_mode = PM_MAX; -#ifdef SUPPORT_SENSORHUB - shub_control_t shub_ctl; -#endif /* SUPPORT_SENSORHUB */ - /* wl_pkt_filter_enable_t enable_parm; */ - int bcn_li_dtim = 0; /* Default bcn_li_dtim in resume mode is 0 */ - int ret = 0; -#ifdef DHD_USE_EARLYSUSPEND -#ifdef CUSTOM_BCN_TIMEOUT_IN_SUSPEND - int bcn_timeout = 0; -#endif /* CUSTOM_BCN_TIMEOUT_IN_SUSPEND */ -#ifdef CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND - int roam_time_thresh = 0; /* (ms) */ -#endif /* CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND */ -#ifndef ENABLE_FW_ROAM_SUSPEND - uint roamvar = dhd->conf->roam_off_suspend; -#endif /* ENABLE_FW_ROAM_SUSPEND */ -#ifdef ENABLE_BCN_LI_BCN_WAKEUP - int bcn_li_bcn; -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ - uint nd_ra_filter = 0; -#endif /* DHD_USE_EARLYSUSPEND */ -#ifdef PASS_ALL_MCAST_PKTS - struct dhd_info *dhdinfo; - uint32 allmulti; - uint i; -#endif /* PASS_ALL_MCAST_PKTS */ -#ifdef ENABLE_IPMCAST_FILTER - int ipmcast_l2filter; -#endif /* ENABLE_IPMCAST_FILTER */ -#ifdef DYNAMIC_SWOOB_DURATION -#ifndef CUSTOM_INTR_WIDTH -#define CUSTOM_INTR_WIDTH 100 - int intr_width = 0; -#endif /* CUSTOM_INTR_WIDTH */ -#endif /* DYNAMIC_SWOOB_DURATION */ - -#if defined(BCMPCIE) - int lpas = 0; - int dtim_period = 0; - int bcn_interval = 0; - int bcn_to_dly = 0; -#ifndef CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND - int bcn_timeout = CUSTOM_BCN_TIMEOUT_SETTING; -#else - bcn_timeout = CUSTOM_BCN_TIMEOUT_SETTING; -#endif /* CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND */ -#endif /* OEM_ANDROID && BCMPCIE */ - - if (!dhd) - return -ENODEV; - -#ifdef PASS_ALL_MCAST_PKTS - dhdinfo = dhd->info; -#endif /* PASS_ALL_MCAST_PKTS */ - - DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n", - __FUNCTION__, value, dhd->in_suspend)); - - dhd_suspend_lock(dhd); - -#ifdef CUSTOM_SET_CPUCORE - DHD_TRACE(("%s set cpucore(suspend%d)\n", __FUNCTION__, value)); - /* set specific cpucore */ - dhd_set_cpucore(dhd, TRUE); -#endif /* CUSTOM_SET_CPUCORE */ - - if (dhd->conf->pm >= 0) - power_mode = dhd->conf->pm; - else - power_mode = PM_FAST; - - if (dhd->up) { - if (value && dhd->in_suspend) { -#ifdef PKT_FILTER_SUPPORT - dhd->early_suspended = 1; -#endif - /* Kernel suspended */ - DHD_ERROR(("%s: force extra suspend setting\n", __FUNCTION__)); - - if (dhd->conf->pm_in_suspend >= 0) - power_mode = dhd->conf->pm_in_suspend; - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, - sizeof(power_mode), TRUE, 0); - -#ifdef PKT_FILTER_SUPPORT - /* Enable packet filter, - * only allow unicast packet to send up - */ - dhd_enable_packet_filter(1, dhd); -#ifdef APF - dhd_dev_apf_enable_filter(dhd_linux_get_primary_netdev(dhd)); -#endif /* APF */ -#endif /* PKT_FILTER_SUPPORT */ - -#ifdef SUPPORT_SENSORHUB - shub_ctl.enable = 1; - shub_ctl.cmd = 0x000; - shub_ctl.op_mode = 1; - shub_ctl.interval = 0; - if (dhd->info->shub_enable == 1) { - ret = dhd_iovar(dhd, 0, "shub_msreq", - (char *)&shub_ctl, sizeof(shub_ctl), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s SensorHub MS start: failed %d\n", - __FUNCTION__, ret)); - } - } -#endif /* SUPPORT_SENSORHUB */ - - -#ifdef PASS_ALL_MCAST_PKTS - allmulti = 0; - for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net) - dhd_iovar(dhd, i, "allmulti", (char *)&allmulti, - sizeof(allmulti), NULL, 0, TRUE); - - } -#endif /* PASS_ALL_MCAST_PKTS */ - - /* If DTIM skip is set up as default, force it to wake - * each third DTIM for better power savings. Note that - * one side effect is a chance to miss BC/MC packet. - */ -#ifdef WLTDLS - /* Do not set bcn_li_ditm on WFD mode */ - if (dhd->tdls_mode) { - bcn_li_dtim = 0; - } else -#endif /* WLTDLS */ -#if defined(BCMPCIE) - bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd, &dtim_period, - &bcn_interval); - dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, - sizeof(bcn_li_dtim), NULL, 0, TRUE); - - if ((bcn_li_dtim * dtim_period * bcn_interval) >= - MIN_DTIM_FOR_ROAM_THRES_EXTEND) { - /* - * Increase max roaming threshold from 2 secs to 8 secs - * the real roam threshold is MIN(max_roam_threshold, - * bcn_timeout/2) - */ - lpas = 1; - dhd_iovar(dhd, 0, "lpas", (char *)&lpas, sizeof(lpas), NULL, - 0, TRUE); - - bcn_to_dly = 1; - /* - * if bcn_to_dly is 1, the real roam threshold is - * MIN(max_roam_threshold, bcn_timeout -1); - * notify link down event after roaming procedure complete - * if we hit bcn_timeout while we are in roaming progress. - */ - dhd_iovar(dhd, 0, "bcn_to_dly", (char *)&bcn_to_dly, - sizeof(bcn_to_dly), NULL, 0, TRUE); - /* Increase beacon timeout to 6 secs or use bigger one */ - bcn_timeout = max(bcn_timeout, BCN_TIMEOUT_IN_SUSPEND); - dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, - sizeof(bcn_timeout), NULL, 0, TRUE); - } -#else - bcn_li_dtim = dhd_get_suspend_bcn_li_dtim(dhd); - if (dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, - sizeof(bcn_li_dtim), NULL, 0, TRUE) < 0) - DHD_ERROR(("%s: set dtim failed\n", __FUNCTION__)); -#endif /* OEM_ANDROID && BCMPCIE */ - -#ifdef DHD_USE_EARLYSUSPEND -#ifdef CUSTOM_BCN_TIMEOUT_IN_SUSPEND - bcn_timeout = CUSTOM_BCN_TIMEOUT_IN_SUSPEND; - dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, - sizeof(bcn_timeout), NULL, 0, TRUE); -#endif /* CUSTOM_BCN_TIMEOUT_IN_SUSPEND */ -#ifdef CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND - roam_time_thresh = CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND; - dhd_iovar(dhd, 0, "roam_time_thresh", (char *)&roam_time_thresh, - sizeof(roam_time_thresh), NULL, 0, TRUE); -#endif /* CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND */ -#ifndef ENABLE_FW_ROAM_SUSPEND - /* Disable firmware roaming during suspend */ - dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), - NULL, 0, TRUE); -#endif /* ENABLE_FW_ROAM_SUSPEND */ -#ifdef ENABLE_BCN_LI_BCN_WAKEUP - bcn_li_bcn = 0; - dhd_iovar(dhd, 0, "bcn_li_bcn", (char *)&bcn_li_bcn, - sizeof(bcn_li_bcn), NULL, 0, TRUE); -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ -#ifdef NDO_CONFIG_SUPPORT - if (dhd->ndo_enable) { - if (!dhd->ndo_host_ip_overflow) { - /* enable ND offload on suspend */ - ret = dhd_ndo_enable(dhd, 1); - if (ret < 0) { - DHD_ERROR(("%s: failed to enable NDO\n", - __FUNCTION__)); - } - } else { - DHD_INFO(("%s: NDO disabled on suspend due to" - "HW capacity\n", __FUNCTION__)); - } - } -#endif /* NDO_CONFIG_SUPPORT */ -#ifndef APF - if (FW_SUPPORTED(dhd, ndoe)) -#else - if (FW_SUPPORTED(dhd, ndoe) && !FW_SUPPORTED(dhd, apf)) -#endif /* APF */ - { - /* enable IPv6 RA filter in firmware during suspend */ - nd_ra_filter = 1; - ret = dhd_iovar(dhd, 0, "nd_ra_filter_enable", - (char *)&nd_ra_filter, sizeof(nd_ra_filter), - NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("failed to set nd_ra_filter (%d)\n", - ret)); - } - dhd_os_suppress_logging(dhd, TRUE); -#ifdef ENABLE_IPMCAST_FILTER - ipmcast_l2filter = 1; - ret = dhd_iovar(dhd, 0, "ipmcast_l2filter", - (char *)&ipmcast_l2filter, sizeof(ipmcast_l2filter), - NULL, 0, TRUE); -#endif /* ENABLE_IPMCAST_FILTER */ -#ifdef DYNAMIC_SWOOB_DURATION - intr_width = CUSTOM_INTR_WIDTH; - ret = dhd_iovar(dhd, 0, "bus:intr_width", (char *)&intr_width, - sizeof(intr_width), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("failed to set intr_width (%d)\n", ret)); - } -#endif /* DYNAMIC_SWOOB_DURATION */ -#endif /* DHD_USE_EARLYSUSPEND */ - dhd_conf_set_ap_in_suspend(dhd, value); - } else { - dhd_conf_set_ap_in_suspend(dhd, value); -#ifdef PKT_FILTER_SUPPORT - dhd->early_suspended = 0; -#endif - /* Kernel resumed */ - DHD_ERROR(("%s: Remove extra suspend setting \n", __FUNCTION__)); - -#ifdef SUPPORT_SENSORHUB - shub_ctl.enable = 1; - shub_ctl.cmd = 0x000; - shub_ctl.op_mode = 0; - shub_ctl.interval = 0; - if (dhd->info->shub_enable == 1) { - ret = dhd_iovar(dhd, 0, "shub_msreq", - (char *)&shub_ctl, sizeof(shub_ctl), - NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s SensorHub MS stop: failed %d\n", - __FUNCTION__, ret)); - } - } -#endif /* SUPPORT_SENSORHUB */ - -#ifdef DYNAMIC_SWOOB_DURATION - intr_width = 0; - ret = dhd_iovar(dhd, 0, "bus:intr_width", (char *)&intr_width, - sizeof(intr_width), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("failed to set intr_width (%d)\n", ret)); - } -#endif /* DYNAMIC_SWOOB_DURATION */ -#ifndef SUPPORT_PM2_ONLY - power_mode = PM_FAST; - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, - sizeof(power_mode), TRUE, 0); -#endif /* SUPPORT_PM2_ONLY */ -#ifdef PKT_FILTER_SUPPORT - /* disable pkt filter */ - dhd_enable_packet_filter(0, dhd); -#ifdef APF - dhd_dev_apf_disable_filter(dhd_linux_get_primary_netdev(dhd)); -#endif /* APF */ -#endif /* PKT_FILTER_SUPPORT */ -#ifdef PASS_ALL_MCAST_PKTS - allmulti = 1; - for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhdinfo->iflist[i] && dhdinfo->iflist[i]->net) - dhd_iovar(dhd, i, "allmulti", (char *)&allmulti, - sizeof(allmulti), NULL, 0, TRUE); - } -#endif /* PASS_ALL_MCAST_PKTS */ -#if defined(BCMPCIE) - /* restore pre-suspend setting */ - ret = dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, - sizeof(bcn_li_dtim), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s:bcn_li_ditm fail:%d\n", __FUNCTION__, ret)); - } - - dhd_iovar(dhd, 0, "lpas", (char *)&lpas, sizeof(lpas), NULL, 0, - TRUE); - - dhd_iovar(dhd, 0, "bcn_to_dly", (char *)&bcn_to_dly, - sizeof(bcn_to_dly), NULL, 0, TRUE); - - dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, - sizeof(bcn_timeout), NULL, 0, TRUE); -#else - /* restore pre-suspend setting for dtim_skip */ - ret = dhd_iovar(dhd, 0, "bcn_li_dtim", (char *)&bcn_li_dtim, - sizeof(bcn_li_dtim), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s:bcn_li_ditm fail:%d\n", __FUNCTION__, ret)); - } -#endif /* OEM_ANDROID && BCMPCIE */ -#ifdef DHD_USE_EARLYSUSPEND -#ifdef CUSTOM_BCN_TIMEOUT_IN_SUSPEND - bcn_timeout = CUSTOM_BCN_TIMEOUT; - dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, - sizeof(bcn_timeout), NULL, 0, TRUE); -#endif /* CUSTOM_BCN_TIMEOUT_IN_SUSPEND */ -#ifdef CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND - roam_time_thresh = 2000; - dhd_iovar(dhd, 0, "roam_time_thresh", (char *)&roam_time_thresh, - sizeof(roam_time_thresh), NULL, 0, TRUE); - -#endif /* CUSTOM_ROAM_TIME_THRESH_IN_SUSPEND */ -#ifndef ENABLE_FW_ROAM_SUSPEND - roamvar = dhd_roam_disable; - dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), - NULL, 0, TRUE); -#endif /* ENABLE_FW_ROAM_SUSPEND */ -#ifdef ENABLE_BCN_LI_BCN_WAKEUP - bcn_li_bcn = 1; - dhd_iovar(dhd, 0, "bcn_li_bcn", (char *)&bcn_li_bcn, - sizeof(bcn_li_bcn), NULL, 0, TRUE); -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ -#ifdef NDO_CONFIG_SUPPORT - if (dhd->ndo_enable) { - /* Disable ND offload on resume */ - ret = dhd_ndo_enable(dhd, 0); - if (ret < 0) { - DHD_ERROR(("%s: failed to disable NDO\n", - __FUNCTION__)); - } - } -#endif /* NDO_CONFIG_SUPPORT */ -#ifndef APF - if (FW_SUPPORTED(dhd, ndoe)) -#else - if (FW_SUPPORTED(dhd, ndoe) && !FW_SUPPORTED(dhd, apf)) -#endif /* APF */ - { - /* disable IPv6 RA filter in firmware during suspend */ - nd_ra_filter = 0; - ret = dhd_iovar(dhd, 0, "nd_ra_filter_enable", - (char *)&nd_ra_filter, sizeof(nd_ra_filter), - NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("failed to set nd_ra_filter (%d)\n", - ret)); - } - } - dhd_os_suppress_logging(dhd, FALSE); -#ifdef ENABLE_IPMCAST_FILTER - ipmcast_l2filter = 0; - ret = dhd_iovar(dhd, 0, "ipmcast_l2filter", - (char *)&ipmcast_l2filter, sizeof(ipmcast_l2filter), - NULL, 0, TRUE); -#endif /* ENABLE_IPMCAST_FILTER */ -#endif /* DHD_USE_EARLYSUSPEND */ - - /* terence 2017029: Reject in early suspend */ - if (!dhd->conf->xmit_in_suspend) { - dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); - } - } - } - dhd_suspend_unlock(dhd); - - return 0; -} - -static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force) -{ - dhd_pub_t *dhdp = &dhd->pub; - int ret = 0; - - DHD_OS_WAKE_LOCK(dhdp); - DHD_PERIM_LOCK(dhdp); - - /* Set flag when early suspend was called */ - dhdp->in_suspend = val; - if ((force || !dhdp->suspend_disable_flag) && - (dhd_support_sta_mode(dhdp) || dhd_conf_get_ap_mode_in_suspend(dhdp))) - { - ret = dhd_set_suspend(val, dhdp); - } - - DHD_PERIM_UNLOCK(dhdp); - DHD_OS_WAKE_UNLOCK(dhdp); - return ret; -} - -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) -static void dhd_early_suspend(struct early_suspend *h) -{ - struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); - DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__)); - - if (dhd) - dhd_suspend_resume_helper(dhd, 1, 0); -} - -static void dhd_late_resume(struct early_suspend *h) -{ - struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); - DHD_TRACE_HW4(("%s: enter\n", __FUNCTION__)); - - if (dhd) - dhd_suspend_resume_helper(dhd, 0, 0); -} -#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ - -/* - * Generalized timeout mechanism. Uses spin sleep with exponential back-off until - * the sleep time reaches one jiffy, then switches over to task delay. Usage: - * - * dhd_timeout_start(&tmo, usec); - * while (!dhd_timeout_expired(&tmo)) - * if (poll_something()) - * break; - * if (dhd_timeout_expired(&tmo)) - * fatal(); - */ - -void -dhd_timeout_start(dhd_timeout_t *tmo, uint usec) -{ - tmo->limit = usec; - tmo->increment = 0; - tmo->elapsed = 0; - tmo->tick = jiffies_to_usecs(1); -} - -int -dhd_timeout_expired(dhd_timeout_t *tmo) -{ - /* Does nothing the first call */ - if (tmo->increment == 0) { - tmo->increment = 1; - return 0; - } - - if (tmo->elapsed >= tmo->limit) - return 1; - - /* Add the delay that's about to take place */ - tmo->elapsed += tmo->increment; - - if ((!CAN_SLEEP()) || tmo->increment < tmo->tick) { - OSL_DELAY(tmo->increment); - tmo->increment *= 2; - if (tmo->increment > tmo->tick) - tmo->increment = tmo->tick; - } else { - wait_queue_head_t delay_wait; - DECLARE_WAITQUEUE(wait, current); - init_waitqueue_head(&delay_wait); - add_wait_queue(&delay_wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - (void)schedule_timeout(1); - remove_wait_queue(&delay_wait, &wait); - set_current_state(TASK_RUNNING); - } - - return 0; -} - -int -dhd_ifindex2idx(dhd_info_t *dhd, int ifindex) -{ - int i = 0; - - if (!dhd) { - DHD_ERROR(("%s : DHD_BAD_IF return\n", __FUNCTION__)); - return DHD_BAD_IF; - } - - while (i < DHD_MAX_IFS) { - if (dhd->iflist[i] && dhd->iflist[i]->net && - (dhd->iflist[i]->net->ifindex == ifindex)) - return i; - i++; - } - - return DHD_BAD_IF; -} - -int -dhd_net2idx(dhd_info_t *dhd, struct net_device *net) -{ - int i = 0; - - if (!dhd) { - DHD_ERROR(("%s : DHD_BAD_IF return\n", __FUNCTION__)); - return DHD_BAD_IF; - } - - while (i < DHD_MAX_IFS) { - if (dhd->iflist[i] && dhd->iflist[i]->net && (dhd->iflist[i]->net == net)) - return i; - i++; - } - - return DHD_BAD_IF; -} - -struct net_device * dhd_idx2net(void *pub, int ifidx) -{ - struct dhd_pub *dhd_pub = (struct dhd_pub *)pub; - struct dhd_info *dhd_info; - - if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS) - return NULL; - dhd_info = dhd_pub->info; - if (dhd_info && dhd_info->iflist[ifidx]) - return dhd_info->iflist[ifidx]->net; - return NULL; -} - -int -dhd_ifname2idx(dhd_info_t *dhd, char *name) -{ - int i = DHD_MAX_IFS; - - ASSERT(dhd); - - if (name == NULL || *name == '\0') - return 0; - - while (--i > 0) - if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->dngl_name, name, IFNAMSIZ)) - break; - - DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name)); - - return i; /* default - the primary interface */ -} - -char * -dhd_ifname(dhd_pub_t *dhdp, int ifidx) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - - ASSERT(dhd); - - if (ifidx < 0 || ifidx >= DHD_MAX_IFS) { - DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx)); - return "<if_bad>"; - } - - if (dhd->iflist[ifidx] == NULL) { - DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx)); - return "<if_null>"; - } - - if (dhd->iflist[ifidx]->net) - return dhd->iflist[ifidx]->net->name; - - return "<if_none>"; -} - -uint8 * -dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx) -{ - int i; - dhd_info_t *dhd = (dhd_info_t *)dhdp; - - ASSERT(dhd); - for (i = 0; i < DHD_MAX_IFS; i++) - if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx) - return dhd->iflist[i]->mac_addr; - - return NULL; -} - - -static void -_dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) -{ - struct net_device *dev; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) - struct netdev_hw_addr *ha; -#else - struct dev_mc_list *mclist; -#endif - uint32 allmulti, cnt; - - wl_ioctl_t ioc; - char *buf, *bufp; - uint buflen; - int ret; - - if (!dhd->iflist[ifidx]) { - DHD_ERROR(("%s : dhd->iflist[%d] was NULL\n", __FUNCTION__, ifidx)); - return; - } - dev = dhd->iflist[ifidx]->net; - if (!dev) - return; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_lock_bh(dev); -#endif /* LINUX >= 2.6.27 */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) - cnt = netdev_mc_count(dev); -#else - cnt = dev->mc_count; -#endif /* LINUX >= 2.6.35 */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_unlock_bh(dev); -#endif /* LINUX >= 2.6.27 */ - - /* Determine initial value of allmulti flag */ - allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; - -#ifdef PASS_ALL_MCAST_PKTS -#ifdef PKT_FILTER_SUPPORT - if (!dhd->pub.early_suspended) -#endif /* PKT_FILTER_SUPPORT */ - allmulti = TRUE; -#endif /* PASS_ALL_MCAST_PKTS */ - - /* Send down the multicast list first. */ - - - buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN); - if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) { - DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n", - dhd_ifname(&dhd->pub, ifidx), cnt)); - return; - } - - strncpy(bufp, "mcast_list", buflen - 1); - bufp[buflen - 1] = '\0'; - bufp += strlen("mcast_list") + 1; - - cnt = htol32(cnt); - memcpy(bufp, &cnt, sizeof(cnt)); - bufp += sizeof(cnt); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_lock_bh(dev); -#endif /* LINUX >= 2.6.27 */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - netdev_for_each_mc_addr(ha, dev) { - if (!cnt) - break; - memcpy(bufp, ha->addr, ETHER_ADDR_LEN); - bufp += ETHER_ADDR_LEN; - cnt--; - } -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif -#else /* LINUX < 2.6.35 */ - for (mclist = dev->mc_list; (mclist && (cnt > 0)); - cnt--, mclist = mclist->next) { - memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); - bufp += ETHER_ADDR_LEN; - } -#endif /* LINUX >= 2.6.35 */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_unlock_bh(dev); -#endif /* LINUX >= 2.6.27 */ - - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = buflen; - ioc.set = TRUE; - - ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); - if (ret < 0) { - DHD_ERROR(("%s: set mcast_list failed, cnt %d\n", - dhd_ifname(&dhd->pub, ifidx), cnt)); - allmulti = cnt ? TRUE : allmulti; - } - - MFREE(dhd->pub.osh, buf, buflen); - - /* Now send the allmulti setting. This is based on the setting in the - * net_device flags, but might be modified above to be turned on if we - * were trying to set some addresses and dongle rejected it... - */ - - allmulti = htol32(allmulti); - ret = dhd_iovar(&dhd->pub, ifidx, "allmulti", (char *)&allmulti, - sizeof(allmulti), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: set allmulti %d failed\n", - dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); - } - - /* Finally, pick up the PROMISC flag as well, like the NIC driver does */ - - allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE; - - allmulti = htol32(allmulti); - - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = WLC_SET_PROMISC; - ioc.buf = &allmulti; - ioc.len = sizeof(allmulti); - ioc.set = TRUE; - - ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); - if (ret < 0) { - DHD_ERROR(("%s: set promisc %d failed\n", - dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); - } -} - -#ifdef BCOL_TCPKA_SYNC -int dhd_get_tcpka_session_id(dhd_pub_t *pub) -{ - int sess_id = -1; - - /* get the right tcpka_conn for IPv6 or IPv4 */ - if (tcpka_sync.sess_type) { - if (tcpka_sync.tcpka6_conn) - sess_id = tcpka_sync.tcpka6_conn->sess_id; - } else { - if (tcpka_sync.tcpka_conn) - sess_id = tcpka_sync.tcpka_conn->sess_id; - } - if (sess_id == -1) { - DHD_ERROR(("%s: Can not get IPv%s session id\n", __func__, tcpka_sync.sess_type ? "6":"4")); - } - return sess_id; -} - -int -_dhd_sync_bcol_tcpka(dhd_info_t *dhd) -{ - char *iovbuf; - dhd_pub_t *dhdp; - uint32 sess_id; - int ret = 0, buflen = WLC_IOCTL_MEDLEN; - tcpka_conn_sess_t *pconn_sess; - tcpka_conn_sess_t default_conn_sess; - - dhdp = &dhd->pub; - if (!tcpka_sync.tcpka_iovbuf) { - DHD_ERROR(("%s: tcpka iov buffer is null\n", __func__)); - ret = BCME_ERROR; - goto exit; - } - - sess_id = dhd_get_tcpka_session_id(dhdp); - if (!sess_id) { - DHD_ERROR(("%s: session id is invaild(%d)\n", __func__, sess_id)); - ret = BCME_ERROR; - goto exit; - } - - iovbuf = kzalloc(buflen, GFP_KERNEL); - memset(iovbuf, 0, buflen); - bcm_mkiovar("tcpka_conn_del", (char *)&sess_id, 4, iovbuf, buflen); - ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, buflen, TRUE, 0); - if (ret < 0) { - DHD_ERROR(("%s: set tcpka_conn_del %d failed\n", __func__, sess_id)); - } - - /* do tcpka_conn_add */ - memset(iovbuf, 0, buflen); - bcopy(tcpka_sync.tcpka_iovbuf, (char *)iovbuf, tcpka_sync.tcpka_iovbuf_len); - ret = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, tcpka_sync.tcpka_iovbuf_len, - FALSE, 0); - if (ret < 0) { - DHD_ERROR(("%s: set tcpka_conn_add failed\n", __func__)); - ret = BCME_ERROR; - goto exit; - } - - memset(iovbuf, 0, buflen); - - if (tcpka_sync.tcpka_en_info && (tcpka_sync.tcpka_en_info->sess_id == sess_id)) { - pconn_sess = tcpka_sync.tcpka_en_info; - } else { - if (tcpka_sync.tcpka_en_info && tcpka_sync.tcpka_en_info->sess_id != sess_id) { - DHD_ERROR(("%s: session id mismatch with tcpka_en_info!\n", __func__)); - dhd_bcol_dump_tcpka_conn_sess(tcpka_sync.tcpka_en_info); - } - default_conn_sess.sess_id = sess_id; - default_conn_sess.flag = 1; - default_conn_sess.tcp_keepalive_timers.interval = 10; - default_conn_sess.tcp_keepalive_timers.retry_interval = 2; - default_conn_sess.tcp_keepalive_timers.retry_count = 2; - /* use default value */ - pconn_sess = &default_conn_sess; - DHD_ERROR(("%s: use default conn session info for enabling\n", __func__)); - } - bcm_mkiovar("tcpka_conn_enable", (char *)pconn_sess, sizeof(tcpka_conn_sess_t), - iovbuf, buflen); - ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, buflen, TRUE, 0); - if (ret < 0) { - DHD_ERROR(("%s: set tcpka_conn_enable %d failed\n", __func__, sess_id)); - ret = BCME_ERROR; - goto exit; - } - - ret = dhd_iovar(dhdp, 0, "tcpka_conn_repair_block", - (char *)&tcpka_sync.tcpka_repair_block, - sizeof(tcpka_sync.tcpka_repair_block), NULL, 0, TRUE); - if (ret != BCME_OK) { - DHD_ERROR(("%s: Failed to set tcpka_conn_repair_block to %d, err %d\n", - __FUNCTION__, tcpka_sync.tcpka_repair_block, ret)); - } - - /* config done, set sync state to done */ - tcpka_sync.tcpka_sync_state = BCOL_TCPKA_SYNC_STATE_DONE; - - if (tcpka_sync.tcpka_act_buf) { - memset(iovbuf, 0, buflen); - bcm_mkiovar("tcpka_pkt_handle", (char *)tcpka_sync.tcpka_act_buf, - tcpka_sync.tcpka_act_buf_len, iovbuf, buflen); - ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, buflen, TRUE, 0); - if (ret < 0) { - DHD_ERROR(("%s: set tcpka_act failed: %d, len %d\n", - __func__, ret, tcpka_sync.tcpka_act_buf_len)); - } - } - - if (tcpka_sync.sess_type) { - DHD_ERROR(("%s: seq %u ack %u\n", __func__, tcpka_sync.tcpka6_conn->seq, - tcpka_sync.tcpka6_conn->ack)); - dhd_bcol_dump_tcpka6_conn(tcpka_sync.tcpka6_conn); - } else { - DHD_ERROR(("%s: seq %u ack %u\n", __func__, tcpka_sync.tcpka_conn->seq, - tcpka_sync.tcpka_conn->ack)); - /* print out more information when seq = 0 */ - if (tcpka_sync.tcpka_conn->seq == 0) { - DHD_ERROR(("window=%u, tsval=%u, tsecr=%u, last_payload_len=%u\n", - tcpka_sync.tcpka_conn->tcpwin, tcpka_sync.tcpka_conn->tsval, - tcpka_sync.tcpka_conn->tsecr, tcpka_sync.tcpka_conn->last_payload_len)); - } - dhd_bcol_dump_tcpka_conn(tcpka_sync.tcpka_conn); - } - if (tcpka_sync.tcpka_noti_buf) { - memset(iovbuf, 0, buflen); - bcm_mkiovar("tcpka_noti_add", (char *)tcpka_sync.tcpka_noti_buf, - tcpka_sync.tcpka_noti_buf_len, iovbuf, buflen); - ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, buflen, TRUE, 0); - DHD_ERROR(("%s: set tcpka_noti: %d, len %d\n", __func__, ret, - tcpka_sync.tcpka_noti_buf_len)); - } - -exit: - kfree(iovbuf); - return ret; -} -#endif /* BCOL_TCPKA_SYNC */ - -int -_dhd_set_mac_address(dhd_info_t *dhd, int ifidx, uint8 *addr) -{ - int ret; - - ret = dhd_iovar(&dhd->pub, ifidx, "cur_etheraddr", (char *)addr, - ETHER_ADDR_LEN, NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx))); - } else { - memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN); - if (ifidx == 0) { - memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN); - memcpy(g_dev_addr.octet, addr, ETHER_ADDR_LEN); - } - } - - return ret; -} - -#ifdef SOFTAP -extern struct net_device *ap_net_dev; -extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */ -#endif - -#ifdef DHD_WMF -void dhd_update_psta_interface_for_sta(dhd_pub_t* dhdp, char* ifname, void* ea, - void* event_data) -{ - struct wl_psta_primary_intf_event *psta_prim_event = - (struct wl_psta_primary_intf_event*)event_data; - dhd_sta_t *psta_interface = NULL; - dhd_sta_t *sta = NULL; - uint8 ifindex; - ASSERT(ifname); - ASSERT(psta_prim_event); - ASSERT(ea); - - ifindex = (uint8)dhd_ifname2idx(dhdp->info, ifname); - sta = dhd_find_sta(dhdp, ifindex, ea); - if (sta != NULL) { - psta_interface = dhd_find_sta(dhdp, ifindex, - (void *)(psta_prim_event->prim_ea.octet)); - if (psta_interface != NULL) { - sta->psta_prim = psta_interface; - } - } -} - -/* Get wmf_psta_disable configuration configuration */ -int dhd_get_wmf_psta_disable(dhd_pub_t *dhdp, uint32 idx) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - ASSERT(idx < DHD_MAX_IFS); - ifp = dhd->iflist[idx]; - return ifp->wmf_psta_disable; -} - -/* Set wmf_psta_disable configuration configuration */ -int dhd_set_wmf_psta_disable(dhd_pub_t *dhdp, uint32 idx, int val) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - ASSERT(idx < DHD_MAX_IFS); - ifp = dhd->iflist[idx]; - ifp->wmf_psta_disable = val; - return 0; -} -#endif /* DHD_WMF */ - -#ifdef DHD_PSTA -/* Get psta/psr configuration configuration */ -int dhd_get_psta_mode(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = dhdp->info; - return (int)dhd->psta_mode; -} -/* Set psta/psr configuration configuration */ -int dhd_set_psta_mode(dhd_pub_t *dhdp, uint32 val) -{ - dhd_info_t *dhd = dhdp->info; - dhd->psta_mode = val; - return 0; -} -#endif /* DHD_PSTA */ - -#if (defined(DHD_WET) || defined(DHD_MCAST_REGEN) || defined(DHD_L2_FILTER)) -static void -dhd_update_rx_pkt_chainable_state(dhd_pub_t* dhdp, uint32 idx) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - - ASSERT(idx < DHD_MAX_IFS); - - ifp = dhd->iflist[idx]; - - if ( -#ifdef DHD_L2_FILTER - (ifp->block_ping) || -#endif -#ifdef DHD_WET - (dhd->wet_mode) || -#endif -#ifdef DHD_MCAST_REGEN - (ifp->mcast_regen_bss_enable) || -#endif - FALSE) { - ifp->rx_pkt_chainable = FALSE; - } -} -#endif /* DHD_WET || DHD_MCAST_REGEN || DHD_L2_FILTER */ - -#ifdef DHD_WET -/* Get wet configuration configuration */ -int dhd_get_wet_mode(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = dhdp->info; - return (int)dhd->wet_mode; -} - -/* Set wet configuration configuration */ -int dhd_set_wet_mode(dhd_pub_t *dhdp, uint32 val) -{ - dhd_info_t *dhd = dhdp->info; - dhd->wet_mode = val; - dhd_update_rx_pkt_chainable_state(dhdp, 0); - return 0; -} -#endif /* DHD_WET */ - -#if defined(WL_CFG80211) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) -int32 dhd_role_to_nl80211_iftype(int32 role) -{ - switch (role) { - case WLC_E_IF_ROLE_STA: - return NL80211_IFTYPE_STATION; - case WLC_E_IF_ROLE_AP: - return NL80211_IFTYPE_AP; - case WLC_E_IF_ROLE_WDS: - return NL80211_IFTYPE_WDS; - case WLC_E_IF_ROLE_P2P_GO: - return NL80211_IFTYPE_P2P_GO; - case WLC_E_IF_ROLE_P2P_CLIENT: - return NL80211_IFTYPE_P2P_CLIENT; - case WLC_E_IF_ROLE_IBSS: - case WLC_E_IF_ROLE_NAN: - return NL80211_IFTYPE_ADHOC; - default: - return NL80211_IFTYPE_UNSPECIFIED; - } -} -#endif /* WL_CFG80211 && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ - -static void -dhd_ifadd_event_handler(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - dhd_if_event_t *if_event = event_info; - struct net_device *ndev; - int ifidx, bssidx; - int ret; -#if defined(WL_CFG80211) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) - struct wl_if_event_info info; -#endif /* WL_CFG80211 && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ - - if (event != DHD_WQ_WORK_IF_ADD) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - if (!if_event) { - DHD_ERROR(("%s: event data is null \n", __FUNCTION__)); - return; - } - - dhd_net_if_lock_local(dhd); - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - - ifidx = if_event->event.ifidx; - bssidx = if_event->event.bssidx; - DHD_TRACE(("%s: registering if with ifidx %d\n", __FUNCTION__, ifidx)); - - -#if defined(WL_CFG80211) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) - if (if_event->event.ifidx > 0) { - bzero(&info, sizeof(info)); - info.ifidx = if_event->event.ifidx; - info.bssidx = if_event->event.bssidx; - info.role = if_event->event.role; - strncpy(info.name, if_event->name, IFNAMSIZ); - if (wl_cfg80211_post_ifcreate(dhd->pub.info->iflist[0]->net, - &info, if_event->mac, NULL, true) != NULL) { - /* Do the post interface create ops */ - DHD_ERROR(("Post ifcreate ops done. Returning \n")); - goto done; - } - } -#endif /* WL_CFG80211 && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ - - /* This path is for non-android case */ - /* The interface name in host and in event msg are same */ - /* if name in event msg is used to create dongle if list on host */ - ndev = dhd_allocate_if(&dhd->pub, ifidx, if_event->name, - if_event->mac, bssidx, TRUE, if_event->name); - if (!ndev) { - DHD_ERROR(("%s: net device alloc failed \n", __FUNCTION__)); - goto done; - } - - DHD_PERIM_UNLOCK(&dhd->pub); - ret = dhd_register_if(&dhd->pub, ifidx, TRUE); - DHD_PERIM_LOCK(&dhd->pub); - if (ret != BCME_OK) { - DHD_ERROR(("%s: dhd_register_if failed\n", __FUNCTION__)); - dhd_remove_if(&dhd->pub, ifidx, TRUE); - goto done; - } -#ifndef PCIE_FULL_DONGLE - /* Turn on AP isolation in the firmware for interfaces operating in AP mode */ - if (FW_SUPPORTED((&dhd->pub), ap) && (if_event->event.role != WLC_E_IF_ROLE_STA)) { - uint32 var_int = 1; - ret = dhd_iovar(&dhd->pub, ifidx, "ap_isolate", (char *)&var_int, sizeof(var_int), - NULL, 0, TRUE); - if (ret != BCME_OK) { - DHD_ERROR(("%s: Failed to set ap_isolate to dongle\n", __FUNCTION__)); - dhd_remove_if(&dhd->pub, ifidx, TRUE); - } - } -#endif /* PCIE_FULL_DONGLE */ - -done: - MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); - - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - dhd_net_if_unlock_local(dhd); -} - -static void -dhd_ifdel_event_handler(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - int ifidx; - dhd_if_event_t *if_event = event_info; - - - if (event != DHD_WQ_WORK_IF_DEL) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - if (!if_event) { - DHD_ERROR(("%s: event data is null \n", __FUNCTION__)); - return; - } - - dhd_net_if_lock_local(dhd); - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - - ifidx = if_event->event.ifidx; - DHD_TRACE(("Removing interface with idx %d\n", ifidx)); - - DHD_PERIM_UNLOCK(&dhd->pub); -#if defined(WL_CFG80211) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) - if (if_event->event.ifidx > 0) { - /* Do the post interface del ops */ - if (wl_cfg80211_post_ifdel(dhd->pub.info->iflist[ifidx]->net, true) == 0) { - DHD_TRACE(("Post ifdel ops done. Returning \n")); - DHD_PERIM_LOCK(&dhd->pub); - goto done; - } - } -#endif /* WL_CFG80211 && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ - - dhd_remove_if(&dhd->pub, ifidx, TRUE); - DHD_PERIM_LOCK(&dhd->pub); - -#if defined(WL_CFG80211) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)) -done: -#endif /* WL_CFG80211 && LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0) */ - MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); - - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - dhd_net_if_unlock_local(dhd); -} - -#ifdef DHD_UPDATE_INTF_MAC -static void -dhd_ifupdate_event_handler(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - int ifidx; - dhd_if_event_t *if_event = event_info; - - if (event != DHD_WQ_WORK_IF_UPDATE) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - if (!if_event) { - DHD_ERROR(("%s: event data is null \n", __FUNCTION__)); - return; - } - - dhd_net_if_lock_local(dhd); - DHD_OS_WAKE_LOCK(&dhd->pub); - - ifidx = if_event->event.ifidx; - DHD_TRACE(("%s: Update interface with idx %d\n", __FUNCTION__, ifidx)); - - dhd_op_if_update(&dhd->pub, ifidx); - - MFREE(dhd->pub.osh, if_event, sizeof(dhd_if_event_t)); - - DHD_OS_WAKE_UNLOCK(&dhd->pub); - dhd_net_if_unlock_local(dhd); -} - -int dhd_op_if_update(dhd_pub_t *dhdpub, int ifidx) -{ - dhd_info_t * dhdinfo = NULL; - dhd_if_t * ifp = NULL; - int ret = 0; - char buf[128]; - - if ((NULL==dhdpub)||(NULL==dhdpub->info)) { - DHD_ERROR(("%s: *** DHD handler is NULL!\n", __FUNCTION__)); - return -1; - } else { - dhdinfo = (dhd_info_t *)dhdpub->info; - ifp = dhdinfo->iflist[ifidx]; - if (NULL==ifp) { - DHD_ERROR(("%s: *** ifp handler is NULL!\n", __FUNCTION__)); - return -2; - } - } - - DHD_TRACE(("%s: idx %d\n", __FUNCTION__, ifidx)); - // Get MAC address - strcpy(buf, "cur_etheraddr"); - ret = dhd_wl_ioctl_cmd(&dhdinfo->pub, WLC_GET_VAR, buf, sizeof(buf), FALSE, ifp->idx); - if (0>ret) { - DHD_ERROR(("Failed to upudate the MAC address for itf=%s, ret=%d\n", ifp->name, ret)); - // avoid collision - dhdinfo->iflist[ifp->idx]->mac_addr[5] += 1; - // force locally administrate address - ETHER_SET_LOCALADDR(&dhdinfo->iflist[ifp->idx]->mac_addr); - } else { -#ifdef SIMPLE_MAC_PRINT - DHD_EVENT(("Got mac for itf %s, idx %d, MAC=%02X:XX:XX:XX:%02X:%02X\n", - ifp->name, ifp->idx, - (unsigned char)buf[0], (unsigned char)buf[4], (unsigned char)buf[5])); -#else - DHD_EVENT(("Got mac for itf %s, idx %d, MAC=%02X:%02X:%02X:%02X:%02X:%02X\n", - ifp->name, ifp->idx, - (unsigned char)buf[0], (unsigned char)buf[1], (unsigned char)buf[2], - (unsigned char)buf[3], (unsigned char)buf[4], (unsigned char)buf[5])); -#endif /* SIMPLE_MAC_PRINT */ - memcpy(dhdinfo->iflist[ifp->idx]->mac_addr, buf, ETHER_ADDR_LEN); - if (dhdinfo->iflist[ifp->idx]->net) { - memcpy(dhdinfo->iflist[ifp->idx]->net->dev_addr, buf, ETHER_ADDR_LEN); - } - } - - return ret; -} -#endif /* DHD_UPDATE_INTF_MAC */ - -#ifdef BCOL_TCPKA_SYNC -static void -dhd_sync_bcol_tcpka_conn_handler(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - - if (event != DHD_WQ_WORK_SYNC_BCOL_TCPKA_CONN) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - - if (!dhd->pub.up) { - DHD_ERROR(("%s: is not up\n", __FUNCTION__)); - goto done; - } - - if (_dhd_sync_bcol_tcpka(dhd) == BCME_OK) { - DHD_ERROR(("%s: BCOL TCPKA is sync\n", __FUNCTION__)); - } else { - DHD_ERROR(("%s: _dhd_sync_bcol_tcpka failed\n", __FUNCTION__)); - } - -done: - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); -} -#endif /* BCOL_TCPKA_SYNC */ - -static void -dhd_set_mac_addr_handler(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - dhd_if_t *ifp = event_info; - - if (event != DHD_WQ_WORK_SET_MAC) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - dhd_net_if_lock_local(dhd); - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - -#ifdef SOFTAP - { - unsigned long flags; - bool in_ap = FALSE; - DHD_GENERAL_LOCK(&dhd->pub, flags); - in_ap = (ap_net_dev != NULL); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - - if (in_ap) { - DHD_ERROR(("attempt to set MAC for %s in AP Mode, blocked. \n", - ifp->net->name)); - goto done; - } - } -#endif /* SOFTAP */ - - // terence 20160907: fix for not able to set mac when wlan0 is down - if (ifp == NULL || !ifp->set_macaddress) { - goto done; - } - if (!dhd_download_fw_on_driverload && !dhd->pub.up) { - DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__)); - goto done; - } - - DHD_INFO(("%s: MACID is overwritting\n", __FUNCTION__)); - ifp->set_macaddress = FALSE; - if (_dhd_set_mac_address(dhd, ifp->idx, ifp->mac_addr) == 0) - DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__)); - else - DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__)); - -done: - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - dhd_net_if_unlock_local(dhd); -} - -static void -dhd_set_mcast_list_handler(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - int ifidx = (int)((long int)event_info); - dhd_if_t *ifp = NULL; - - if (event != DHD_WQ_WORK_SET_MCAST_LIST) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - dhd_net_if_lock_local(dhd); - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - - ifp = dhd->iflist[ifidx]; - - if (ifp == NULL || !dhd->pub.up) { - DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__)); - goto done; - } - -#ifdef SOFTAP - { - bool in_ap = FALSE; - unsigned long flags; - DHD_GENERAL_LOCK(&dhd->pub, flags); - in_ap = (ap_net_dev != NULL); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - - if (in_ap) { - DHD_ERROR(("set MULTICAST list for %s in AP Mode, blocked. \n", - ifp->net->name)); - ifp->set_multicast = FALSE; - goto done; - } - } -#endif /* SOFTAP */ - - if (ifp == NULL || !dhd->pub.up) { - DHD_ERROR(("%s: interface info not available/down \n", __FUNCTION__)); - goto done; - } - - ifidx = ifp->idx; - - - _dhd_set_multicast_list(dhd, ifidx); - DHD_INFO(("%s: set multicast list for if %d\n", __FUNCTION__, ifidx)); - -done: - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - dhd_net_if_unlock_local(dhd); -} - -static int -dhd_set_mac_address(struct net_device *dev, void *addr) -{ - int ret = 0; - - dhd_info_t *dhd = DHD_DEV_INFO(dev); - struct sockaddr *sa = (struct sockaddr *)addr; - int ifidx; - dhd_if_t *dhdif; - - ifidx = dhd_net2idx(dhd, dev); - if (ifidx == DHD_BAD_IF) - return -1; - - dhdif = dhd->iflist[ifidx]; - - dhd_net_if_lock_local(dhd); - memcpy(dhdif->mac_addr, sa->sa_data, ETHER_ADDR_LEN); - dhdif->set_macaddress = TRUE; - dhd_net_if_unlock_local(dhd); - dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhdif, DHD_WQ_WORK_SET_MAC, - dhd_set_mac_addr_handler, DHD_WQ_WORK_PRIORITY_LOW); - return ret; -} - -static void -dhd_set_multicast_list(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ifidx; - - ifidx = dhd_net2idx(dhd, dev); - if (ifidx == DHD_BAD_IF) - return; - - dhd->iflist[ifidx]->set_multicast = TRUE; - dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)((long int)ifidx), - DHD_WQ_WORK_SET_MCAST_LIST, dhd_set_mcast_list_handler, DHD_WQ_WORK_PRIORITY_LOW); - - // terence 20160907: fix for not able to set mac when wlan0 is down - dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)dhd->iflist[ifidx], - DHD_WQ_WORK_SET_MAC, dhd_set_mac_addr_handler, DHD_WQ_WORK_PRIORITY_LOW); -} - -#ifdef DHD_UCODE_DOWNLOAD -/* Get ucode path */ -char * -dhd_get_ucode_path(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = dhdp->info; - return dhd->uc_path; -} -#endif /* DHD_UCODE_DOWNLOAD */ - -#ifdef PROP_TXSTATUS -int -dhd_os_wlfc_block(dhd_pub_t *pub) -{ - dhd_info_t *di = (dhd_info_t *)(pub->info); - ASSERT(di != NULL); - /* terence 20161229: don't do spin lock if proptx not enabled */ - if (disable_proptx) - return 1; -#ifdef BCMDBUS - spin_lock_irqsave(&di->wlfc_spinlock, di->wlfc_lock_flags); -#else - spin_lock_bh(&di->wlfc_spinlock); -#endif /* BCMDBUS */ - return 1; -} - -int -dhd_os_wlfc_unblock(dhd_pub_t *pub) -{ - dhd_info_t *di = (dhd_info_t *)(pub->info); - - ASSERT(di != NULL); - /* terence 20161229: don't do spin lock if proptx not enabled */ - if (disable_proptx) - return 1; -#ifdef BCMDBUS - spin_unlock_irqrestore(&di->wlfc_spinlock, di->wlfc_lock_flags); -#else - spin_unlock_bh(&di->wlfc_spinlock); -#endif /* BCMDBUS */ - return 1; -} - -#endif /* PROP_TXSTATUS */ - -#if defined(DHD_RX_DUMP) || defined(DHD_TX_DUMP) -typedef struct { - uint16 type; - const char *str; -} PKTTYPE_INFO; - -static const PKTTYPE_INFO packet_type_info[] = -{ - { ETHER_TYPE_IP, "IP" }, - { ETHER_TYPE_ARP, "ARP" }, - { ETHER_TYPE_BRCM, "BRCM" }, - { ETHER_TYPE_802_1X, "802.1X" }, - { ETHER_TYPE_WAI, "WAPI" }, - { 0, ""} -}; - -static const char *_get_packet_type_str(uint16 type) -{ - int i; - int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1; - - for (i = 0; i < n; i++) { - if (packet_type_info[i].type == type) - return packet_type_info[i].str; - } - - return packet_type_info[n].str; -} -#endif /* DHD_RX_DUMP || DHD_TX_DUMP */ - -#if defined(DHD_TX_DUMP) -void -dhd_tx_dump(struct net_device *ndev, osl_t *osh, void *pkt) -{ - uint8 *dump_data; - uint16 protocol; - char *ifname; - - dump_data = PKTDATA(osh, pkt); - protocol = (dump_data[12] << 8) | dump_data[13]; - ifname = ndev ? ndev->name : "N/A"; - - DHD_ERROR(("TX DUMP[%s] - %s\n", ifname, _get_packet_type_str(protocol))); - - if (protocol == ETHER_TYPE_802_1X) { - dhd_dump_eapol_4way_message(ifname, dump_data, TRUE); - } - -#if defined(DHD_TX_FULL_DUMP) - { - int i; - uint datalen; - datalen = PKTLEN(osh, pkt); - - for (i = 0; i < datalen; i++) { - printk("%02X ", dump_data[i]); - if ((i & 15) == 15) - printk("\n"); - } - printk("\n"); - } -#endif /* DHD_TX_FULL_DUMP */ -} -#endif /* DHD_TX_DUMP */ - -/* This routine do not support Packet chain feature, Currently tested for - * proxy arp feature - */ -int dhd_sendup(dhd_pub_t *dhdp, int ifidx, void *p) -{ - struct sk_buff *skb; - void *skbhead = NULL; - void *skbprev = NULL; - dhd_if_t *ifp; - ASSERT(!PKTISCHAINED(p)); - skb = PKTTONATIVE(dhdp->osh, p); - - ifp = dhdp->info->iflist[ifidx]; - skb->dev = ifp->net; -#if defined(BCM_GMAC3) - /* Forwarder capable interfaces use WOFA based forwarding */ - if (ifp->fwdh) { - struct ether_header *eh = (struct ether_header *)PKTDATA(dhdp->osh, p); - uint16 * da = (uint16 *)(eh->ether_dhost); - uintptr_t wofa_data; - ASSERT(ISALIGNED(da, 2)); - - wofa_data = fwder_lookup(ifp->fwdh->mate, da, ifp->idx); - if (wofa_data == WOFA_DATA_INVALID) { /* Unknown MAC address */ - if (fwder_transmit(ifp->fwdh, skb, 1, skb->dev) == FWDER_SUCCESS) { - return BCME_OK; - } - } - PKTFRMNATIVE(dhdp->osh, p); - PKTFREE(dhdp->osh, p, FALSE); - return BCME_OK; - } -#endif /* BCM_GMAC3 */ - - skb->protocol = eth_type_trans(skb, skb->dev); - - if (in_interrupt()) { - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, - __FUNCTION__, __LINE__); - netif_rx(skb); - } else { - if (dhdp->info->rxthread_enabled) { - if (!skbhead) { - skbhead = skb; - } else { - PKTSETNEXT(dhdp->osh, skbprev, skb); - } - skbprev = skb; - } else { - /* If the receive is not processed inside an ISR, - * the softirqd must be woken explicitly to service - * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled - * by netif_rx_ni(), but in earlier kernels, we need - * to do it manually. - */ - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, - __FUNCTION__, __LINE__); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - netif_rx_ni(skb); -#else - ulong flags; - netif_rx(skb); - local_irq_save(flags); - RAISE_RX_SOFTIRQ(); - local_irq_restore(flags); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ - } - } - - if (dhdp->info->rxthread_enabled && skbhead) - dhd_sched_rxf(dhdp, skbhead); - - return BCME_OK; -} - -int BCMFASTPATH -__dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) -{ - int ret = BCME_OK; - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - struct ether_header *eh = NULL; -#if defined(DHD_L2_FILTER) - dhd_if_t *ifp = dhd_get_ifp(dhdp, ifidx); -#endif - - /* Reject if down */ - if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { - /* free the packet here since the caller won't */ - PKTCFREE(dhdp->osh, pktbuf, TRUE); - return -ENODEV; - } - -#ifdef PCIE_FULL_DONGLE - if (dhdp->busstate == DHD_BUS_SUSPEND) { - DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); - PKTCFREE(dhdp->osh, pktbuf, TRUE); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) - return -ENODEV; -#else - return NETDEV_TX_BUSY; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) */ - } -#endif /* PCIE_FULL_DONGLE */ - -#ifdef DHD_L2_FILTER - /* if dhcp_unicast is enabled, we need to convert the */ - /* broadcast DHCP ACK/REPLY packets to Unicast. */ - if (ifp->dhcp_unicast) { - uint8* mac_addr; - uint8* ehptr = NULL; - int ret; - ret = bcm_l2_filter_get_mac_addr_dhcp_pkt(dhdp->osh, pktbuf, ifidx, &mac_addr); - if (ret == BCME_OK) { - /* if given mac address having valid entry in sta list - * copy the given mac address, and return with BCME_OK - */ - if (dhd_find_sta(dhdp, ifidx, mac_addr)) { - ehptr = PKTDATA(dhdp->osh, pktbuf); - bcopy(mac_addr, ehptr + ETHER_DEST_OFFSET, ETHER_ADDR_LEN); - } - } - } - - if (ifp->grat_arp && DHD_IF_ROLE_AP(dhdp, ifidx)) { - if (bcm_l2_filter_gratuitous_arp(dhdp->osh, pktbuf) == BCME_OK) { - PKTCFREE(dhdp->osh, pktbuf, TRUE); - return BCME_ERROR; - } - } - - if (ifp->parp_enable && DHD_IF_ROLE_AP(dhdp, ifidx)) { - ret = dhd_l2_filter_pkt_handle(dhdp, ifidx, pktbuf, TRUE); - - /* Drop the packets if l2 filter has processed it already - * otherwise continue with the normal path - */ - if (ret == BCME_OK) { - PKTCFREE(dhdp->osh, pktbuf, TRUE); - return BCME_ERROR; - } - } -#endif /* DHD_L2_FILTER */ - /* Update multicast statistic */ - if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) { - uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); - eh = (struct ether_header *)pktdata; - - if (ETHER_ISMULTI(eh->ether_dhost)) - dhdp->tx_multicast++; - if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) { -#ifdef DHD_LOSSLESS_ROAMING - uint8 prio = (uint8)PKTPRIO(pktbuf); - - /* back up 802.1x's priority */ - dhdp->prio_8021x = prio; -#endif /* DHD_LOSSLESS_ROAMING */ - DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED); - atomic_inc(&dhd->pend_8021x_cnt); -#if defined(DHD_8021X_DUMP) - dhd_dump_eapol_4way_message(dhd_ifname(dhdp, ifidx), pktdata, TRUE); -#endif /* DHD_8021X_DUMP */ - } - - if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) { -#ifdef DHD_DHCP_DUMP - dhd_dhcp_dump(dhd_ifname(dhdp, ifidx), pktdata, TRUE); -#endif /* DHD_DHCP_DUMP */ -#ifdef DHD_ICMP_DUMP - dhd_icmp_dump(dhd_ifname(dhdp, ifidx), pktdata, TRUE); -#endif /* DHD_ICMP_DUMP */ - } - } else { - PKTCFREE(dhdp->osh, pktbuf, TRUE); - return BCME_ERROR; - } - - { - /* Look into the packet and update the packet priority */ -#ifndef PKTPRIO_OVERRIDE - if (PKTPRIO(pktbuf) == 0) -#endif /* !PKTPRIO_OVERRIDE */ - { -#if defined(QOS_MAP_SET) - pktsetprio_qms(pktbuf, wl_get_up_table(dhdp, ifidx), FALSE); -#else - pktsetprio(pktbuf, FALSE); -#endif /* QOS_MAP_SET */ - } - } - - -#if defined(TRAFFIC_MGMT_DWM) - traffic_mgmt_pkt_set_prio(dhdp, pktbuf); - -#ifdef BCM_GMAC3 - DHD_PKT_SET_DATAOFF(pktbuf, 0); -#endif /* BCM_GMAC3 */ -#endif - -#ifdef PCIE_FULL_DONGLE - /* - * Lkup the per interface hash table, for a matching flowring. If one is not - * available, allocate a unique flowid and add a flowring entry. - * The found or newly created flowid is placed into the pktbuf's tag. - */ - ret = dhd_flowid_update(dhdp, ifidx, dhdp->flow_prio_map[(PKTPRIO(pktbuf))], pktbuf); - if (ret != BCME_OK) { - PKTCFREE(dhd->pub.osh, pktbuf, TRUE); - return ret; - } -#endif - -#if defined(DHD_TX_DUMP) - ndev = dhd_idx2net(dhdp, ifidx); - dhd_tx_dump(ndev, dhdp->osh, pktbuf); -#endif - /* terence 20150901: Micky add to ajust the 802.1X priority */ - /* Set the 802.1X packet with the highest priority 7 */ - if (dhdp->conf->pktprio8021x >= 0) - pktset8021xprio(pktbuf, dhdp->conf->pktprio8021x); - -#ifdef PROP_TXSTATUS - if (dhd_wlfc_is_supported(dhdp)) { - /* store the interface ID */ - DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx); - - /* store destination MAC in the tag as well */ - DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost); - - /* decide which FIFO this packet belongs to */ - if (ETHER_ISMULTI(eh->ether_dhost)) - /* one additional queue index (highest AC + 1) is used for bc/mc queue */ - DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT); - else - DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf))); - } else -#endif /* PROP_TXSTATUS */ - { - /* If the protocol uses a data header, apply it */ - dhd_prot_hdrpush(dhdp, ifidx, pktbuf); - } - - /* Use bus module to send data frame */ -#ifdef WLMEDIA_HTSF - dhd_htsf_addtxts(dhdp, pktbuf); -#endif -#ifdef PROP_TXSTATUS - { - if (dhd_wlfc_commit_packets(dhdp, (f_commitpkt_t)dhd_bus_txdata, - dhdp->bus, pktbuf, TRUE) == WLFC_UNSUPPORTED) { - /* non-proptxstatus way */ -#ifdef BCMPCIE - ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx); -#else - ret = dhd_bus_txdata(dhdp->bus, pktbuf); -#endif /* BCMPCIE */ - } - } -#else -#ifdef BCMPCIE - ret = dhd_bus_txdata(dhdp->bus, pktbuf, (uint8)ifidx); -#else - ret = dhd_bus_txdata(dhdp->bus, pktbuf); -#endif /* BCMPCIE */ -#endif /* PROP_TXSTATUS */ -#ifdef BCMDBUS - if (ret) - PKTCFREE(dhdp->osh, pktbuf, TRUE); -#endif /* BCMDBUS */ - - return ret; -} - -int BCMFASTPATH -dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) -{ - int ret = 0; - unsigned long flags; - - DHD_GENERAL_LOCK(dhdp, flags); - if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhdp)) { - DHD_ERROR(("%s: returning as busstate=%d\n", - __FUNCTION__, dhdp->busstate)); - DHD_GENERAL_UNLOCK(dhdp, flags); - PKTCFREE(dhdp->osh, pktbuf, TRUE); - return -ENODEV; - } - DHD_BUS_BUSY_SET_IN_SEND_PKT(dhdp); - DHD_GENERAL_UNLOCK(dhdp, flags); - -#ifdef DHD_PCIE_RUNTIMEPM - if (dhdpcie_runtime_bus_wake(dhdp, FALSE, __builtin_return_address(0))) { - DHD_ERROR(("%s : pcie is still in suspend state!!\n", __FUNCTION__)); - PKTCFREE(dhdp->osh, pktbuf, TRUE); - ret = -EBUSY; - goto exit; - } -#endif /* DHD_PCIE_RUNTIMEPM */ - - DHD_GENERAL_LOCK(dhdp, flags); - if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhdp)) { - DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state!!\n", - __FUNCTION__, dhdp->busstate, dhdp->dhd_bus_busy_state)); - DHD_BUS_BUSY_CLEAR_IN_SEND_PKT(dhdp); - dhd_os_busbusy_wake(dhdp); - DHD_GENERAL_UNLOCK(dhdp, flags); - PKTCFREE(dhdp->osh, pktbuf, TRUE); - return -ENODEV; - } - DHD_GENERAL_UNLOCK(dhdp, flags); - - ret = __dhd_sendpkt(dhdp, ifidx, pktbuf); - -#ifdef DHD_PCIE_RUNTIMEPM -exit: -#endif - DHD_GENERAL_LOCK(dhdp, flags); - DHD_BUS_BUSY_CLEAR_IN_SEND_PKT(dhdp); - dhd_os_busbusy_wake(dhdp); - DHD_GENERAL_UNLOCK(dhdp, flags); - return ret; -} - -#if defined(DHD_LB_TXP) - -int BCMFASTPATH -dhd_lb_sendpkt(dhd_info_t *dhd, struct net_device *net, - int ifidx, void *skb) -{ - DHD_LB_STATS_PERCPU_ARR_INCR(dhd->tx_start_percpu_run_cnt); - - /* If the feature is disabled run-time do TX from here */ - if (atomic_read(&dhd->lb_txp_active) == 0) { - DHD_LB_STATS_PERCPU_ARR_INCR(dhd->txp_percpu_run_cnt); - return __dhd_sendpkt(&dhd->pub, ifidx, skb); - } - - /* Store the address of net device and interface index in the Packet tag */ - DHD_LB_TX_PKTTAG_SET_NETDEV((dhd_tx_lb_pkttag_fr_t *)PKTTAG(skb), net); - DHD_LB_TX_PKTTAG_SET_IFIDX((dhd_tx_lb_pkttag_fr_t *)PKTTAG(skb), ifidx); - - /* Enqueue the skb into tx_pend_queue */ - skb_queue_tail(&dhd->tx_pend_queue, skb); - - DHD_TRACE(("%s(): Added skb %p for netdev %p \r\n", __FUNCTION__, skb, net)); - - /* Dispatch the Tx job to be processed by the tx_tasklet */ - dhd_lb_tx_dispatch(&dhd->pub); - - return NETDEV_TX_OK; -} -#endif /* DHD_LB_TXP */ - -int BCMFASTPATH -dhd_start_xmit(struct sk_buff *skb, struct net_device *net) -{ - int ret; - uint datalen; - void *pktbuf; - dhd_info_t *dhd = DHD_DEV_INFO(net); - dhd_if_t *ifp = NULL; - int ifidx; - unsigned long flags; -#ifdef WLMEDIA_HTSF - uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz; -#else - uint8 htsfdlystat_sz = 0; -#endif -#ifdef DHD_WMF - struct ether_header *eh; - uint8 *iph; -#endif /* DHD_WMF */ -#ifdef TCPKA_REPAIR - dhd_pub_t *dhdp = &dhd->pub; -#endif /* TCPKA_REPAIR */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (dhd_query_bus_erros(&dhd->pub)) { - return -ENODEV; - } - - /* terence 2017029: Reject in early suspend */ - if (!dhd->pub.conf->xmit_in_suspend && dhd->pub.early_suspended) { - dhd_txflowcontrol(&dhd->pub, ALL_INTERFACES, ON); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) - return -ENODEV; -#else - return NETDEV_TX_BUSY; -#endif - } - - DHD_GENERAL_LOCK(&dhd->pub, flags); - DHD_BUS_BUSY_SET_IN_TX(&dhd->pub); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - -#ifdef DHD_PCIE_RUNTIMEPM - if (dhdpcie_runtime_bus_wake(&dhd->pub, FALSE, dhd_start_xmit)) { - /* In order to avoid pkt loss. Return NETDEV_TX_BUSY until run-time resumed. */ - /* stop the network queue temporarily until resume done */ - DHD_GENERAL_LOCK(&dhd->pub, flags); - if (!dhdpcie_is_resume_done(&dhd->pub)) { - dhd_bus_stop_queue(dhd->pub.bus); - } - DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); - dhd_os_busbusy_wake(&dhd->pub); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) - return -ENODEV; -#else - return NETDEV_TX_BUSY; -#endif - } -#endif /* DHD_PCIE_RUNTIMEPM */ - - DHD_GENERAL_LOCK(&dhd->pub, flags); -#ifdef BCMPCIE - if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(&dhd->pub)) { - DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state!!\n", - __FUNCTION__, dhd->pub.busstate, dhd->pub.dhd_bus_busy_state)); - DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); -#ifdef PCIE_FULL_DONGLE - /* Stop tx queues if suspend is in progress */ - if (DHD_BUS_CHECK_ANY_SUSPEND_IN_PROGRESS(&dhd->pub)) { - dhd_bus_stop_queue(dhd->pub.bus); - } -#endif /* PCIE_FULL_DONGLE */ - dhd_os_busbusy_wake(&dhd->pub); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) - return -ENODEV; -#else - return NETDEV_TX_BUSY; -#endif - } -#else - if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(&dhd->pub)) { - DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state!!\n", - __FUNCTION__, dhd->pub.busstate, dhd->pub.dhd_bus_busy_state)); - } -#endif - - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK_TRY(DHD_FWDER_UNIT(dhd), lock_taken); - - -#if defined(DHD_HANG_SEND_UP_TEST) - if (dhd->pub.req_hang_type == HANG_REASON_BUS_DOWN) { - dhd->pub.busstate = DHD_BUS_DOWN; - } -#endif /* DHD_HANG_SEND_UP_TEST */ - - /* Reject if down */ - if (dhd->pub.hang_was_sent || DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(&dhd->pub)) { - DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n", - __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); - netif_stop_queue(net); - /* Send Event when bus down detected during data session */ - if (dhd->pub.up && !dhd->pub.hang_was_sent && !DHD_BUS_CHECK_REMOVE(&dhd->pub)) { - DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__)); - dhd->pub.hang_reason = HANG_REASON_BUS_DOWN; - net_os_send_hang_message(net); - } - DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); - dhd_os_busbusy_wake(&dhd->pub); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), lock_taken); - DHD_OS_WAKE_UNLOCK(&dhd->pub); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) - return -ENODEV; -#else - return NETDEV_TX_BUSY; -#endif - } - - ifp = DHD_DEV_IFP(net); - ifidx = DHD_DEV_IFIDX(net); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx)); - netif_stop_queue(net); - DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); - dhd_os_busbusy_wake(&dhd->pub); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), lock_taken); - DHD_OS_WAKE_UNLOCK(&dhd->pub); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) - return -ENODEV; -#else - return NETDEV_TX_BUSY; -#endif - } - - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - - ASSERT(ifidx == dhd_net2idx(dhd, net)); - ASSERT((ifp != NULL) && ((ifidx < DHD_MAX_IFS) && (ifp == dhd->iflist[ifidx]))); - - bcm_object_trace_opr(skb, BCM_OBJDBG_ADD_PKT, __FUNCTION__, __LINE__); - - /* re-align socket buffer if "skb->data" is odd address */ - if (((unsigned long)(skb->data)) & 0x1) { - unsigned char *data = skb->data; - uint32 length = skb->len; - PKTPUSH(dhd->pub.osh, skb, 1); - memmove(skb->data, data, length); - PKTSETLEN(dhd->pub.osh, skb, length); - } - - datalen = PKTLEN(dhd->pub.osh, skb); - - /* Make sure there's enough room for any header */ - if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) { - struct sk_buff *skb2; - - DHD_INFO(("%s: insufficient headroom\n", - dhd_ifname(&dhd->pub, ifidx))); - dhd->pub.tx_realloc++; - - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, __FUNCTION__, __LINE__); - skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz); - - dev_kfree_skb(skb); - if ((skb = skb2) == NULL) { - DHD_ERROR(("%s: skb_realloc_headroom failed\n", - dhd_ifname(&dhd->pub, ifidx))); - ret = -ENOMEM; - goto done; - } - bcm_object_trace_opr(skb, BCM_OBJDBG_ADD_PKT, __FUNCTION__, __LINE__); - } - -#ifdef DHD_SK_PACING_SHIFT -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)) - sk_pacing_shift_update(skb->sk, DHD_SK_PACING_SHIFT); -#else - if (skb->sk && sk_fullsock(skb->sk) && - skb->sk->sk_pacing_shift != DHD_SK_PACING_SHIFT) - skb->sk->sk_pacing_shift = DHD_SK_PACING_SHIFT; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)) */ -#endif /* DHD_SK_PACING_SHIFT */ - - /* Convert to packet */ - if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) { - DHD_ERROR(("%s: PKTFRMNATIVE failed\n", - dhd_ifname(&dhd->pub, ifidx))); - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, __FUNCTION__, __LINE__); - dev_kfree_skb_any(skb); - ret = -ENOMEM; - goto done; - } - -#if defined(WLMEDIA_HTSF) - if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) { - uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf); - struct ether_header *eh = (struct ether_header *)pktdata; - - if (!ETHER_ISMULTI(eh->ether_dhost) && - (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) { - eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS); - } - } -#endif -#ifdef DHD_WET - /* wet related packet proto manipulation should be done in DHD - since dongle doesn't have complete payload - */ - if (WET_ENABLED(&dhd->pub) && - (dhd_wet_send_proc(dhd->pub.wet_info, pktbuf, &pktbuf) < 0)) { - DHD_INFO(("%s:%s: wet send proc failed\n", - __FUNCTION__, dhd_ifname(&dhd->pub, ifidx))); - PKTFREE(dhd->pub.osh, pktbuf, FALSE); - ret = -EFAULT; - goto done; - } -#endif /* DHD_WET */ - -#ifdef DHD_WMF - eh = (struct ether_header *)PKTDATA(dhd->pub.osh, pktbuf); - iph = (uint8 *)eh + ETHER_HDR_LEN; - - /* WMF processing for multicast packets - * Only IPv4 packets are handled - */ - if (ifp->wmf.wmf_enable && (ntoh16(eh->ether_type) == ETHER_TYPE_IP) && - (IP_VER(iph) == IP_VER_4) && (ETHER_ISMULTI(eh->ether_dhost) || - ((IPV4_PROT(iph) == IP_PROT_IGMP) && dhd->pub.wmf_ucast_igmp))) { -#if defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) - void *sdu_clone; - bool ucast_convert = FALSE; -#ifdef DHD_UCAST_UPNP - uint32 dest_ip; - - dest_ip = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET))); - ucast_convert = dhd->pub.wmf_ucast_upnp && MCAST_ADDR_UPNP_SSDP(dest_ip); -#endif /* DHD_UCAST_UPNP */ -#ifdef DHD_IGMP_UCQUERY - ucast_convert |= dhd->pub.wmf_ucast_igmp_query && - (IPV4_PROT(iph) == IP_PROT_IGMP) && - (*(iph + IPV4_HLEN(iph)) == IGMPV2_HOST_MEMBERSHIP_QUERY); -#endif /* DHD_IGMP_UCQUERY */ - if (ucast_convert) { - dhd_sta_t *sta; - unsigned long flags; - struct list_head snapshot_list; - struct list_head *wmf_ucforward_list; - - ret = NETDEV_TX_OK; - - /* For non BCM_GMAC3 platform we need a snapshot sta_list to - * resolve double DHD_IF_STA_LIST_LOCK call deadlock issue. - */ - wmf_ucforward_list = DHD_IF_WMF_UCFORWARD_LOCK(dhd, ifp, &snapshot_list); - - /* Convert upnp/igmp query to unicast for each assoc STA */ - list_for_each_entry(sta, wmf_ucforward_list, list) { - /* Skip sending to proxy interfaces of proxySTA */ - if (sta->psta_prim != NULL && !ifp->wmf_psta_disable) { - continue; - } - if ((sdu_clone = PKTDUP(dhd->pub.osh, pktbuf)) == NULL) { - ret = WMF_NOP; - break; - } - dhd_wmf_forward(ifp->wmf.wmfh, sdu_clone, 0, sta, 1); - } - DHD_IF_WMF_UCFORWARD_UNLOCK(dhd, wmf_ucforward_list); - - DHD_GENERAL_LOCK(&dhd->pub, flags); - DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); - dhd_os_busbusy_wake(&dhd->pub); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), lock_taken); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - if (ret == NETDEV_TX_OK) - PKTFREE(dhd->pub.osh, pktbuf, TRUE); - - return ret; - } else -#endif /* defined(DHD_IGMP_UCQUERY) || defined(DHD_UCAST_UPNP) */ - { - /* There will be no STA info if the packet is coming from LAN host - * Pass as NULL - */ - ret = dhd_wmf_packets_handle(&dhd->pub, pktbuf, NULL, ifidx, 0); - switch (ret) { - case WMF_TAKEN: - case WMF_DROP: - /* Either taken by WMF or we should drop it. - * Exiting send path - */ - - DHD_GENERAL_LOCK(&dhd->pub, flags); - DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); - dhd_os_busbusy_wake(&dhd->pub); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), lock_taken); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return NETDEV_TX_OK; - default: - /* Continue the transmit path */ - break; - } - } - } -#endif /* DHD_WMF */ -#ifdef DHD_PSTA - /* PSR related packet proto manipulation should be done in DHD - * since dongle doesn't have complete payload - */ - if (PSR_ENABLED(&dhd->pub) && (dhd_psta_proc(&dhd->pub, - ifidx, &pktbuf, TRUE) < 0)) { - DHD_ERROR(("%s:%s: psta send proc failed\n", __FUNCTION__, - dhd_ifname(&dhd->pub, ifidx))); - } -#endif /* DHD_PSTA */ - -#ifdef BCOL_TCPKA_SYNC - ret = dhd_bcol_tcpka_check_xmit(&dhd->pub, pktbuf); - if (ret == BCME_BUSY) { - PKTFREE(dhd->pub.osh, pktbuf, FALSE); - ret = 0; - goto done; - } -#endif /* BCOL_TCPKA_SYNC */ - -#ifdef TCPKA_REPAIR - if (tcpka_sync.tcpka_rp.configured == TRUE) { - tcpka_conn_repair_t pkt_info = {0}; - dhd_tcpka_repair_pkt_check(dhdp, pktbuf, &pkt_info, __func__); - - if (tcpka_sync.tcpka_rp.block_tcpka && tcpka_sync.tcpka_rp.pkt_in_q_num > 0 && - pkt_info.configured == TRUE && - pkt_info.src_ip == tcpka_sync.tcpka_rp.src_ip && - pkt_info.dst_ip == tcpka_sync.tcpka_rp.dst_ip && - pkt_info.src_port == tcpka_sync.tcpka_rp.src_port && - pkt_info.dst_port == tcpka_sync.tcpka_rp.dst_port) { - del_timer_sync(&dhd->tcpka_rp_timer); - dhd_tcpka_repair_pkt_sendup(dhdp); - } - } -#endif /* TCPKA_REPAIR */ - -#ifdef DHDTCPACK_SUPPRESS - if (dhd->pub.tcpack_sup_mode == TCPACK_SUP_HOLD) { - /* If this packet has been hold or got freed, just return */ - if (dhd_tcpack_hold(&dhd->pub, pktbuf, ifidx)) { - ret = 0; - goto done; - } - } else { - /* If this packet has replaced another packet and got freed, just return */ - if (dhd_tcpack_suppress(&dhd->pub, pktbuf)) { - ret = 0; - goto done; - } - } -#endif /* DHDTCPACK_SUPPRESS */ - - /* - * If Load Balance is enabled queue the packet - * else send directly from here. - */ -#if defined(DHD_LB_TXP) - ret = dhd_lb_sendpkt(dhd, net, ifidx, pktbuf); -#else - ret = __dhd_sendpkt(&dhd->pub, ifidx, pktbuf); -#endif - -done: - if (ret) { - ifp->stats.tx_dropped++; - dhd->pub.tx_dropped++; - } else { -#ifdef PROP_TXSTATUS - /* tx_packets counter can counted only when wlfc is disabled */ - if (!dhd_wlfc_is_supported(&dhd->pub)) -#endif - { - dhd->pub.tx_packets++; - ifp->stats.tx_packets++; - ifp->stats.tx_bytes += datalen; - } - } - - - DHD_GENERAL_LOCK(&dhd->pub, flags); - DHD_BUS_BUSY_CLEAR_IN_TX(&dhd->pub); - dhd_os_busbusy_wake(&dhd->pub); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_PERIM_UNLOCK_TRY(DHD_FWDER_UNIT(dhd), lock_taken); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - /* Return ok: we always eat the packet */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) - return 0; -#else - return NETDEV_TX_OK; -#endif -} - - -void -dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) -{ - struct net_device *net; - dhd_info_t *dhd = dhdp->info; - int i; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(dhd); - -#ifdef DHD_LOSSLESS_ROAMING - /* block flowcontrol during roaming */ - if ((dhdp->dequeue_prec_map == 1 << PRIO_8021D_NC) && state == ON) { - return; - } -#endif - - if (ifidx == ALL_INTERFACES) { - /* Flow control on all active interfaces */ - dhdp->txoff = state; - for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhd->iflist[i]) { - net = dhd->iflist[i]->net; - if (state == ON) - netif_stop_queue(net); - else - netif_wake_queue(net); - } - } - } else { - if (dhd->iflist[ifidx]) { - net = dhd->iflist[ifidx]->net; - if (state == ON) - netif_stop_queue(net); - else - netif_wake_queue(net); - } - } -} - - -#ifdef DHD_WMF -bool -dhd_is_rxthread_enabled(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = dhdp->info; - - return dhd->rxthread_enabled; -} -#endif /* DHD_WMF */ - -#ifdef DHD_MCAST_REGEN -/* - * Description: This function is called to do the reverse translation - * - * Input eh - pointer to the ethernet header - */ -int32 -dhd_mcast_reverse_translation(struct ether_header *eh) -{ - uint8 *iph; - uint32 dest_ip; - - iph = (uint8 *)eh + ETHER_HDR_LEN; - dest_ip = ntoh32(*((uint32 *)(iph + IPV4_DEST_IP_OFFSET))); - - /* Only IP packets are handled */ - if (eh->ether_type != hton16(ETHER_TYPE_IP)) - return BCME_ERROR; - - /* Non-IPv4 multicast packets are not handled */ - if (IP_VER(iph) != IP_VER_4) - return BCME_ERROR; - - /* - * The packet has a multicast IP and unicast MAC. That means - * we have to do the reverse translation - */ - if (IPV4_ISMULTI(dest_ip) && !ETHER_ISMULTI(&eh->ether_dhost)) { - ETHER_FILL_MCAST_ADDR_FROM_IP(eh->ether_dhost, dest_ip); - return BCME_OK; - } - - return BCME_ERROR; -} -#endif /* MCAST_REGEN */ - -#ifdef SHOW_LOGTRACE -static int -dhd_event_logtrace_pkt_process(dhd_pub_t *dhdp, struct sk_buff * skb) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - int ret = BCME_OK; - uint datalen; - bcm_event_msg_u_t evu; - void *data = NULL; - void *pktdata = NULL; - bcm_event_t *pvt_data; - uint pktlen; - - DHD_TRACE(("%s:Enter\n", __FUNCTION__)); - - /* In dhd_rx_frame, header is stripped using skb_pull - * of size ETH_HLEN, so adjust pktlen accordingly - */ - pktlen = skb->len + ETH_HLEN; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) - pktdata = (void *)skb_mac_header(skb); -#else - pktdata = (void *)skb->mac.raw; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */ - - ret = wl_host_event_get_data(pktdata, pktlen, &evu); - - if (ret != BCME_OK) { - DHD_ERROR(("%s: wl_host_event_get_data err = %d\n", - __FUNCTION__, ret)); - goto exit; - } - - datalen = ntoh32(evu.event.datalen); - - pvt_data = (bcm_event_t *)pktdata; - data = &pvt_data[1]; - - dhd_dbg_trace_evnt_handler(dhdp, data, &dhd->event_data, datalen); - -exit: - return ret; -} - -static void -dhd_event_logtrace_process(struct work_struct * work) -{ -/* Ignore compiler warnings due to -Werror=cast-qual */ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - struct dhd_info *dhd = - container_of(work, struct dhd_info, event_log_dispatcher_work); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - - dhd_pub_t *dhdp; - struct sk_buff *skb; - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - dhdp = &dhd->pub; - - if (!dhdp) { - DHD_ERROR(("%s: dhd pub is null \n", __FUNCTION__)); - return; - } - - DHD_TRACE(("%s:Enter\n", __FUNCTION__)); - - /* Run while(1) loop till all skbs are dequeued */ - while ((skb = skb_dequeue(&dhd->evt_trace_queue)) != NULL) { -#ifdef PCIE_FULL_DONGLE - int ifid; - ifid = DHD_PKTTAG_IFID((dhd_pkttag_fr_t *)PKTTAG(skb)); - if (ifid == DHD_EVENT_IF) { - dhd_event_logtrace_infobuf_pkt_process(dhdp, skb, &dhd->event_data); - /* For sending skb to network layer, convert it to Native PKT - * after that assign skb->dev with Primary interface n/w device - * as for infobuf events, we are sending special DHD_EVENT_IF - */ -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, skb, FALSE); -#else - PKTFREE(dhdp->osh, skb, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ - continue; - } - else { - dhd_event_logtrace_pkt_process(dhdp, skb); - } -#else - dhd_event_logtrace_pkt_process(dhdp, skb); -#endif /* PCIE_FULL_DONGLE */ - - /* Free skb buffer here if DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT - * macro is defined the Info Ring event and WLC_E_TRACE event is freed in DHD - * else it is always sent up to network layers. - */ -#ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, skb, FALSE); -#else - PKTFREE(dhdp->osh, skb, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ -#else /* !DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT */ - /* Do not call netif_recieve_skb as this workqueue scheduler is not from NAPI - * Also as we are not in INTR context, do not call netif_rx, instead call - * netif_rx_ni (for kerenl >= 2.6) which does netif_rx, disables irq, raise - * NET_IF_RX softirq and enables interrupts back - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - netif_rx_ni(skb); -#else - { - ulong flags; - netif_rx(skb); - local_irq_save(flags); - RAISE_RX_SOFTIRQ(); - local_irq_restore(flags); - } -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ -#endif /* DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT */ - } -} - -void -dhd_event_logtrace_enqueue(dhd_pub_t *dhdp, int ifidx, void *pktbuf) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - -#ifdef PCIE_FULL_DONGLE - /* Add ifidx in the PKTTAG */ - DHD_PKTTAG_SET_IFID((dhd_pkttag_fr_t *)PKTTAG(pktbuf), ifidx); -#endif /* PCIE_FULL_DONGLE */ - skb_queue_tail(&dhd->evt_trace_queue, pktbuf); - - schedule_work(&dhd->event_log_dispatcher_work); -} - -void -dhd_event_logtrace_flush_queue(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - struct sk_buff *skb; - - while ((skb = skb_dequeue(&dhd->evt_trace_queue)) != NULL) { -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, skb, FALSE); -#else - PKTFREE(dhdp->osh, skb, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ - } -} -#endif /* SHOW_LOGTRACE */ - -#if defined(BCOL_TCPKA_SYNC) && defined(RESUME_INIT) -static void -dhd_tcpka_reset(dhd_pub_t *dhd, struct net_device *dev) -{ - tcpka_conn_sess_t tcpka_sess; - char iovbuf[64]; - int i, err; -#ifdef PF_SETUP_COMMAND - pf_config_t pf_cfg; - - DHD_ERROR(("%s: enter\n", __func__)); - - mutex_lock(&dhd->dhd_tcpka_mutex); - if(tcpka_sync.tcpka_sync_mode == BCOL_TCPKA_SYNC_MODE_ON) { - DHD_ERROR(("%s: already in sync mode\n", __func__)); - goto out; - } - - err = dhd_packet_filter_sync(dev); - if (err) { - DHD_ERROR(("%s: fail to sync pkt filter\n", __func__)); - goto out; - } -#endif /* PF_SETUP_COMMAND */ - - memset(&tcpka_sess, 0, sizeof(tcpka_sess)); - /* clean all rules */ - for (i = TCPKA_DEFAULT_SESS_ID; i <= TCPKA_MAX_SESSION; i++) { - /* disable tcpka rule */ - tcpka_sess.sess_id = i; - tcpka_sess.flag = htod32(0); - - bcm_mkiovar("tcpka_conn_enable", (char *)&tcpka_sess, sizeof(tcpka_conn_sess_t), - iovbuf, sizeof(iovbuf)); - err = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - if (err < 0 && err != BCME_NOTFOUND) { - DHD_ERROR(("%s: disable tcpka_conn_enable %d failed, ret %d\n", - __func__, tcpka_sess.sess_id, err)); - } - -#ifdef PF_SETUP_COMMAND - /* delete packet filter rule */ - memset(&pf_cfg, 0, sizeof(pf_cfg)); - pf_cfg.addremove = 0; - pf_cfg.id = PF_FOR_TCPKA_ID_BASE + i; - - err = dhd_packet_filter_add_remove_ext(dev, - false, pf_cfg.id, NULL, FALSE); - if (err) { - DHD_ERROR(("%s: fail to remove pf rule %d, ret %d\n", - __func__, pf_cfg.id, err)); - } - - /* delete packet filter rule */ - memset(&pf_cfg, 0, sizeof(pf_cfg)); - pf_cfg.addremove = 0; - pf_cfg.id = PF_FOR_WEAVE_ID_BASE + i; - - err = dhd_packet_filter_add_remove_ext(dev, - false, pf_cfg.id, NULL, FALSE); - if (err) { - DHD_ERROR(("%s: fail to remove weave pf rule %d, ret %d\n", - __func__, pf_cfg.id, err)); - } -#endif /* PF_SETUP_COMMAND */ - } -out: - mutex_unlock(&dhd->dhd_tcpka_mutex); -} -#endif /* defined(BCOL_TCPKA_SYNC) && defined(RESUME_INIT) */ - -#ifdef TCPKA_REPAIR -static void dhd_tcpka_repair_pkt_sendup(dhd_pub_t *dhdp) -{ - struct sk_buff *skbp; - - if (!dhdp || !dhdp->info) { - DHD_ERROR(("%s: Invalid parameter, dhdp(%p)\n", __func__, dhdp)); - return; - } - schedule_work(&dhdp->info->tcpka_reset_work); - - tcpka_sync.tcpka_rp.block_tcpka = FALSE; - tcpka_sync.tcpka_rp.block_tcpka_start_time = 0; - DHD_ERROR(("%s: release %d pkts\n", - __func__, tcpka_sync.tcpka_rp.pkt_in_q_num)); - - if (tcpka_sync.tcpka_rp.skbhead == NULL) { - DHD_ERROR(("skhead is NULL!\n")); - return; - } - - skbp = tcpka_sync.tcpka_rp.skbhead; - - while (skbp) { - void *skbnext = PKTNEXT(dhdp->osh, skbp); - - if (tcpka_sync.tcpka_rp.pkt_in_q_num <= 0) { - DHD_ERROR(("wrong skb!!!\n")); - break; - } - - PKTSETNEXT(dhdp->osh, skbp, NULL); - /* check skb->dev */ - if (!skbp->dev) { - uint8 ifidx = DHD_PKTTAG_IFIDX((dhd_pkttag_rx_t *)PKTTAG(skbp)); - dhd_if_t *ifp = NULL; - - DHD_ERROR(("%s: null dev, ifidx %d\n", __func__, ifidx)); - - if (ifidx < DHD_MAX_IFS) { - ifp = dhdp->info->iflist[ifidx]; - if (ifp && ifp->net) { - skbp->dev = ifp->net; - DHD_ERROR(("%s: assign new dev %p\n", __func__, skbp->dev)); - } - } - } - DHD_PKTTAG_SET_IFIDX((dhd_pkttag_rx_t *)PKTTAG(skbp), 0); - - if (skbp->dev) { - bcm_object_trace_opr(skbp, BCM_OBJDBG_REMOVE, - __FUNCTION__, __LINE__); - - DHD_PERIM_UNLOCK_ALL((dhdp->fwder_unit % FWDER_MAX_UNIT)); - if (in_interrupt()) { -#if defined(DHD_LB_RXP) - netif_receive_skb(skbp); -#else /* !defined(DHD_LB_RXP) */ - netif_rx(skbp); -#endif /* !defined(DHD_LB_RXP) */ - } else { - netif_rx_ni(skbp); - } - DHD_PERIM_LOCK_ALL((dhdp->fwder_unit % FWDER_MAX_UNIT)); - } else { - PKTFREE(dhdp->osh, skbp, FALSE); - DHD_ERROR(("%s: null dev, free pkt\n", __func__)); - } - - if (tcpka_sync.tcpka_rp.pkt_in_q_num > 0) { - DHD_TRACE(("SENDUP PKT %p\n", skbp)); - tcpka_sync.tcpka_rp.pkt_in_q_num--; - } else { - DHD_ERROR(("PKT NUM MISMATCH!!!\n")); - } - skbp = skbnext; - } - DHD_TRACE(("send skb to kernel backlog without rxf_thread\n")); - - tcpka_sync.tcpka_rp.skbhead = NULL; -} - -static void dhd_tcpka_repair_pkt_sendup_action( -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) - struct timer_list *t -#else - ulong data -#endif -) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) - dhd_info_t *dhd = from_timer(dhd, t, tcpka_rp_timer); -#else - dhd_info_t *dhd = (dhd_info_t *)data; -#endif - dhd_tcpka_repair_pkt_sendup(&dhd->pub); -} - - -static int dhd_tcpka_repair_pkt_check(dhd_pub_t *dhdp, void *pkt, - tcpka_conn_repair_t *info, const char *func) -{ - uint8 *ether_hdr; /* Ethernet header of the rx packet */ - uint16 ether_type; /* Ethernet type of the rx packet */ - uint8 *ip_hdr; /* IP header of the rx packet */ - uint8 *tcp_hdr; /* TCP header of the rx packet */ - uint32 ip_hdr_len; /* IP header length of the rx packet */ - uint8 src_ip_buf[16]; - uint8 dst_ip_buf[16]; - - ether_hdr = PKTDATA(dhdp->osh, pkt); - ether_type = ether_hdr[12] << 8 | ether_hdr[13]; - if (ether_type != ETHER_TYPE_IP) { - return BCME_NOTFOUND; - } - - ip_hdr = ether_hdr + ETHER_HDR_LEN; - if (IP_VER(ip_hdr) != IP_VER_4 || IPV4_PROT(ip_hdr) != IP_PROT_TCP) { - return BCME_NOTFOUND; - } - - ip_hdr_len = IPV4_HLEN(ip_hdr); - tcp_hdr = ip_hdr + ip_hdr_len; - info->src_ip = *(uint32 *)&ip_hdr[IPV4_SRC_IP_OFFSET]; - info->dst_ip = *(uint32 *)&ip_hdr[IPV4_DEST_IP_OFFSET]; - info->src_port = ntoh16_ua(&tcp_hdr[TCP_SRC_PORT_OFFSET]); - info->dst_port = ntoh16_ua(&tcp_hdr[TCP_DEST_PORT_OFFSET]); - bcm_ip_ntoa((struct ipv4_addr *)&info->src_ip, src_ip_buf); - bcm_ip_ntoa((struct ipv4_addr *)&info->dst_ip, dst_ip_buf); - DHD_TRACE(("%s: pkt %p: [src] %s:%u, [dst] %s:%u\n", func, - pkt, src_ip_buf, info->src_port, - dst_ip_buf, info->dst_port)); - info->configured = TRUE; - return BCME_OK; -} - -static int dhd_tcpka_seq_update(dhd_pub_t *dhdp, void *pkt) -{ - uint8 *new_ether_hdr; /* Ethernet header of the new packet */ - uint16 new_ether_type; /* Ethernet type of the new packet */ - uint8 *new_ip_hdr; /* IP header of the new packet */ - uint8 *new_tcp_hdr; /* TCP header of the new packet */ - uint32 new_ip_hdr_len; /* IP header length of the new packet */ - tcpka_conn_t *tcpka; - - if (tcpka_sync.tcpka_sync_mode != BCOL_TCPKA_SYNC_STATE_TRAC || !tcpka_sync.tcpka_conn) { - return BCME_NOTFOUND; - } - - tcpka = tcpka_sync.tcpka_conn; - if (!tcpka->sess_id) { - DHD_ERROR(("%s: tcpka config has no vaild session id\n", __func__)); - return BCME_NOTREADY; - } - - new_ether_hdr = PKTDATA(dhdp->osh, pkt); - - new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13]; - if (new_ether_type != ETHER_TYPE_IP) { - return BCME_NOTFOUND; - } - - new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN; - if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) { - return BCME_NOTFOUND; - } - - new_ip_hdr_len = IPV4_HLEN(new_ip_hdr); - new_tcp_hdr = new_ip_hdr + new_ip_hdr_len; -#ifdef BCOL_TCPKA_SYNC_MATCHED_BY_PORT - DHD_TRACE(("[pkt] %p src port: %u dest port %u, [tcpka] src port %u dest port %u\n", - pkt, - ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]), - tcpka->srcport, - tcpka->dstport)); - /* If TCP port number does not match, skip. */ - if (tcpka->srcport == 0) { - if (ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]) != tcpka->dstport) { - return BCME_NOTFOUND; - } - } else { - if ((ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]) != tcpka->dstport) || - (ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]) != tcpka->srcport)) { - return BCME_NOTFOUND; - } - } -#else - /* If either of IP address or TCP port number does not match, skip. */ - if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET], tcpka->dst_ip.addr, IPV4_ADDR_LEN) || - memcmp(&new_ip_hdr[IPV4_DEST_IP_OFFSET], tcpka->src_ip.addr, IPV4_ADDR_LEN) || - (ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]) != tcpka->dstport) || - (ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]) != tcpka->srcport)) { - return BCME_NOTFOUND; - } -#endif /* BCOL_TCPKA_SYNC_MATCHED_BY_PORT */ - - DHD_TRACE(("%s: [TCKPA ] seq %u -> %u, ack %u -> %u\n", - __func__, tcpka->seq, ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]), - tcpka->ack, ntoh32_ua(&new_tcp_hdr[TCP_SEQ_NUM_OFFSET]))); - tcpka->ack = ntoh32_ua(&new_tcp_hdr[TCP_SEQ_NUM_OFFSET]); - tcpka->seq = ntoh32_ua(&new_tcp_hdr[TCP_ACK_NUM_OFFSET]); - return BCME_OK; -} -#endif /* TCPKA_REPAIR */ - -#if defined(EVENT_DATA_HOSTWAKE) && defined(BCOL_TCPKA_SYNC) -static int dhd_tcpka_rx_check(dhd_pub_t *dhdp, void *pkt) -{ - uint8 *new_ether_hdr; /* Ethernet header of the new packet */ - uint16 new_ether_type; /* Ethernet type of the new packet */ - uint8 *new_ip_hdr; /* IP header of the new packet */ - uint8 *new_tcp_hdr; /* TCP header of the new packet */ - uint32 new_ip_hdr_len; /* IP header length of the new packet */ - tcpka_conn_t *tcpka; - - tcpka = tcpka_sync.tcpka_conn; - if (tcpka_sync.tcpka_sync_mode == BCOL_TCPKA_SYNC_MODE_OFF || !tcpka_sync.tcpka_conn) { - return BCME_NOTFOUND; - } - - if (!tcpka->sess_id) { - DHD_ERROR(("%s: tcpka config has no vaild session id\n", __func__)); - return BCME_NOTREADY; - } - - new_ether_hdr = PKTDATA(dhdp->osh, pkt); - - new_ether_type = new_ether_hdr[12] << 8 | new_ether_hdr[13]; - if (new_ether_type != ETHER_TYPE_IP) { - return BCME_NOTFOUND; - } - - new_ip_hdr = new_ether_hdr + ETHER_HDR_LEN; - if (IP_VER(new_ip_hdr) != IP_VER_4 || IPV4_PROT(new_ip_hdr) != IP_PROT_TCP) { - return BCME_NOTFOUND; - } - - new_ip_hdr_len = IPV4_HLEN(new_ip_hdr); - new_tcp_hdr = new_ip_hdr + new_ip_hdr_len; -#ifdef BCOL_TCPKA_SYNC_MATCHED_BY_PORT - DHD_TRACE(("pkt %p src port: %d dest port %d, tcpka src port %d dest port %d\n", - pkt, - ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]), - ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]), - tcpka->srcport, - tcpka->dstport)); - - /* If TCP port number does not match, skip. */ - if (tcpka->srcport == 0) { - if (ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]) != tcpka->dstport) { - return BCME_NOTFOUND; - } - } else { - if ((ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]) != tcpka->dstport) || - (ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]) != tcpka->srcport)) { - return BCME_NOTFOUND; - } - } -#else - /* If either of IP address or TCP port number does not match, skip. */ - if (memcmp(&new_ip_hdr[IPV4_SRC_IP_OFFSET], tcpka->dst_ip.addr, IPV4_ADDR_LEN) || - memcmp(&new_ip_hdr[IPV4_DEST_IP_OFFSET], tcpka->src_ip.addr, IPV4_ADDR_LEN) || - (ntoh16_ua(&new_tcp_hdr[TCP_SRC_PORT_OFFSET]) != tcpka->dstport) || - (ntoh16_ua(&new_tcp_hdr[TCP_DEST_PORT_OFFSET]) != tcpka->srcport)) { - return BCME_NOTFOUND; - } -#endif /* BCOL_TCPKA_SYNC_MATCHED_BY_PORT */ - return BCME_OK; -} -#endif /* defined(EVENT_DATA_HOSTWAKE) && defined(BCOL_TCPKA_SYNC) */ - - -/** Called when a frame is received by the dongle on interface 'ifidx' */ -void -dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - struct sk_buff *skb; - uchar *eth; - uint len; - void *data, *pnext = NULL; - int i; - dhd_if_t *ifp; - wl_event_msg_t event; - int tout_rx = 0; - int tout_ctrl = 0; - void *skbhead = NULL; - void *skbprev = NULL; - uint16 protocol; -#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) || defined(DHD_DHCP_DUMP) || \ - defined(DHD_ICMP_DUMP) || defined(DHD_WAKE_STATUS) - unsigned char *dump_data; -#endif /* DHD_RX_DUMP || DHD_8021X_DUMP || DHD_DHCP_DUMP || DHD_ICMP_DUMP || DHD_WAKE_STATUS */ -#ifdef DHD_MCAST_REGEN - uint8 interface_role; - if_flow_lkup_t *if_flow_lkup; - unsigned long flags; -#endif -#ifdef DHD_WAKE_STATUS - int pkt_wake = 0; - wake_counts_t *wcp = NULL; -#endif /* DHD_WAKE_STATUS */ -#ifdef EVENT_DATA_HOSTWAKE - bool sendup = dhdp->evt_data_sendup; -#endif /* EVENT_DATA_HOSTWAKE */ -#ifdef DHD_BUILTIN - int driver_state = DHD_DRIVER_STATE_DOWN; -#endif /* DHD_BUILTIN */ - - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { - struct ether_header *eh; -#ifdef TCPKA_REPAIR - bool queue_this_pkt = FALSE; -#endif /* TCPKA_REPAIR */ - - pnext = PKTNEXT(dhdp->osh, pktbuf); - PKTSETNEXT(dhdp->osh, pktbuf, NULL); - -#ifdef TCPKA_REPAIR - queue_this_pkt = DHD_PKTTAG_QUEUED((dhd_pkttag_rx_t *)PKTTAG(pktbuf)); - if (queue_this_pkt && !tcpka_sync.tcpka_rp.block_tcpka) { - tcpka_sync.tcpka_rp.block_tcpka = TRUE; - tcpka_sync.tcpka_rp.block_tcpka_start_time = OSL_SYSUPTIME(); - tcpka_sync.tcpka_rp.block_tcpka_timeout = dhdp->conf->tcpka_repair_timeout; - if (dhd_get_driver_state() == DHD_DRIVER_STATE_COMPLETE) { - /* passed complete state, still need queue pkt */ - DHD_ERROR(("[TCP RP] release packets after %d sec\n", - tcpka_sync.tcpka_rp.block_tcpka_timeout)); - mod_timer(&dhdp->info->tcpka_rp_timer, - jiffies + - msecs_to_jiffies(tcpka_sync.tcpka_rp.block_tcpka_timeout * 1000)); - } - } - - if (tcpka_sync.tcpka_rp.block_tcpka) { - tcpka_conn_repair_t pkt_info = {0}; - dhd_tcpka_repair_pkt_check(dhdp, pktbuf, &pkt_info, __func__); - DHD_TRACE(("%s: queue_this_pkt %p %d\n", - __func__, pktbuf, queue_this_pkt)); - if (queue_this_pkt) { - if (tcpka_sync.tcpka_rp.configured == FALSE && - pkt_info.configured == TRUE) { - tcpka_sync.tcpka_rp.pkt_in_q_num = 0; - tcpka_sync.tcpka_rp.src_ip = pkt_info.dst_ip; - tcpka_sync.tcpka_rp.dst_ip = pkt_info.src_ip; - tcpka_sync.tcpka_rp.src_port = pkt_info.dst_port; - tcpka_sync.tcpka_rp.dst_port = pkt_info.src_port; - tcpka_sync.tcpka_rp.configured = TRUE; - } - DHD_PKTTAG_SET_QUEUED((dhd_pkttag_rx_t *)PKTTAG(pktbuf), FALSE); - } else { - if (pkt_info.configured == TRUE && - pkt_info.src_ip == tcpka_sync.tcpka_rp.dst_ip && - pkt_info.dst_ip == tcpka_sync.tcpka_rp.src_ip && - pkt_info.src_port == tcpka_sync.tcpka_rp.dst_port && - pkt_info.dst_port == tcpka_sync.tcpka_rp.src_port) { - DHD_TRACE(("%s: Found a PASS PACKET %p! Queue it\n", - __func__, pktbuf)); - queue_this_pkt = TRUE; - } - } - } -#endif /* TCPKA_REPAIR */ - - /* info ring "debug" data, which is not a 802.3 frame, is sent/hacked with a - * special ifidx of DHD_EVENT_IF. This is just internal to dhd to get the data from - * dhd_msgbuf.c:dhd_prot_infobuf_cmplt_process() to here (dhd_rx_frame). - */ - if (ifidx == DHD_EVENT_IF) { - /* Event msg printing is called from dhd_rx_frame which is in Tasklet - * context in case of PCIe FD, in case of other bus this will be from - * DPC context. If we get bunch of events from Dongle then printing all - * of them from Tasklet/DPC context that too in data path is costly. - * Also in the new Dongle SW(4359, 4355 onwards) console prints too come as - * events with type WLC_E_TRACE. - * We'll print this console logs from the WorkQueue context by enqueing SKB - * here and Dequeuing will be done in WorkQueue and will be freed only if - * DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT is defined - */ -#ifdef SHOW_LOGTRACE - dhd_event_logtrace_enqueue(dhdp, ifidx, pktbuf); -#else /* !SHOW_LOGTRACE */ - /* If SHOW_LOGTRACE not defined and ifidx is DHD_EVENT_IF, - * free the PKT here itself - */ -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); -#else - PKTFREE(dhdp->osh, pktbuf, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ -#endif /* SHOW_LOGTRACE */ - continue; - } -#ifdef DHD_WAKE_STATUS -#ifdef BCMDBUS - wcp = NULL; -#else - pkt_wake = dhd_chip_alive; - wcp = dhd_bus_get_wakecount(dhdp); -#endif /* BCMDBUS */ - if (wcp == NULL) { - /* If wakeinfo count buffer is null do not update wake count values */ - pkt_wake = 0; - } -#endif /* DHD_WAKE_STATUS */ - - ifp = dhd->iflist[ifidx]; - if (ifp == NULL) { - DHD_ERROR(("%s: ifp is NULL. drop packet\n", - __FUNCTION__)); - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - } - - eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf); - -#ifdef PROP_TXSTATUS - if (dhd_wlfc_is_header_only_pkt(dhdp, pktbuf)) { - /* WLFC may send header only packet when - there is an urgent message but no packet to - piggy-back on - */ - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - } -#endif -#ifdef DHD_L2_FILTER - /* If block_ping is enabled drop the ping packet */ - if (ifp->block_ping) { - if (bcm_l2_filter_block_ping(dhdp->osh, pktbuf) == BCME_OK) { - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - } - } - if (ifp->grat_arp && DHD_IF_ROLE_STA(dhdp, ifidx)) { - if (bcm_l2_filter_gratuitous_arp(dhdp->osh, pktbuf) == BCME_OK) { - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - } - } - if (ifp->parp_enable && DHD_IF_ROLE_AP(dhdp, ifidx)) { - int ret = dhd_l2_filter_pkt_handle(dhdp, ifidx, pktbuf, FALSE); - - /* Drop the packets if l2 filter has processed it already - * otherwise continue with the normal path - */ - if (ret == BCME_OK) { - PKTCFREE(dhdp->osh, pktbuf, TRUE); - continue; - } - } -#endif /* DHD_L2_FILTER */ - -#ifdef DHD_MCAST_REGEN - DHD_FLOWID_LOCK(dhdp->flowid_lock, flags); - if_flow_lkup = (if_flow_lkup_t *)dhdp->if_flow_lkup; - ASSERT(if_flow_lkup); - - interface_role = if_flow_lkup[ifidx].role; - DHD_FLOWID_UNLOCK(dhdp->flowid_lock, flags); - - if (ifp->mcast_regen_bss_enable && (interface_role != WLC_E_IF_ROLE_WDS) && - !DHD_IF_ROLE_AP(dhdp, ifidx) && - ETHER_ISUCAST(eh->ether_dhost)) { - if (dhd_mcast_reverse_translation(eh) == BCME_OK) { -#ifdef DHD_PSTA - /* Change bsscfg to primary bsscfg for unicast-multicast packets */ - if ((dhd_get_psta_mode(dhdp) == DHD_MODE_PSTA) || - (dhd_get_psta_mode(dhdp) == DHD_MODE_PSR)) { - if (ifidx != 0) { - /* Let the primary in PSTA interface handle this - * frame after unicast to Multicast conversion - */ - ifp = dhd_get_ifp(dhdp, 0); - ASSERT(ifp); - } - } - } -#endif /* PSTA */ - } -#endif /* MCAST_REGEN */ - -#ifdef DHD_WMF - /* WMF processing for multicast packets */ - if (ifp->wmf.wmf_enable && (ETHER_ISMULTI(eh->ether_dhost))) { - dhd_sta_t *sta; - int ret; - - sta = dhd_find_sta(dhdp, ifidx, (void *)eh->ether_shost); - ret = dhd_wmf_packets_handle(dhdp, pktbuf, sta, ifidx, 1); - switch (ret) { - case WMF_TAKEN: - /* The packet is taken by WMF. Continue to next iteration */ - continue; - case WMF_DROP: - /* Packet DROP decision by WMF. Toss it */ - DHD_ERROR(("%s: WMF decides to drop packet\n", - __FUNCTION__)); - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - default: - /* Continue the transmit path */ - break; - } - } -#endif /* DHD_WMF */ - -#ifdef DHDTCPACK_SUPPRESS - dhd_tcpdata_info_get(dhdp, pktbuf); -#endif - skb = PKTTONATIVE(dhdp->osh, pktbuf); - - ASSERT(ifp); - skb->dev = ifp->net; -#ifdef DHD_WET - /* wet related packet proto manipulation should be done in DHD - * since dongle doesn't have complete payload - */ - if (WET_ENABLED(&dhd->pub) && (dhd_wet_recv_proc(dhd->pub.wet_info, - pktbuf) < 0)) { - DHD_INFO(("%s:%s: wet recv proc failed\n", - __FUNCTION__, dhd_ifname(dhdp, ifidx))); - } -#endif /* DHD_WET */ - -#ifdef DHD_PSTA - if (PSR_ENABLED(dhdp) && (dhd_psta_proc(dhdp, ifidx, &pktbuf, FALSE) < 0)) { - DHD_ERROR(("%s:%s: psta recv proc failed\n", __FUNCTION__, - dhd_ifname(dhdp, ifidx))); - } -#endif /* DHD_PSTA */ - -#ifdef PCIE_FULL_DONGLE - if ((DHD_IF_ROLE_AP(dhdp, ifidx) || DHD_IF_ROLE_P2PGO(dhdp, ifidx)) && - (!ifp->ap_isolate)) { - eh = (struct ether_header *)PKTDATA(dhdp->osh, pktbuf); - if (ETHER_ISUCAST(eh->ether_dhost)) { - if (dhd_find_sta(dhdp, ifidx, (void *)eh->ether_dhost)) { - dhd_sendpkt(dhdp, ifidx, pktbuf); - continue; - } - } else { - void *npktbuf = PKTDUP(dhdp->osh, pktbuf); - if (npktbuf) - dhd_sendpkt(dhdp, ifidx, npktbuf); - } - } -#endif /* PCIE_FULL_DONGLE */ - - /* Get the protocol, maintain skb around eth_type_trans() - * The main reason for this hack is for the limitation of - * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len' - * to perform skb_pull inside vs ETH_HLEN. Since to avoid - * coping of the packet coming from the network stack to add - * BDC, Hardware header etc, during network interface registration - * we set the 'net->hard_header_len' to ETH_HLEN + extra space required - * for BDC, Hardware header etc. and not just the ETH_HLEN - */ - eth = skb->data; - len = skb->len; - -#if defined(DHD_RX_DUMP) || defined(DHD_8021X_DUMP) || defined(DHD_DHCP_DUMP) || \ - defined(DHD_ICMP_DUMP) || defined(DHD_WAKE_STATUS) - dump_data = skb->data; -#endif /* DHD_RX_DUMP || DHD_8021X_DUMP || DHD_DHCP_DUMP || DHD_ICMP_DUMP || DHD_WAKE_STATUS */ - - protocol = (skb->data[12] << 8) | skb->data[13]; - if (protocol == ETHER_TYPE_802_1X) { - DBG_EVENT_LOG(dhdp, WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED); -#ifdef DHD_8021X_DUMP - dhd_dump_eapol_4way_message(dhd_ifname(dhdp, ifidx), dump_data, FALSE); -#endif /* DHD_8021X_DUMP */ - } - - if (protocol != ETHER_TYPE_BRCM && protocol == ETHER_TYPE_IP) { -#ifdef DHD_DHCP_DUMP - dhd_dhcp_dump(dhd_ifname(dhdp, ifidx), dump_data, FALSE); -#endif /* DHD_DHCP_DUMP */ -#ifdef DHD_ICMP_DUMP - dhd_icmp_dump(dhd_ifname(dhdp, ifidx), dump_data, FALSE); -#endif /* DHD_ICMP_DUMP */ - } -#ifdef DHD_RX_DUMP - DHD_ERROR(("RX DUMP[%s] - %s\n", - dhd_ifname(dhdp, ifidx), _get_packet_type_str(protocol))); - if (protocol != ETHER_TYPE_BRCM) { - if (dump_data[0] == 0xFF) { - DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__)); - - if ((dump_data[12] == 8) && - (dump_data[13] == 6)) { - DHD_ERROR(("%s: ARP %d\n", - __FUNCTION__, dump_data[0x15])); - } - } else if (dump_data[0] & 1) { - DHD_ERROR(("%s: MULTICAST: " MACDBG "\n", - __FUNCTION__, MAC2STRDBG(dump_data))); - } -#ifdef DHD_RX_FULL_DUMP - { - int k; - for (k = 0; k < skb->len; k++) { - printk("%02X ", dump_data[k]); - if ((k & 15) == 15) - printk("\n"); - } - printk("\n"); - } -#endif /* DHD_RX_FULL_DUMP */ - } -#endif /* DHD_RX_DUMP */ -#if defined(DHD_WAKE_STATUS) && defined(DHD_WAKEPKT_DUMP) - if (pkt_wake) { - prhex("[wakepkt_dump]", (char*)dump_data, MIN(len, 48)); - } -#endif /* DHD_WAKE_STATUS && DHD_WAKEPKT_DUMP */ - - skb->protocol = eth_type_trans(skb, skb->dev); - - if (skb->pkt_type == PACKET_MULTICAST) { - dhd->pub.rx_multicast++; - ifp->stats.multicast++; - } - - skb->data = eth; - skb->len = len; - -#ifdef BCOL_TCPKA_SYNC - dhd_tcpka_seq_update(dhdp, skb); -#endif /* BCOL_TCPKA_SYNC */ - -#ifdef EVENT_DATA_HOSTWAKE - if (!sendup) { - int ret = BCME_OK; -#ifdef BCOL_TCPKA_SYNC - ret = dhd_tcpka_rx_check(dhdp, skb); -#endif /* BCOL_TCPKA_SYNC */ - if (ret == BCME_OK) { - dhdp->pending_evt_data = TRUE; - } - - if (ntoh16(skb->protocol) != ETHER_TYPE_BRCM) { -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); -#else - PKTFREE(dhdp->osh, pktbuf, FALSE); -#endif - continue; - } - } -#endif /* EVENT_DATA_HOSTWAKE */ - - if (!show_firstpkt) { - DHD_ERROR(("%s: First pkt, proto: 0x%x, drv_state %s", - __func__, ntoh16(skb->protocol), - get_dhd_drv_state_str(dhd_get_driver_state()))); - show_firstpkt = TRUE; - } - -#ifdef DHD_BUILTIN - driver_state = dhd_get_driver_state(); - if (driver_state == DHD_DRIVER_STATE_WARM_PARTIAL || - (driver_state == DHD_DRIVER_STATE_DOWN && - dhd_load_mode == DHD_LOAD_MODE_PARTIAL)) { - dhd_change_driver_state(DHD_DRIVER_STATE_PENDING_WAKE); - DHD_ERROR(("%s: data/event comes during partial warm boot\n", - __func__)); -#ifdef IDSUP_STATS - wl_state_event_sendup(wl_get_cfg(dhd_linux_get_primary_netdev(dhdp)), - ndev_to_cfgdev(dhd_linux_get_primary_netdev(dhdp)), - NULL, EVT_WAKE_PENDING, NULL); -#endif /* IDSUP_STATS */ - } -#endif /* DHD_BUILTIN */ - -#ifdef WLMEDIA_HTSF - dhd_htsf_addrxts(dhdp, pktbuf); -#endif -#ifdef DBG_PKT_MON - DHD_DBG_PKT_MON_RX(dhdp, skb); -#endif /* DBG_PKT_MON */ -#ifdef DHD_PKT_LOGGING - DHD_PKTLOG_RX(dhdp, skb); -#endif /* DHD_PKT_LOGGING */ - /* Strip header, count, deliver upward */ - skb_pull(skb, ETH_HLEN); - - /* Process special event packets and then discard them */ - memset(&event, 0, sizeof(event)); - - if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) { - bcm_event_msg_u_t evu; - int ret_event; - int event_type, event_reason; - - ret_event = wl_host_event_get_data( -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) - skb_mac_header(skb), -#else - skb->mac.raw, -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */ - len, &evu); - - if (ret_event != BCME_OK) { - DHD_ERROR(("%s: wl_host_event_get_data err = %d\n", - __FUNCTION__, ret_event)); -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); -#else - PKTFREE(dhdp->osh, pktbuf, FALSE); -#endif - continue; - } - - memcpy(&event, &evu.event, sizeof(wl_event_msg_t)); - event_type = ntoh32_ua((void *)&event.event_type); -#ifdef RELOAD_WIFI - event_reason = ntoh32_ua((void *)&event.reason); - if (event_type == WLC_E_RELOAD && - dhdp->fw_need_reload == NO_FW_RELOAD) { - DHD_ERROR(("Need reload FW, reason %d\n", event_reason)); - dhdp->fw_need_reload = FW_RELOAD_NEEDED; - dhdp->wifi_recover_reason = FW_RECOVER_BASE_RELOAD + event_reason; -#ifdef SDIO_TRAITS_STATS - switch(event_reason) { - case FW_RELOAD_BACKOFF_TYPE_PHY_REINIT: - dhd_bus_traits_fw_reload_phy_reinit_inc(); - break; - case FW_RELOAD_BACKOFF_TYPE_CONNECTION: - dhd_bus_traits_fw_reload_conn_stuck_inc(); - break; - case FW_RELOAD_BACKOFF_TYPE_DHCP: - dhd_bus_traits_fw_reload_dhcp_stuck_inc(); - break; - default: - break; - } -#endif /* SDIO_TRAITS_STATS */ - } -#endif /* RELOAD_WIFI */ -#ifdef SHOW_LOGTRACE - /* Event msg printing is called from dhd_rx_frame which is in Tasklet - * context in case of PCIe FD, in case of other bus this will be from - * DPC context. If we get bunch of events from Dongle then printing all - * of them from Tasklet/DPC context that too in data path is costly. - * Also in the new Dongle SW(4359, 4355 onwards) console prints too come as - * events with type WLC_E_TRACE. - * We'll print this console logs from the WorkQueue context by enqueing SKB - * here and Dequeuing will be done in WorkQueue and will be freed only if - * DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT is defined - */ - if (event_type == WLC_E_TRACE) { - DHD_TRACE(("%s: WLC_E_TRACE\n", __FUNCTION__)); - dhd_event_logtrace_enqueue(dhdp, ifidx, pktbuf); - continue; - } -#endif /* SHOW_LOGTRACE */ - -#ifdef EVENT_DATA_HOSTWAKE - if (!sendup) { - const char* event_name = bcmevent_get_name(event_type); - uint32 status = ntoh32_ua((void *)&event.status); - uint32 reason = ntoh32_ua((void *)&event.reason); - - dhd_msg_level |= DHD_EVENT_VAL; - DHD_ERROR(("MACEVENT: %s(%d), status %u, reason %u\n", - event_name, event_type, status, reason)); -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); -#else - PKTFREE(dhdp->osh, pktbuf, FALSE); -#endif - continue; - } else { - dhd_msg_level &= ~DHD_EVENT_VAL; - } -#endif /* EVENT_DATA_HOSTWAKE */ - - ret_event = dhd_wl_host_event(dhd, ifidx, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) - skb_mac_header(skb), -#else - skb->mac.raw, -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) */ - len, &event, &data); - - wl_event_to_host_order(&event); - if (!tout_ctrl) - tout_ctrl = DHD_PACKET_TIMEOUT_MS; - -#if defined(PNO_SUPPORT) - if (event_type == WLC_E_PFN_NET_FOUND) { - /* enforce custom wake lock to garantee that Kernel not suspended */ - tout_ctrl = CUSTOM_PNO_EVENT_LOCK_xTIME * DHD_PACKET_TIMEOUT_MS; - } -#endif /* PNO_SUPPORT */ - if (numpkt != 1) { - DHD_TRACE(("%s: Got BRCM event packet in a chained packet.\n", - __FUNCTION__)); - } - -#ifdef DHD_WAKE_STATUS - if (unlikely(pkt_wake)) { -#ifdef DHD_WAKE_EVENT_STATUS - if (event.event_type < WLC_E_LAST) { - wcp->rc_event[event.event_type]++; -#ifdef WIFI_STATS - if (wcp->rcwake < 4) - wcp->event[wcp->rcwake] = event.event_type + 1; -#endif /* WIFI_STATS */ - wcp->rcwake++; - pkt_wake = 0; - } -#endif /* DHD_WAKE_EVENT_STATUS */ - } -#endif /* DHD_WAKE_STATUS */ - - /* For delete virtual interface event, wl_host_event returns positive - * i/f index, do not proceed. just free the pkt. - */ - if ((event_type == WLC_E_IF) && (ret_event > 0)) { - DHD_ERROR(("%s: interface is deleted. Free event packet\n", - __FUNCTION__)); -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); -#else - PKTFREE(dhdp->osh, pktbuf, FALSE); -#endif - continue; - } - -#ifdef DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); -#else - PKTFREE(dhdp->osh, pktbuf, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ - continue; -#else - /* - * For the event packets, there is a possibility - * of ifidx getting modifed.Thus update the ifp - * once again. - */ - ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); - ifp = dhd->iflist[ifidx]; -#ifndef PROP_TXSTATUS_VSDB - if (!(ifp && ifp->net && (ifp->net->reg_state == NETREG_REGISTERED))) -#else - if (!(ifp && ifp->net && (ifp->net->reg_state == NETREG_REGISTERED) && - dhd->pub.up)) -#endif /* PROP_TXSTATUS_VSDB */ - { - DHD_INFO(("%s: net device is NOT registered. drop event packet\n", - __FUNCTION__)); -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhdp->osh, pktbuf, FALSE); -#else - PKTFREE(dhdp->osh, pktbuf, FALSE); -#endif - continue; - } -#endif /* DHD_DONOT_FORWARD_BCMEVENT_AS_NETWORK_PKT */ - } else { - tout_rx = DHD_PACKET_TIMEOUT_MS; - -#ifdef PROP_TXSTATUS - dhd_wlfc_save_rxpath_ac_time(dhdp, (uint8)PKTPRIO(skb)); -#endif /* PROP_TXSTATUS */ - -#ifdef DHD_WAKE_STATUS - if (unlikely(pkt_wake)) { - wcp->rxwake++; -#ifdef DHD_WAKE_RX_STATUS -#define ETHER_ICMP6_HEADER 20 -#define ETHER_IPV6_SADDR (ETHER_ICMP6_HEADER + 2) -#define ETHER_IPV6_DAADR (ETHER_IPV6_SADDR + IPV6_ADDR_LEN) -#define ETHER_ICMPV6_TYPE (ETHER_IPV6_DAADR + IPV6_ADDR_LEN) - - if (ntoh16(skb->protocol) == ETHER_TYPE_ARP) /* ARP */ - wcp->rx_arp++; - if (dump_data[0] == 0xFF) { /* Broadcast */ - wcp->rx_bcast++; - } else if (dump_data[0] & 0x01) { /* Multicast */ - wcp->rx_mcast++; - if (ntoh16(skb->protocol) == ETHER_TYPE_IPV6) { - wcp->rx_multi_ipv6++; - if ((skb->len > ETHER_ICMP6_HEADER) && - (dump_data[ETHER_ICMP6_HEADER] == IPPROTO_ICMPV6)) { - wcp->rx_icmpv6++; - if (skb->len > ETHER_ICMPV6_TYPE) { - switch (dump_data[ETHER_ICMPV6_TYPE]) { - case NDISC_ROUTER_ADVERTISEMENT: - wcp->rx_icmpv6_ra++; - break; - case NDISC_NEIGHBOUR_ADVERTISEMENT: - wcp->rx_icmpv6_na++; - break; - case NDISC_NEIGHBOUR_SOLICITATION: - wcp->rx_icmpv6_ns++; - break; - } - } - } - } else if (dump_data[2] == 0x5E) { - wcp->rx_multi_ipv4++; - } else { - wcp->rx_multi_other++; - } - } else { /* Unicast */ - wcp->rx_ucast++; - } -#undef ETHER_ICMP6_HEADER -#undef ETHER_IPV6_SADDR -#undef ETHER_IPV6_DAADR -#undef ETHER_ICMPV6_TYPE -#endif /* DHD_WAKE_RX_STATUS */ - pkt_wake = 0; - } -#endif /* DHD_WAKE_STATUS */ - } - - /* Dropping only data packets before registering net device to avoid kernel panic */ -#ifndef PROP_TXSTATUS_VSDB - if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED) && - (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) -#else - if ((!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) && - (ntoh16(eh->ether_type) != ETHER_TYPE_BRCM)) -#endif /* PROP_TXSTATUS_VSDB */ - { -#ifndef TCPKA_REPAIR - DHD_INFO(("%s: net device is NOT registered yet. drop packet\n", - __FUNCTION__)); - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; -#else - DHD_INFO(("%s: net device is NOT registered yet. drop packet, q_pkt %d\n", - __FUNCTION__, queue_this_pkt)); - if (!queue_this_pkt) { - PKTCFREE(dhdp->osh, pktbuf, FALSE); - continue; - } -#endif /* TCPKA_REPAIR */ - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) - if (ifp->net) - ifp->net->last_rx = jiffies; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) */ - - if (ntoh16(skb->protocol) != ETHER_TYPE_BRCM) { - dhdp->dstats.rx_bytes += skb->len; - dhdp->rx_packets++; /* Local count */ - ifp->stats.rx_bytes += skb->len; - ifp->stats.rx_packets++; - } - -#ifdef TCPKA_REPAIR - if (queue_this_pkt) { - DHD_TRACE(("%s: put pkt %p into queue\n", __func__, skb)); - PKTSETNEXT(dhdp->osh, skb, NULL); - if (!tcpka_sync.tcpka_rp.skbhead) - tcpka_sync.tcpka_rp.skbhead = skb; - else - PKTSETNEXT(dhdp->osh, tcpka_sync.tcpka_rp.skbprev, skb); - tcpka_sync.tcpka_rp.skbprev = skb; - tcpka_sync.tcpka_rp.pkt_in_q_num++; - DHD_PKTTAG_SET_IFIDX((dhd_pkttag_rx_t *)PKTTAG(skb), ifidx); - } else -#endif /* TCPKA_REPAIR */ - if (in_interrupt()) { - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, - __FUNCTION__, __LINE__); - DHD_PERIM_UNLOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); -#if defined(DHD_LB_RXP) - netif_receive_skb(skb); -#else /* !defined(DHD_LB_RXP) */ - netif_rx(skb); -#endif /* !defined(DHD_LB_RXP) */ - DHD_PERIM_LOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); - } else { - if (dhd->rxthread_enabled) { - if (!skbhead) - skbhead = skb; - else - PKTSETNEXT(dhdp->osh, skbprev, skb); - skbprev = skb; - } else { - - /* If the receive is not processed inside an ISR, - * the softirqd must be woken explicitly to service - * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled - * by netif_rx_ni(), but in earlier kernels, we need - * to do it manually. - */ - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, - __FUNCTION__, __LINE__); - -#if defined(DHD_LB_RXP) - DHD_PERIM_UNLOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); - netif_receive_skb(skb); - DHD_PERIM_LOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); -#else /* !defined(DHD_LB_RXP) */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - DHD_PERIM_UNLOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); - netif_rx_ni(skb); - DHD_PERIM_LOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); -#else - ulong flags; - DHD_PERIM_UNLOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); - netif_rx(skb); - DHD_PERIM_LOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); - local_irq_save(flags); - RAISE_RX_SOFTIRQ(); - local_irq_restore(flags); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ -#endif /* !defined(DHD_LB_RXP) */ - } - } - } - - if (dhd->rxthread_enabled && skbhead) - dhd_sched_rxf(dhdp, skbhead); - - DHD_OS_WAKE_LOCK_RX_TIMEOUT_ENABLE(dhdp, tout_rx); - DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(dhdp, tout_ctrl); -} - -void -dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx) -{ - /* Linux version has nothing to do */ - return; -} - -void -dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) -{ - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - struct ether_header *eh; - uint16 type; - - dhd_prot_hdrpull(dhdp, NULL, txp, NULL, NULL); - - - eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); - type = ntoh16(eh->ether_type); - - if ((type == ETHER_TYPE_802_1X) && (dhd_get_pend_8021x_cnt(dhd) > 0)) { - atomic_dec(&dhd->pend_8021x_cnt); - } - -#ifdef PROP_TXSTATUS - if (dhdp->wlfc_state && (dhdp->proptxstatus_mode != WLFC_FCMODE_NONE)) { - dhd_if_t *ifp = dhd->iflist[DHD_PKTTAG_IF(PKTTAG(txp))]; - uint datalen = PKTLEN(dhd->pub.osh, txp); - if (ifp != NULL) { - if (success) { - dhd->pub.tx_packets++; - ifp->stats.tx_packets++; - ifp->stats.tx_bytes += datalen; - } else { - ifp->stats.tx_dropped++; - } - } - } -#endif -} - -static struct net_device_stats * -dhd_get_stats(struct net_device *net) -{ - dhd_info_t *dhd = DHD_DEV_INFO(net); - dhd_if_t *ifp; - int ifidx; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!dhd) { - DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); - goto error; - } - - ifidx = dhd_net2idx(dhd, net); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__)); - goto error; - } - - ifp = dhd->iflist[ifidx]; - - if (!ifp) { - ASSERT(ifp); - DHD_ERROR(("%s: ifp is NULL\n", __FUNCTION__)); - goto error; - } - - if (dhd->pub.up) { - /* Use the protocol to get dongle stats */ - dhd_prot_dstats(&dhd->pub); - } - return &ifp->stats; - -error: - memset(&net->stats, 0, sizeof(net->stats)); - return &net->stats; -} - -#ifndef BCMDBUS -static int -dhd_watchdog_thread(void *data) -{ - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - dhd_info_t *dhd = (dhd_info_t *)tsk->parent; - /* This thread doesn't need any user-level access, - * so get rid of all our resources - */ - if (dhd_watchdog_prio > 0) { - struct sched_param param; - param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)? - dhd_watchdog_prio:(MAX_RT_PRIO-1); - setScheduler(current, SCHED_FIFO, ¶m); - } - - while (1) { - if (down_interruptible (&tsk->sema) == 0) { - unsigned long flags; - unsigned long jiffies_at_start = jiffies; - unsigned long time_lapse; - DHD_OS_WD_WAKE_LOCK(&dhd->pub); - - SMP_RD_BARRIER_DEPENDS(); - if (tsk->terminated) { - break; - } - - if (dhd->pub.dongle_reset == FALSE) { - DHD_TIMER(("%s:\n", __FUNCTION__)); - dhd_bus_watchdog(&dhd->pub); - -#ifdef DHD_TIMESYNC - /* Call the timesync module watchdog */ - dhd_timesync_watchdog(&dhd->pub); -#endif /* DHD_TIMESYNC */ - - DHD_GENERAL_LOCK(&dhd->pub, flags); - /* Count the tick for reference */ - dhd->pub.tickcnt++; -#ifdef DHD_L2_FILTER - dhd_l2_filter_watchdog(&dhd->pub); -#endif /* DHD_L2_FILTER */ - time_lapse = jiffies - jiffies_at_start; - - /* Reschedule the watchdog */ - if (dhd->wd_timer_valid) { - mod_timer(&dhd->timer, - jiffies + - msecs_to_jiffies(dhd_watchdog_ms) - - min(msecs_to_jiffies(dhd_watchdog_ms), time_lapse)); - } - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - } - DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); - } else { - break; - } - } - - complete_and_exit(&tsk->completed, 0); -} - -static void dhd_watchdog( -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) - struct timer_list *t -#else - ulong data -#endif -) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) - dhd_info_t *dhd = from_timer(dhd, t, timer); -#else - dhd_info_t *dhd = (dhd_info_t *)data; -#endif - unsigned long flags; - - if (dhd->pub.dongle_reset) { - return; - } - - if (dhd->thr_wdt_ctl.thr_pid >= 0) { - up(&dhd->thr_wdt_ctl.sema); - return; - } - - DHD_OS_WD_WAKE_LOCK(&dhd->pub); - /* Call the bus module watchdog */ - dhd_bus_watchdog(&dhd->pub); - -#ifdef DHD_TIMESYNC - /* Call the timesync module watchdog */ - dhd_timesync_watchdog(&dhd->pub); -#endif /* DHD_TIMESYNC */ - - DHD_GENERAL_LOCK(&dhd->pub, flags); - /* Count the tick for reference */ - dhd->pub.tickcnt++; - -#ifdef DHD_L2_FILTER - dhd_l2_filter_watchdog(&dhd->pub); -#endif /* DHD_L2_FILTER */ - /* Reschedule the watchdog */ - if (dhd->wd_timer_valid) - mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); -} - -#ifdef DHD_PCIE_RUNTIMEPM -static int -dhd_rpm_state_thread(void *data) -{ - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - dhd_info_t *dhd = (dhd_info_t *)tsk->parent; - - while (1) { - if (down_interruptible (&tsk->sema) == 0) { - unsigned long flags; - unsigned long jiffies_at_start = jiffies; - unsigned long time_lapse; - - SMP_RD_BARRIER_DEPENDS(); - if (tsk->terminated) { - break; - } - - if (dhd->pub.dongle_reset == FALSE) { - DHD_TIMER(("%s:\n", __FUNCTION__)); - if (dhd->pub.up) { - dhd_runtimepm_state(&dhd->pub); - } - - DHD_GENERAL_LOCK(&dhd->pub, flags); - time_lapse = jiffies - jiffies_at_start; - - /* Reschedule the watchdog */ - if (dhd->rpm_timer_valid) { - mod_timer(&dhd->rpm_timer, - jiffies + - msecs_to_jiffies(dhd_runtimepm_ms) - - min(msecs_to_jiffies(dhd_runtimepm_ms), - time_lapse)); - } - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - } - } else { - break; - } - } - - complete_and_exit(&tsk->completed, 0); -} - -static void dhd_runtimepm( -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) - struct timer_list *t -#else - ulong data -#endif -) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) - dhd_info_t *dhd = from_timer(dhd, t, rpm_timer); -#else - dhd_info_t *dhd = (dhd_info_t *)data; -#endif - - if (dhd->pub.dongle_reset) { - return; - } - - if (dhd->thr_rpm_ctl.thr_pid >= 0) { - up(&dhd->thr_rpm_ctl.sema); - return; - } -} - -void dhd_runtime_pm_disable(dhd_pub_t *dhdp) -{ - dhd_os_runtimepm_timer(dhdp, 0); - dhdpcie_runtime_bus_wake(dhdp, TRUE, __builtin_return_address(0)); - DHD_ERROR(("DHD Runtime PM Disabled \n")); -} - -void dhd_runtime_pm_enable(dhd_pub_t *dhdp) -{ - if (dhd_get_idletime(dhdp)) { - dhd_os_runtimepm_timer(dhdp, dhd_runtimepm_ms); - DHD_ERROR(("DHD Runtime PM Enabled \n")); - } -} - -#endif /* DHD_PCIE_RUNTIMEPM */ - - -#ifdef ENABLE_ADAPTIVE_SCHED -static void -dhd_sched_policy(int prio) -{ - struct sched_param param; - if (cpufreq_quick_get(0) <= CUSTOM_CPUFREQ_THRESH) { - param.sched_priority = 0; - setScheduler(current, SCHED_NORMAL, ¶m); - } else { - if (get_scheduler_policy(current) != SCHED_FIFO) { - param.sched_priority = (prio < MAX_RT_PRIO)? prio : (MAX_RT_PRIO-1); - setScheduler(current, SCHED_FIFO, ¶m); - } - } -} -#endif /* ENABLE_ADAPTIVE_SCHED */ -#ifdef DEBUG_CPU_FREQ -static int dhd_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data) -{ - dhd_info_t *dhd = container_of(nb, struct dhd_info, freq_trans); - struct cpufreq_freqs *freq = data; - if (dhd) { - if (!dhd->new_freq) - goto exit; - if (val == CPUFREQ_POSTCHANGE) { - DHD_ERROR(("cpu freq is changed to %u kHZ on CPU %d\n", - freq->new, freq->cpu)); - *per_cpu_ptr(dhd->new_freq, freq->cpu) = freq->new; - } - } -exit: - return 0; -} -#endif /* DEBUG_CPU_FREQ */ - -static int -dhd_dpc_thread(void *data) -{ - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - dhd_info_t *dhd = (dhd_info_t *)tsk->parent; - - /* This thread doesn't need any user-level access, - * so get rid of all our resources - */ - if (dhd_dpc_prio > 0) - { - struct sched_param param; - param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1); - setScheduler(current, SCHED_FIFO, ¶m); - } - -#ifdef CUSTOM_DPC_CPUCORE - set_cpus_allowed_ptr(current, cpumask_of(CUSTOM_DPC_CPUCORE)); -#endif -#ifdef CUSTOM_SET_CPUCORE - dhd->pub.current_dpc = current; -#endif /* CUSTOM_SET_CPUCORE */ - /* Run until signal received */ - while (1) { - if (dhd->pub.conf->dpc_cpucore >= 0) { - DHD_INFO(("%s: set dpc_cpucore %d\n", __FUNCTION__, dhd->pub.conf->dpc_cpucore)); - set_cpus_allowed_ptr(current, cpumask_of(dhd->pub.conf->dpc_cpucore)); - dhd->pub.conf->dpc_cpucore = -1; - } - if (!binary_sema_down(tsk)) { -#ifdef ENABLE_ADAPTIVE_SCHED - dhd_sched_policy(dhd_dpc_prio); -#endif /* ENABLE_ADAPTIVE_SCHED */ - SMP_RD_BARRIER_DEPENDS(); - if (tsk->terminated) { - break; - } - - /* Call bus dpc unless it indicated down (then clean stop) */ - if (dhd->pub.busstate != DHD_BUS_DOWN) { -#ifdef DEBUG_DPC_THREAD_WATCHDOG - int resched_cnt = 0; -#endif /* DEBUG_DPC_THREAD_WATCHDOG */ - dhd_os_wd_timer_extend(&dhd->pub, TRUE); - while (dhd_bus_dpc(dhd->pub.bus)) { - /* process all data */ -#ifdef DEBUG_DPC_THREAD_WATCHDOG - resched_cnt++; - if (resched_cnt > MAX_RESCHED_CNT) { - DHD_INFO(("%s Calling msleep to" - "let other processes run. \n", - __FUNCTION__)); - dhd->pub.dhd_bug_on = true; - resched_cnt = 0; - OSL_SLEEP(1); - } -#endif /* DEBUG_DPC_THREAD_WATCHDOG */ - } - dhd_os_wd_timer_extend(&dhd->pub, FALSE); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - } else { - if (dhd->pub.up) - dhd_bus_stop(dhd->pub.bus, TRUE); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - } - } else { - break; - } - } - complete_and_exit(&tsk->completed, 0); -} - -static int -dhd_rxf_thread(void *data) -{ - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - dhd_info_t *dhd = (dhd_info_t *)tsk->parent; -#if defined(WAIT_DEQUEUE) -#define RXF_WATCHDOG_TIME 250 /* BARK_TIME(1000) / */ - ulong watchdogTime = OSL_SYSUPTIME(); /* msec */ -#endif - dhd_pub_t *pub = &dhd->pub; - - /* This thread doesn't need any user-level access, - * so get rid of all our resources - */ - if (dhd_rxf_prio > 0) - { - struct sched_param param; - param.sched_priority = (dhd_rxf_prio < MAX_RT_PRIO)?dhd_rxf_prio:(MAX_RT_PRIO-1); - setScheduler(current, SCHED_FIFO, ¶m); - } - -#ifdef CUSTOM_SET_CPUCORE - dhd->pub.current_rxf = current; -#endif /* CUSTOM_SET_CPUCORE */ - /* Run until signal received */ - while (1) { - if (dhd->pub.conf->rxf_cpucore >= 0) { - DHD_INFO(("%s: set rxf_cpucore %d\n", __FUNCTION__, dhd->pub.conf->rxf_cpucore)); - set_cpus_allowed_ptr(current, cpumask_of(dhd->pub.conf->rxf_cpucore)); - dhd->pub.conf->rxf_cpucore = -1; - } - if (down_interruptible(&tsk->sema) == 0) { - void *skb; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) - ulong flags; -#endif -#ifdef ENABLE_ADAPTIVE_SCHED - dhd_sched_policy(dhd_rxf_prio); -#endif /* ENABLE_ADAPTIVE_SCHED */ - - SMP_RD_BARRIER_DEPENDS(); - - if (tsk->terminated) { - break; - } - skb = dhd_rxf_dequeue(pub); - - if (skb == NULL) { - continue; - } - while (skb) { - void *skbnext = PKTNEXT(pub->osh, skb); - PKTSETNEXT(pub->osh, skb, NULL); - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, - __FUNCTION__, __LINE__); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - netif_rx_ni(skb); -#else - netif_rx(skb); - local_irq_save(flags); - RAISE_RX_SOFTIRQ(); - local_irq_restore(flags); - -#endif - skb = skbnext; - } -#if defined(WAIT_DEQUEUE) - if (OSL_SYSUPTIME() - watchdogTime > RXF_WATCHDOG_TIME) { - OSL_SLEEP(1); - watchdogTime = OSL_SYSUPTIME(); - } -#endif - - DHD_OS_WAKE_UNLOCK(pub); - } else { - break; - } - } - complete_and_exit(&tsk->completed, 0); -} - -#ifdef BCMPCIE -void dhd_dpc_enable(dhd_pub_t *dhdp) -{ -#if defined(DHD_LB_RXP) || defined(DHD_LB_TXP) - dhd_info_t *dhd; - - if (!dhdp || !dhdp->info) - return; - dhd = dhdp->info; -#endif /* DHD_LB_RXP || DHD_LB_TXP */ - -#ifdef DHD_LB_RXP - __skb_queue_head_init(&dhd->rx_pend_queue); -#endif /* DHD_LB_RXP */ - -#ifdef DHD_LB_TXP - skb_queue_head_init(&dhd->tx_pend_queue); -#endif /* DHD_LB_TXP */ -} -#endif /* BCMPCIE */ - -#ifdef BCMPCIE -void -dhd_dpc_kill(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - - if (!dhdp) { - return; - } - - dhd = dhdp->info; - - if (!dhd) { - return; - } - - if (dhd->thr_dpc_ctl.thr_pid < 0) { - tasklet_kill(&dhd->tasklet); - DHD_ERROR(("%s: tasklet disabled\n", __FUNCTION__)); - } - -#ifdef DHD_LB -#ifdef DHD_LB_RXP - cancel_work_sync(&dhd->rx_napi_dispatcher_work); - __skb_queue_purge(&dhd->rx_pend_queue); -#endif /* DHD_LB_RXP */ -#ifdef DHD_LB_TXP - cancel_work_sync(&dhd->tx_dispatcher_work); - skb_queue_purge(&dhd->tx_pend_queue); -#endif /* DHD_LB_TXP */ - - /* Kill the Load Balancing Tasklets */ -#if defined(DHD_LB_TXC) - tasklet_kill(&dhd->tx_compl_tasklet); -#endif /* DHD_LB_TXC */ -#if defined(DHD_LB_RXC) - tasklet_kill(&dhd->rx_compl_tasklet); -#endif /* DHD_LB_RXC */ -#if defined(DHD_LB_TXP) - tasklet_kill(&dhd->tx_tasklet); -#endif /* DHD_LB_TXP */ -#endif /* DHD_LB */ -} - -void -dhd_dpc_tasklet_kill(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - - if (!dhdp) { - return; - } - - dhd = dhdp->info; - - if (!dhd) { - return; - } - - if (dhd->thr_dpc_ctl.thr_pid < 0) { - tasklet_kill(&dhd->tasklet); - } -} -#endif /* BCMPCIE */ - -static void -dhd_dpc(ulong data) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)data; - - /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c] - * down below , wake lock is set, - * the tasklet is initialized in dhd_attach() - */ - /* Call bus dpc unless it indicated down (then clean stop) */ - if (dhd->pub.busstate != DHD_BUS_DOWN) { -#if defined(DHD_LB_STATS) && defined(PCIE_FULL_DONGLE) - DHD_LB_STATS_INCR(dhd->dhd_dpc_cnt); -#endif /* DHD_LB_STATS && PCIE_FULL_DONGLE */ - if (dhd_bus_dpc(dhd->pub.bus)) { - tasklet_schedule(&dhd->tasklet); - } - } else { - dhd_bus_stop(dhd->pub.bus, TRUE); - } -} - -void -dhd_sched_dpc(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - - if (dhd->thr_dpc_ctl.thr_pid >= 0) { - DHD_OS_WAKE_LOCK(dhdp); - /* If the semaphore does not get up, - * wake unlock should be done here - */ - if (!binary_sema_up(&dhd->thr_dpc_ctl)) { - DHD_OS_WAKE_UNLOCK(dhdp); - } - return; - } else { - tasklet_schedule(&dhd->tasklet); - } -} -#endif /* BCMDBUS */ - -static void -dhd_sched_rxf(dhd_pub_t *dhdp, void *skb) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; -#ifdef RXF_DEQUEUE_ON_BUSY - int ret = BCME_OK; - int retry = 2; -#endif /* RXF_DEQUEUE_ON_BUSY */ - - DHD_OS_WAKE_LOCK(dhdp); - - DHD_TRACE(("dhd_sched_rxf: Enter\n")); -#ifdef RXF_DEQUEUE_ON_BUSY - do { - ret = dhd_rxf_enqueue(dhdp, skb); - if (ret == BCME_OK || ret == BCME_ERROR) - break; - else - OSL_SLEEP(50); /* waiting for dequeueing */ - } while (retry-- > 0); - - if (retry <= 0 && ret == BCME_BUSY) { - void *skbp = skb; - - while (skbp) { - void *skbnext = PKTNEXT(dhdp->osh, skbp); - PKTSETNEXT(dhdp->osh, skbp, NULL); - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, - __FUNCTION__, __LINE__); - netif_rx_ni(skbp); - skbp = skbnext; - } - DHD_ERROR(("send skb to kernel backlog without rxf_thread\n")); - } else { - if (dhd->thr_rxf_ctl.thr_pid >= 0) { - up(&dhd->thr_rxf_ctl.sema); - } - } -#else /* RXF_DEQUEUE_ON_BUSY */ - do { - if (dhd_rxf_enqueue(dhdp, skb) == BCME_OK) - break; - } while (1); - if (dhd->thr_rxf_ctl.thr_pid >= 0) { - up(&dhd->thr_rxf_ctl.sema); - } - return; -#endif /* RXF_DEQUEUE_ON_BUSY */ -} - -#if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) -#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */ - -#ifdef TOE -/* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */ -static int -dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol) -{ - char buf[32]; - int ret; - - ret = dhd_iovar(&dhd->pub, ifidx, "toe_ol", NULL, 0, (char *)&buf, sizeof(buf), FALSE); - - if (ret < 0) { - if (ret == -EIO) { - DHD_ERROR(("%s: toe not supported by device\n", dhd_ifname(&dhd->pub, - ifidx))); - return -EOPNOTSUPP; - } - - DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); - return ret; - } - - memcpy(toe_ol, buf, sizeof(uint32)); - return 0; -} - -/* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */ -static int -dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol) -{ - int toe, ret; - - /* Set toe_ol as requested */ - ret = dhd_iovar(&dhd->pub, ifidx, "toe_ol", (char *)&toe_ol, sizeof(toe_ol), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: could not set toe_ol: ret=%d\n", - dhd_ifname(&dhd->pub, ifidx), ret)); - return ret; - } - - /* Enable toe globally only if any components are enabled. */ - toe = (toe_ol != 0); - ret = dhd_iovar(&dhd->pub, ifidx, "toe", (char *)&toe, sizeof(toe), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); - return ret; - } - - return 0; -} -#endif /* TOE */ - -#if defined(WL_CFG80211) && defined(NUM_SCB_MAX_PROBE) -void dhd_set_scb_probe(dhd_pub_t *dhd) -{ - wl_scb_probe_t scb_probe; - int ret; - - if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { - return; - } - - ret = dhd_iovar(dhd, 0, "scb_probe", NULL, 0, - (char *)&scb_probe, sizeof(scb_probe), FALSE); - if (ret < 0) { - DHD_ERROR(("%s: GET max_scb_probe failed\n", __FUNCTION__)); - } - - scb_probe.scb_max_probe = NUM_SCB_MAX_PROBE; - - ret = dhd_iovar(dhd, 0, "scb_probe", (char *)&scb_probe, sizeof(scb_probe), - NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: max_scb_probe setting failed\n", __FUNCTION__)); - return; - } -} -#endif /* WL_CFG80211 && NUM_SCB_MAX_PROBE */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -static void -dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) -{ - dhd_info_t *dhd = DHD_DEV_INFO(net); - - snprintf(info->driver, sizeof(info->driver), "wl"); - snprintf(info->version, sizeof(info->version), "%lu", dhd->pub.drv_version); -} - -struct ethtool_ops dhd_ethtool_ops = { - .get_drvinfo = dhd_ethtool_get_drvinfo -}; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ - - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) -static int -dhd_ethtool(dhd_info_t *dhd, void *uaddr) -{ - struct ethtool_drvinfo info; - char drvname[sizeof(info.driver)]; - uint32 cmd; -#ifdef TOE - struct ethtool_value edata; - uint32 toe_cmpnt, csum_dir; - int ret; -#endif - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* all ethtool calls start with a cmd word */ - if (copy_from_user(&cmd, uaddr, sizeof (uint32))) - return -EFAULT; - - switch (cmd) { - case ETHTOOL_GDRVINFO: - /* Copy out any request driver name */ - if (copy_from_user(&info, uaddr, sizeof(info))) - return -EFAULT; - strncpy(drvname, info.driver, sizeof(info.driver)); - drvname[sizeof(info.driver)-1] = '\0'; - - /* clear struct for return */ - memset(&info, 0, sizeof(info)); - info.cmd = cmd; - - /* if dhd requested, identify ourselves */ - if (strcmp(drvname, "?dhd") == 0) { - snprintf(info.driver, sizeof(info.driver), "dhd"); - strncpy(info.version, EPI_VERSION_STR, sizeof(info.version) - 1); - info.version[sizeof(info.version) - 1] = '\0'; - } - - /* otherwise, require dongle to be up */ - else if (!dhd->pub.up) { - DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__)); - return -ENODEV; - } - - /* finally, report dongle driver type */ - else if (dhd->pub.iswl) - snprintf(info.driver, sizeof(info.driver), "wl"); - else - snprintf(info.driver, sizeof(info.driver), "xx"); - - snprintf(info.version, sizeof(info.version), "%lu", dhd->pub.drv_version); - if (copy_to_user(uaddr, &info, sizeof(info))) - return -EFAULT; - DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__, - (int)sizeof(drvname), drvname, info.driver)); - break; - -#ifdef TOE - /* Get toe offload components from dongle */ - case ETHTOOL_GRXCSUM: - case ETHTOOL_GTXCSUM: - if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0) - return ret; - - csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; - - edata.cmd = cmd; - edata.data = (toe_cmpnt & csum_dir) ? 1 : 0; - - if (copy_to_user(uaddr, &edata, sizeof(edata))) - return -EFAULT; - break; - - /* Set toe offload components in dongle */ - case ETHTOOL_SRXCSUM: - case ETHTOOL_STXCSUM: - if (copy_from_user(&edata, uaddr, sizeof(edata))) - return -EFAULT; - - /* Read the current settings, update and write back */ - if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0) - return ret; - - csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; - - if (edata.data != 0) - toe_cmpnt |= csum_dir; - else - toe_cmpnt &= ~csum_dir; - - if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0) - return ret; - - /* If setting TX checksum mode, tell Linux the new mode */ - if (cmd == ETHTOOL_STXCSUM) { - if (edata.data) - dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM; - else - dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM; - } - - break; -#endif /* TOE */ - - default: - return -EOPNOTSUPP; - } - - return 0; -} -#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ - -static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) -{ - if (!dhdp) { - DHD_ERROR(("%s: dhdp is NULL\n", __FUNCTION__)); - return FALSE; - } - - if (!dhdp->up) - return FALSE; - -#if !defined(BCMPCIE) && !defined(BCMDBUS) - if (dhdp->info->thr_dpc_ctl.thr_pid < 0) { - DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__)); - return FALSE; - } -#endif /* !BCMPCIE && !BCMDBUS */ - - if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) || - ((dhdp->busstate == DHD_BUS_DOWN) && (!dhdp->dongle_reset))) { -#ifdef BCMPCIE - DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d d3acke=%d e=%d s=%d\n", - __FUNCTION__, dhdp->rxcnt_timeout, dhdp->txcnt_timeout, - dhdp->d3ackcnt_timeout, error, dhdp->busstate)); -#else - DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, - dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate)); -#endif /* BCMPCIE */ - if (dhdp->hang_reason == 0) { - if (dhdp->dongle_trap_occured) { - dhdp->hang_reason = HANG_REASON_DONGLE_TRAP; -#ifdef BCMPCIE - } else if (dhdp->d3ackcnt_timeout) { - dhdp->hang_reason = HANG_REASON_D3_ACK_TIMEOUT; -#endif /* BCMPCIE */ - } else { - dhdp->hang_reason = HANG_REASON_IOCTL_RESP_TIMEOUT; - } - } - net_os_send_hang_message(net); - return TRUE; - } - return FALSE; -} - -#ifdef WL_MONITOR -bool -dhd_monitor_enabled(dhd_pub_t *dhd, int ifidx) -{ - return (dhd->info->monitor_type != 0); -} - -void -dhd_rx_mon_pkt(dhd_pub_t *dhdp, host_rxbuf_cmpl_t* msg, void *pkt, int ifidx) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; -#ifdef HOST_RADIOTAP_CONV - uint16 len = 0, offset = 0; - monitor_pkt_info_t pkt_info; - memcpy(&pkt_info.marker, &msg->marker, sizeof(msg->marker)); - memcpy(&pkt_info.ts, &msg->ts, sizeof(monitor_pkt_ts_t)); - - if (!dhd->monitor_skb) { - if ((dhd->monitor_skb = dev_alloc_skb(MAX_MON_PKT_SIZE)) == NULL) - return; - } - - len = bcmwifi_monitor(dhd->monitor_info, &pkt_info, PKTDATA(dhdp->osh, pkt), - PKTLEN(dhdp->osh, pkt), PKTDATA(dhdp->osh, dhd->monitor_skb), &offset); - - if (dhd->monitor_type && dhd->monitor_dev) - dhd->monitor_skb->dev = dhd->monitor_dev; - else { - PKTFREE(dhdp->osh, pkt, FALSE); - dev_kfree_skb(dhd->monitor_skb); - return; - } - - PKTFREE(dhdp->osh, pkt, FALSE); - - if (!len) { - return; - } - - skb_put(dhd->monitor_skb, len); - skb_pull(dhd->monitor_skb, offset); - - dhd->monitor_skb->protocol = eth_type_trans(dhd->monitor_skb, dhd->monitor_skb->dev); -#else - uint8 amsdu_flag = (msg->flags & BCMPCIE_PKT_FLAGS_MONITOR_MASK) >> - BCMPCIE_PKT_FLAGS_MONITOR_SHIFT; - switch (amsdu_flag) { - case BCMPCIE_PKT_FLAGS_MONITOR_NO_AMSDU: - default: - if (!dhd->monitor_skb) { - if ((dhd->monitor_skb = PKTTONATIVE(dhdp->osh, pkt)) == NULL) - return; - } - - if (dhd->monitor_type && dhd->monitor_dev) - dhd->monitor_skb->dev = dhd->monitor_dev; - else { - PKTFREE(dhdp->osh, pkt, FALSE); - dhd->monitor_skb = NULL; - return; - } - - dhd->monitor_skb->protocol = - eth_type_trans(dhd->monitor_skb, dhd->monitor_skb->dev); - dhd->monitor_len = 0; - break; - case BCMPCIE_PKT_FLAGS_MONITOR_FIRST_PKT: - if (!dhd->monitor_skb) { - if ((dhd->monitor_skb = dev_alloc_skb(MAX_MON_PKT_SIZE)) == NULL) - return; - dhd->monitor_len = 0; - } - if (dhd->monitor_type && dhd->monitor_dev) - dhd->monitor_skb->dev = dhd->monitor_dev; - else { - PKTFREE(dhdp->osh, pkt, FALSE); - dev_kfree_skb(dhd->monitor_skb); - return; - } - memcpy(PKTDATA(dhdp->osh, dhd->monitor_skb), - PKTDATA(dhdp->osh, pkt), PKTLEN(dhdp->osh, pkt)); - - dhd->monitor_len = PKTLEN(dhdp->osh, pkt); - PKTFREE(dhdp->osh, pkt, FALSE); - return; - case BCMPCIE_PKT_FLAGS_MONITOR_INTER_PKT: - memcpy(PKTDATA(dhdp->osh, dhd->monitor_skb) + dhd->monitor_len, - PKTDATA(dhdp->osh, pkt), PKTLEN(dhdp->osh, pkt)); - dhd->monitor_len += PKTLEN(dhdp->osh, pkt); - - PKTFREE(dhdp->osh, pkt, FALSE); - return; - case BCMPCIE_PKT_FLAGS_MONITOR_LAST_PKT: - memcpy(PKTDATA(dhdp->osh, dhd->monitor_skb) + dhd->monitor_len, - PKTDATA(dhdp->osh, pkt), PKTLEN(dhdp->osh, pkt)); - dhd->monitor_len += PKTLEN(dhdp->osh, pkt); - - PKTFREE(dhdp->osh, pkt, FALSE); - skb_put(dhd->monitor_skb, dhd->monitor_len); - dhd->monitor_skb->protocol = - eth_type_trans(dhd->monitor_skb, dhd->monitor_skb->dev); - dhd->monitor_len = 0; - break; - } - -#endif /* HOST_RADIOTAP_CONV */ - if (in_interrupt()) { - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, - __FUNCTION__, __LINE__); - DHD_PERIM_UNLOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); - netif_rx(dhd->monitor_skb); - DHD_PERIM_LOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); - } else { - /* If the receive is not processed inside an ISR, - * the softirqd must be woken explicitly to service - * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled - * by netif_rx_ni(), but in earlier kernels, we need - * to do it manually. - */ - bcm_object_trace_opr(dhd->monitor_skb, BCM_OBJDBG_REMOVE, - __FUNCTION__, __LINE__); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - DHD_PERIM_UNLOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); - netif_rx_ni(dhd->monitor_skb); - DHD_PERIM_LOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); -#else - ulong flags; - DHD_PERIM_UNLOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); - netif_rx(dhd->monitor_skb); - DHD_PERIM_LOCK_ALL((dhd->fwder_unit % FWDER_MAX_UNIT)); - local_irq_save(flags); - RAISE_RX_SOFTIRQ(); - local_irq_restore(flags); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ - } - - dhd->monitor_skb = NULL; -} - -typedef struct dhd_mon_dev_priv { - struct net_device_stats stats; -} dhd_mon_dev_priv_t; - -#define DHD_MON_DEV_PRIV_SIZE (sizeof(dhd_mon_dev_priv_t)) -#define DHD_MON_DEV_PRIV(dev) ((dhd_mon_dev_priv_t *)DEV_PRIV(dev)) -#define DHD_MON_DEV_STATS(dev) (((dhd_mon_dev_priv_t *)DEV_PRIV(dev))->stats) - -static int -dhd_monitor_start(struct sk_buff *skb, struct net_device *dev) -{ - PKTFREE(NULL, skb, FALSE); - return 0; -} - -static int -dhd_monitor_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - return 0; -} - -static struct net_device_stats* -dhd_monitor_get_stats(struct net_device *dev) -{ - return &DHD_MON_DEV_STATS(dev); -} - -static const struct net_device_ops netdev_monitor_ops = -{ - .ndo_start_xmit = dhd_monitor_start, - .ndo_get_stats = dhd_monitor_get_stats, - .ndo_do_ioctl = dhd_monitor_ioctl -}; - -static void -dhd_add_monitor_if(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - struct net_device *dev; - char *devname; - - if (event != DHD_WQ_WORK_IF_ADD) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - dev = alloc_etherdev(DHD_MON_DEV_PRIV_SIZE); - if (!dev) { - DHD_ERROR(("%s: alloc wlif failed\n", __FUNCTION__)); - return; - } - - devname = "radiotap"; - - snprintf(dev->name, sizeof(dev->name), "%s%u", devname, dhd->unit); - -#ifndef ARPHRD_IEEE80211_PRISM /* From Linux 2.4.18 */ -#define ARPHRD_IEEE80211_PRISM 802 -#endif - -#ifndef ARPHRD_IEEE80211_RADIOTAP -#define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */ -#endif /* ARPHRD_IEEE80211_RADIOTAP */ - - dev->type = ARPHRD_IEEE80211_RADIOTAP; - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - dev->hard_start_xmit = dhd_monitor_start; - dev->do_ioctl = dhd_monitor_ioctl; - dev->get_stats = dhd_monitor_get_stats; -#else - dev->netdev_ops = &netdev_monitor_ops; -#endif - - if (register_netdev(dev)) { - DHD_ERROR(("%s, register_netdev failed for %s\n", - __FUNCTION__, dev->name)); - free_netdev(dev); - } - - bcmwifi_monitor_create(&dhd->monitor_info); - dhd->monitor_dev = dev; -} - -static void -dhd_del_monitor_if(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - - if (event != DHD_WQ_WORK_IF_DEL) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - if (dhd->monitor_dev) { - unregister_netdev(dhd->monitor_dev); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)) - MFREE(dhd->osh, dhd->monitor_dev->priv, DHD_MON_DEV_PRIV_SIZE); - MFREE(dhd->osh, dhd->monitor_dev, sizeof(struct net_device)); -#else - free_netdev(dhd->monitor_dev); -#endif /* 2.6.24 */ - - dhd->monitor_dev = NULL; - } - - if (dhd->monitor_info) { - bcmwifi_monitor_delete(dhd->monitor_info); - dhd->monitor_info = NULL; - } -} - -static void -dhd_set_monitor(dhd_pub_t *dhd, int ifidx, int val) -{ - dhd_info_t *info = dhd->info; - - DHD_TRACE(("%s: val %d\n", __FUNCTION__, val)); - if ((val && info->monitor_dev) || (!val && !info->monitor_dev)) { - DHD_ERROR(("%s: Mismatched params, return\n", __FUNCTION__)); - return; - } - - /* Delete monitor */ - if (!val) { - info->monitor_type = val; - dhd_deferred_schedule_work(info->dhd_deferred_wq, NULL, DHD_WQ_WORK_IF_DEL, - dhd_del_monitor_if, DHD_WQ_WORK_PRIORITY_LOW); - return; - } - - /* Add monitor */ - info->monitor_type = val; - dhd_deferred_schedule_work(info->dhd_deferred_wq, NULL, DHD_WQ_WORK_IF_ADD, - dhd_add_monitor_if, DHD_WQ_WORK_PRIORITY_LOW); -} -#endif /* WL_MONITOR */ - -#ifdef BCOL_TCPKA_SYNC -static void dhd_bcol_tcpka_check_options(dhd_pub_t *dhdp) -{ - struct sock *sk = tcpka_sync.tcpka_sk; - struct tcp_sock *tp = NULL; - struct tcp_info info = {0}; - tcpka_conn_sess_t *tcpka_en_info = tcpka_sync.tcpka_en_info; - - if (!sk) { - DHD_ERROR(("%s: sock is NULL!!\n", __func__)); - return; - } - - if (!tcpka_en_info) { - DHD_ERROR(("%s: tcpka_en_info is NULL!!\n", __func__)); - return; - } - tp = tcp_sk(sk); - - //TCP_MAXSEG - tcpka_en_info->mss = tp->rx_opt.mss_clamp; - DHD_TRACE(("%s: mss %u\n", - __func__, tcpka_en_info->mss)); - - //TCP_REPAIR_WINDOW - tcpka_en_info->snd_wl1 = tp->snd_wl1; - tcpka_en_info->snd_wnd = tp->snd_wnd; - tcpka_en_info->max_window = tp->max_window;; - tcpka_en_info->rcv_wnd = tp->rcv_wnd; - tcpka_en_info->rcv_wup = tp->rcv_wup; - DHD_TRACE(("%s: snd_wl1 %u snd_wnd %u max_window %u rcv_wnd %u rcv_wup %u\n", - __func__, - tp->snd_wl1, tp->snd_wnd, tp->max_window, tp->rcv_wnd, tp->rcv_wup)); - - //WSCALE - tcp_get_info(sk, &info); - tcpka_en_info->snd_wscale = info.tcpi_snd_wscale; - tcpka_en_info->rcv_wscale = info.tcpi_rcv_wscale; - - //TCP options - if (tp->rx_opt.tstamp_ok) - info.tcpi_options |= TCPI_OPT_TIMESTAMPS; - if (tcp_is_sack(tp)) - info.tcpi_options |= TCPI_OPT_SACK; - if (tp->rx_opt.wscale_ok) { - info.tcpi_options |= TCPI_OPT_WSCALE; - info.tcpi_snd_wscale = tp->rx_opt.snd_wscale; - info.tcpi_rcv_wscale = tp->rx_opt.rcv_wscale; - } - if (tp->ecn_flags & TCP_ECN_OK) - info.tcpi_options |= TCPI_OPT_ECN; - if (tp->ecn_flags & TCP_ECN_SEEN) - info.tcpi_options |= TCPI_OPT_ECN_SEEN; - if (tp->syn_data_acked) - info.tcpi_options |= TCPI_OPT_SYN_DATA; - - tcpka_en_info->tcpi_options = info.tcpi_options; - - DHD_TRACE(("%s: snd_wscale %u rcv_wscale %u tcpi_options %u\n", - __func__, info.tcpi_snd_wscale, info.tcpi_rcv_wscale, info.tcpi_options)); -} - -static int dhd_tcpka_conn_addbuf_get_sess_id(void *data_buf, int buflen, bool isv4) { - uint32 offset = strlen(isv4 ? CMD_STR_TCPKA_CONN_ADD : CMD_STR_TCPKA6_CONN_ADD) + 1; - tcpka_conn_t *tcpka_conn = NULL; - tcpka6_conn_t *tcpka6_conn = NULL; - - if (buflen <= offset || data_buf == NULL) - return -1; - - if (isv4) { - tcpka_conn = (tcpka_conn_t *)((char *)data_buf + offset); - return tcpka_conn->sess_id; - } else { - tcpka6_conn = (tcpka6_conn_t *)((char *)data_buf + offset); - return tcpka6_conn->sess_id; - } -} - -static bool dhd_ioctl_tcpka_preprocess(dhd_pub_t *pub, dhd_ioctl_t *ioc, - void *data_buf, int buflen, bool *wait_for_sess_id, int *bcmerror) -{ - if (ioc->cmd == WLC_GET_VAR) { - /* dump tcpka conn sync status */ - if (!strcmp(data_buf, CMD_STR_TCPKA_CONN_SYNC)) { - *(uint32*)data_buf = tcpka_sync.tcpka_sync_mode; - DHD_TCPKA_INFO(("%s: dump %s:\n", __func__, CMD_STR_TCPKA_CONN_SYNC)); - DHD_TCPKA_INFO(("get sync mode=%d, state=%d\n", tcpka_sync.tcpka_sync_mode, - tcpka_sync.tcpka_sync_state)); - if (tcpka_sync.tcpka_iovbuf) { - if (tcpka_sync.sess_type) { - dhd_bcol_dump_tcpka6_conn(tcpka_sync.tcpka6_conn); - } else { - dhd_bcol_dump_tcpka_conn(tcpka_sync.tcpka_conn); - } - } - *bcmerror = BCME_OK; - return false; - } - /* config tcpka conn info */ - if (!strcmp(data_buf, CMD_STR_TCPKA_CONN_ADD) && - (tcpka_sync.tcpka_sync_mode == BCOL_TCPKA_SYNC_MODE_ON) && - (tcpka_sync.tcpka_sync_state == BCOL_TCPKA_SYNC_STATE_NONE || - tcpka_sync.tcpka_sync_state == BCOL_TCPKA_SYNC_STATE_DONE) && - (dhd_tcpka_conn_addbuf_get_sess_id(data_buf, buflen, TRUE) == TCPKA_DEFAULT_SESS_ID)) { - /* tcpka sync mode is on and state is none or done */ - if (tcpka_sync.tcpka_iovbuf) { - MFREE(pub->osh, tcpka_sync.tcpka_iovbuf, tcpka_sync.tcpka_iovbuf_len); - } - tcpka_sync.tcpka_iovbuf_len = buflen; - tcpka_sync.tcpka_iovbuf = MALLOC(pub->osh, tcpka_sync.tcpka_iovbuf_len); - if (tcpka_sync.tcpka_iovbuf) { - uint32 offset = strlen(CMD_STR_TCPKA_CONN_ADD) + 1; - /* set session type to 0(IPv4) */ - tcpka_sync.sess_type = 0; - memcpy(tcpka_sync.tcpka_iovbuf, data_buf, buflen); - tcpka_sync.tcpka_conn = (tcpka_conn_t*)((char*)tcpka_sync.tcpka_iovbuf + offset); - dhd_bcol_dump_tcpka_conn(tcpka_sync.tcpka_conn); - *wait_for_sess_id = true; - } - } - if (!strcmp(data_buf, CMD_STR_TCPKA6_CONN_ADD) && - (tcpka_sync.tcpka_sync_mode == BCOL_TCPKA_SYNC_MODE_ON) && - (tcpka_sync.tcpka_sync_state == BCOL_TCPKA_SYNC_STATE_NONE || - tcpka_sync.tcpka_sync_state == BCOL_TCPKA_SYNC_STATE_DONE) && - (dhd_tcpka_conn_addbuf_get_sess_id(data_buf, buflen, FALSE) == TCPKA_DEFAULT_SESS_ID)) { - /* tcpka sync mode is on and state is none or done */ - if (tcpka_sync.tcpka_iovbuf) { - MFREE(pub->osh, tcpka_sync.tcpka_iovbuf, tcpka_sync.tcpka_iovbuf_len); - } - tcpka_sync.tcpka_iovbuf_len = buflen; - tcpka_sync.tcpka_iovbuf = MALLOC(pub->osh, tcpka_sync.tcpka_iovbuf_len); - if (tcpka_sync.tcpka_iovbuf) { - uint32 offset = strlen(CMD_STR_TCPKA6_CONN_ADD) + 1; - /* set session type to 1(IPv6) */ - tcpka_sync.sess_type = 1; - memcpy(tcpka_sync.tcpka_iovbuf, data_buf, buflen); - tcpka_sync.tcpka6_conn = (tcpka6_conn_t*)((char*)tcpka_sync.tcpka_iovbuf + offset); - dhd_bcol_dump_tcpka6_conn(tcpka_sync.tcpka6_conn); - *wait_for_sess_id = true; - } - } - } - - if (ioc->cmd == WLC_SET_VAR) { - /* set tcpka conn sync mode */ - if (!strcmp(data_buf, CMD_STR_TCPKA_CONN_SYNC)) { - char tcpka_sync_mode = !!*((char*)data_buf + strlen(CMD_STR_TCPKA_CONN_SYNC) + 1); - DHD_TCPKA_INFO(("%s: dump %s:\n", __func__, CMD_STR_TCPKA_CONN_SYNC)); - DHD_TCPKA_INFO(("set sync=%d\n", tcpka_sync_mode)); - if (tcpka_sync.tcpka_sync_mode != tcpka_sync_mode) { - /* sync state reset to none */ - tcpka_sync.tcpka_sync_state = BCOL_TCPKA_SYNC_STATE_NONE; -#ifdef TCPKA_REPAIR - mutex_lock(&pub->dhd_tcpka_mutex); -#endif /* TCPKA_REPAIR */ - tcpka_sync.tcpka_sync_mode = tcpka_sync_mode; -#ifdef TCPKA_REPAIR - mutex_unlock(&pub->dhd_tcpka_mutex); -#endif /* TCPKA_REPAIR */ - } - *bcmerror = BCME_OK; - return false; - } - /* del tcpka conn info */ - if (!strcmp(data_buf, CMD_STR_TCPKA_CONN_DEL)) { - uint32 *sess_id; - sess_id = (uint32*)((char*)data_buf + strlen(CMD_STR_TCPKA_CONN_DEL) + 1); - tcpka_sync.sess_type = 0; - DHD_TCPKA_INFO(("%s: dump %s:\n", __func__, CMD_STR_TCPKA_CONN_DEL)); - DHD_TCPKA_INFO(("session id=%d\n", *sess_id)); - } else if (!strcmp(data_buf, CMD_STR_TCPKA_CONN_EN)) { - tcpka_conn_sess_t *tcpka; - int sess_id = 0; - tcpka = (tcpka_conn_sess_t*)((char*)data_buf + strlen(CMD_STR_TCPKA_CONN_EN) + 1); - dhd_bcol_dump_tcpka_conn_sess(tcpka); - sess_id = dhd_get_tcpka_session_id(pub); - - if (tcpka->sess_id == sess_id) { - if (tcpka_sync.tcpka_sync_state == BCOL_TCPKA_SYNC_STATE_READY) { - uint32 offset = strlen(CMD_STR_TCPKA_CONN_EN) + 1; - - /* save conn_sess info for enabling later */ - if (!tcpka_sync.tcpka_en_info) { - tcpka_sync.tcpka_en_info = MALLOC(pub->osh, sizeof(tcpka_conn_sess_t)); - if (!tcpka_sync.tcpka_en_info) { - DHD_ERROR(("%s: malloc tcpka_en_info failed.\n", __func__)); - *bcmerror = BCME_NORESOURCE; - return false; - } - } - - memcpy(tcpka_sync.tcpka_en_info, ((char*)data_buf+offset), - sizeof(tcpka_conn_sess_t)); - - DHD_TCPKA_INFO(("%s: save conn_sess info for enabling later\n", __func__)); - /* sync state to busy */ - tcpka_sync.tcpka_sync_state = BCOL_TCPKA_SYNC_STATE_BUSY; - dhd_bcol_tcpka_check_options(pub); - dhd_deferred_schedule_work(pub->info->dhd_deferred_wq, NULL, - DHD_WQ_WORK_SYNC_BCOL_TCPKA_CONN, - dhd_sync_bcol_tcpka_conn_handler, - DHD_WQ_WORK_PRIORITY_HIGH); - *bcmerror = BCME_OK; - return false; - } else { - *bcmerror = BCME_NOTREADY; - return false; - } - } - } - } - - return true; -} - -static void dhd_ioctl_tcpka_postprocess(dhd_pub_t *pub, dhd_ioctl_t *ioc, - void *data_buf, int buflen, bool *wait_for_sess_id, int *bcmerror) -{ - if (*bcmerror == BCME_OK && *wait_for_sess_id) { - if (tcpka_sync.sess_type) { - if (tcpka_sync.tcpka6_conn) { - tcpka_sync.tcpka6_conn->sess_id = *(char*)data_buf; - DHD_TCPKA_INFO(("%s: result of %s:\n", __func__, CMD_STR_TCPKA6_CONN_ADD)); - DHD_TCPKA_INFO(("session id=%d\n", tcpka_sync.tcpka6_conn->sess_id)); - } - } else { - if (tcpka_sync.tcpka_conn) { - tcpka_sync.tcpka_conn->sess_id = *(char*)data_buf; - DHD_TCPKA_INFO(("%s: result of %s:\n", __func__, CMD_STR_TCPKA_CONN_ADD)); - DHD_TCPKA_INFO(("session id=%d\n", tcpka_sync.tcpka_conn->sess_id)); - } - } - /* start to trac */ - tcpka_sync.tcpka_sync_state = BCOL_TCPKA_SYNC_STATE_TRAC; - } -} -#endif /* BCOL_TCPKA_SYNC */ - -int dhd_ioctl_process(dhd_pub_t *pub, int ifidx, dhd_ioctl_t *ioc, void *data_buf) -{ - int bcmerror = BCME_OK; - int buflen = 0; - struct net_device *net; -#ifdef BCOL_TCPKA_SYNC - bool wait_for_sess_id = false; -#endif /* BCOL_TCPKA_SYNC */ - -#ifdef REPORT_FATAL_TIMEOUTS - if (ioc->cmd == WLC_SET_WPA_AUTH) { - int wpa_auth; - - wpa_auth = *((int *)ioc->buf); - DHD_INFO(("wpa_auth:%d\n", wpa_auth)); - if (wpa_auth != WPA_AUTH_DISABLED) { - /* If AP is with security then enable WLC_E_PSK_SUP event checking */ - dhd_set_join_error(pub, WLC_WPA_MASK); - } else { - /* If AP is with open then disable WLC_E_PSK_SUP event checking */ - dhd_clear_join_error(pub, WLC_WPA_MASK); - } - } - - if (ioc->cmd == WLC_SET_AUTH) { - int auth; - auth = *((int *)ioc->buf); - DHD_INFO(("Auth:%d\n", auth)); - - if (auth != WL_AUTH_OPEN_SYSTEM) { - /* If AP is with security then enable WLC_E_PSK_SUP event checking */ - dhd_set_join_error(pub, WLC_WPA_MASK); - } else { - /* If AP is with open then disable WLC_E_PSK_SUP event checking */ - dhd_clear_join_error(pub, WLC_WPA_MASK); - } - } -#endif /* REPORT_FATAL_TIMEOUTS */ - net = dhd_idx2net(pub, ifidx); - if (!net) { - bcmerror = BCME_BADARG; - goto done; - } - - /* check for local dhd ioctl and handle it */ - if (ioc->driver == DHD_IOCTL_MAGIC) { - /* This is a DHD IOVAR, truncate buflen to DHD_IOCTL_MAXLEN */ - if (data_buf) - buflen = MIN(ioc->len, DHD_IOCTL_MAXLEN); - bcmerror = dhd_ioctl((void *)pub, ioc, data_buf, buflen); - if (bcmerror) - pub->bcmerror = bcmerror; - goto done; - } - - /* This is a WL IOVAR, truncate buflen to WLC_IOCTL_MAXLEN */ - if (data_buf) - buflen = MIN(ioc->len, WLC_IOCTL_MAXLEN); - -#ifndef BCMDBUS - /* send to dongle (must be up, and wl). */ - if (pub->busstate == DHD_BUS_DOWN || pub->busstate == DHD_BUS_LOAD) { - if ((!pub->dongle_trap_occured) && allow_delay_fwdl) { - int ret; - if (atomic_read(&exit_in_progress)) { - DHD_ERROR(("%s module exit in progress\n", __func__)); - bcmerror = BCME_DONGLE_DOWN; - goto done; - } - ret = dhd_bus_start(pub); - if (ret != 0) { - DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); - bcmerror = BCME_DONGLE_DOWN; - goto done; - } - } else { - bcmerror = BCME_DONGLE_DOWN; - goto done; - } - } - - if (!pub->iswl) { - bcmerror = BCME_DONGLE_DOWN; - goto done; - } -#endif /* !BCMDBUS */ - - /* - * Flush the TX queue if required for proper message serialization: - * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to - * prevent M4 encryption and - * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to - * prevent disassoc frame being sent before WPS-DONE frame. - */ - if (ioc->cmd == WLC_SET_KEY || - (ioc->cmd == WLC_SET_VAR && data_buf != NULL && - strncmp("wsec_key", data_buf, 9) == 0) || - (ioc->cmd == WLC_SET_VAR && data_buf != NULL && - strncmp("bsscfg:wsec_key", data_buf, 15) == 0) || - ioc->cmd == WLC_DISASSOC) - dhd_wait_pend8021x(net); - -#ifdef WLMEDIA_HTSF - if (data_buf) { - /* short cut wl ioctl calls here */ - if (strcmp("htsf", data_buf) == 0) { - dhd_ioctl_htsf_get(dhd, 0); - return BCME_OK; - } - - if (strcmp("htsflate", data_buf) == 0) { - if (ioc->set) { - memset(ts, 0, sizeof(tstamp_t)*TSMAX); - memset(&maxdelayts, 0, sizeof(tstamp_t)); - maxdelay = 0; - tspktcnt = 0; - maxdelaypktno = 0; - memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); - } else { - dhd_dump_latency(); - } - return BCME_OK; - } - if (strcmp("htsfclear", data_buf) == 0) { - memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); - htsf_seqnum = 0; - return BCME_OK; - } - if (strcmp("htsfhis", data_buf) == 0) { - dhd_dump_htsfhisto(&vi_d1, "H to D"); - dhd_dump_htsfhisto(&vi_d2, "D to D"); - dhd_dump_htsfhisto(&vi_d3, "D to H"); - dhd_dump_htsfhisto(&vi_d4, "H to H"); - return BCME_OK; - } - if (strcmp("tsport", data_buf) == 0) { - if (ioc->set) { - memcpy(&tsport, data_buf + 7, 4); - } else { - DHD_ERROR(("current timestamp port: %d \n", tsport)); - } - return BCME_OK; - } - } -#endif /* WLMEDIA_HTSF */ - - if ((ioc->cmd == WLC_SET_VAR || ioc->cmd == WLC_GET_VAR) && - data_buf != NULL && strncmp("rpc_", data_buf, 4) == 0) { -#ifdef BCM_FD_AGGR - bcmerror = dhd_fdaggr_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen); -#else - bcmerror = BCME_UNSUPPORTED; -#endif - goto done; - } - -#ifdef BCOL_TCPKA_SYNC - if (!dhd_ioctl_tcpka_preprocess(pub, ioc, data_buf, buflen, - &wait_for_sess_id, &bcmerror)) { - goto done; - } -#endif /* BCOL_TCPKA_SYNC */ - - bcmerror = dhd_wl_ioctl(pub, ifidx, (wl_ioctl_t *)ioc, data_buf, buflen); - -#ifdef BCOL_TCPKA_SYNC - dhd_ioctl_tcpka_postprocess(pub, ioc, data_buf, buflen, &wait_for_sess_id, - &bcmerror); -#endif /* BCOL_TCPKA_SYNC */ - -#ifdef WL_MONITOR - /* Intercept monitor ioctl here, add/del monitor if */ - if (bcmerror == BCME_OK && ioc->cmd == WLC_SET_MONITOR) { - dhd_set_monitor(pub, ifidx, *(int32*)data_buf); - } -#endif - -#ifdef REPORT_FATAL_TIMEOUTS - if (ioc->cmd == WLC_SCAN && bcmerror == 0) { - dhd_start_scan_timer(pub); - } - if (ioc->cmd == WLC_SET_SSID && bcmerror == 0) { - dhd_start_join_timer(pub); - } -#endif /* REPORT_FATAL_TIMEOUTS */ - -done: - dhd_check_hang(net, pub, bcmerror); - - return bcmerror; -} - -static int -dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) -{ - dhd_info_t *dhd = DHD_DEV_INFO(net); - dhd_ioctl_t ioc; - int bcmerror = 0; - int ifidx; - int ret; - void *local_buf = NULL; - void __user *ioc_buf_user = NULL; - u16 buflen = 0; - - if (atomic_read(&exit_in_progress)) { - DHD_ERROR(("%s module exit in progress\n", __func__)); - bcmerror = BCME_DONGLE_DOWN; - return OSL_ERROR(bcmerror); - } - - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - - /* Interface up check for built-in type */ - if (!dhd_download_fw_on_driverload && dhd->pub.up == FALSE) { - DHD_ERROR(("%s: Interface is down \n", __FUNCTION__)); - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return OSL_ERROR(BCME_NOTUP); - } - - ifidx = dhd_net2idx(dhd, net); - DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); - - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: BAD IF\n", __FUNCTION__)); - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return -1; - } - -#if defined(WL_WIRELESS_EXT) - /* linux wireless extensions */ - if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { - /* may recurse, do NOT lock */ - ret = wl_iw_ioctl(net, ifr, cmd); - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return ret; - } -#endif /* defined(WL_WIRELESS_EXT) */ - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) - if (cmd == SIOCETHTOOL) { - ret = dhd_ethtool(dhd, (void*)ifr->ifr_data); - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return ret; - } -#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ - - if (cmd == SIOCDEVPRIVATE+1) { - ret = wl_android_priv_cmd(net, ifr, cmd); - dhd_check_hang(net, &dhd->pub, ret); - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return ret; - } - - if (cmd != SIOCDEVPRIVATE) { - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return -EOPNOTSUPP; - } - - memset(&ioc, 0, sizeof(ioc)); - -#ifdef CONFIG_COMPAT -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)) - if (in_compat_syscall()) -#else - if (is_compat_task()) -#endif - { - compat_wl_ioctl_t compat_ioc; - if (copy_from_user(&compat_ioc, ifr->ifr_data, sizeof(compat_wl_ioctl_t))) { - bcmerror = BCME_BADADDR; - goto done; - } - ioc.cmd = compat_ioc.cmd; - ioc.buf = compat_ptr(compat_ioc.buf); - ioc.len = compat_ioc.len; - ioc.set = compat_ioc.set; - ioc.used = compat_ioc.used; - ioc.needed = compat_ioc.needed; - /* To differentiate between wl and dhd read 4 more byes */ - if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(compat_wl_ioctl_t), - sizeof(uint)) != 0)) { - bcmerror = BCME_BADADDR; - goto done; - } - } else -#endif /* CONFIG_COMPAT */ - { - /* Copy the ioc control structure part of ioctl request */ - if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { - bcmerror = BCME_BADADDR; - goto done; - } - - /* To differentiate between wl and dhd read 4 more byes */ - if ((copy_from_user(&ioc.driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), - sizeof(uint)) != 0)) { - bcmerror = BCME_BADADDR; - goto done; - } - } - - if (!capable(CAP_NET_ADMIN)) { - bcmerror = BCME_EPERM; - goto done; - } - - /* Take backup of ioc.buf and restore later */ - ioc_buf_user = ioc.buf; - - if (ioc.len > 0) { - buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN); - if (!(local_buf = MALLOC(dhd->pub.osh, buflen+1))) { - bcmerror = BCME_NOMEM; - goto done; - } - - DHD_PERIM_UNLOCK(&dhd->pub); - if (copy_from_user(local_buf, ioc.buf, buflen)) { - DHD_PERIM_LOCK(&dhd->pub); - bcmerror = BCME_BADADDR; - goto done; - } - DHD_PERIM_LOCK(&dhd->pub); - - *((char *)local_buf + buflen) = '\0'; - - /* For some platforms accessing userspace memory - * of ioc.buf is causing kernel panic, so to avoid that - * make ioc.buf pointing to kernel space memory local_buf - */ - ioc.buf = local_buf; - } - - /* Skip all the non DHD iovars (wl iovars) after f/w hang */ - if (ioc.driver != DHD_IOCTL_MAGIC && dhd->pub.hang_was_sent) { - DHD_TRACE(("%s: HANG was sent up earlier\n", __FUNCTION__)); - DHD_OS_WAKE_LOCK_CTRL_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS); - bcmerror = BCME_DONGLE_DOWN; - goto done; - } - - bcmerror = dhd_ioctl_process(&dhd->pub, ifidx, &ioc, local_buf); - - /* Restore back userspace pointer to ioc.buf */ - ioc.buf = ioc_buf_user; - - if (!bcmerror && buflen && local_buf && ioc.buf) { - DHD_PERIM_UNLOCK(&dhd->pub); - if (copy_to_user(ioc.buf, local_buf, buflen)) - bcmerror = -EFAULT; - DHD_PERIM_LOCK(&dhd->pub); - } - -done: - if (local_buf) - MFREE(dhd->pub.osh, local_buf, buflen+1); - - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - return OSL_ERROR(bcmerror); -} - - -#ifdef FIX_CPU_MIN_CLOCK -static int dhd_init_cpufreq_fix(dhd_info_t *dhd) -{ - if (dhd) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_init(&dhd->cpufreq_fix); -#endif - dhd->cpufreq_fix_status = FALSE; - } - return 0; -} - -static void dhd_fix_cpu_freq(dhd_info_t *dhd) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_lock(&dhd->cpufreq_fix); -#endif - if (dhd && !dhd->cpufreq_fix_status) { - pm_qos_add_request(&dhd->dhd_cpu_qos, PM_QOS_CPU_FREQ_MIN, 300000); -#ifdef FIX_BUS_MIN_CLOCK - pm_qos_add_request(&dhd->dhd_bus_qos, PM_QOS_BUS_THROUGHPUT, 400000); -#endif /* FIX_BUS_MIN_CLOCK */ - DHD_ERROR(("pm_qos_add_requests called\n")); - - dhd->cpufreq_fix_status = TRUE; - } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&dhd->cpufreq_fix); -#endif -} - -static void dhd_rollback_cpu_freq(dhd_info_t *dhd) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_lock(&dhd ->cpufreq_fix); -#endif - if (dhd && dhd->cpufreq_fix_status != TRUE) { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&dhd->cpufreq_fix); -#endif - return; - } - - pm_qos_remove_request(&dhd->dhd_cpu_qos); -#ifdef FIX_BUS_MIN_CLOCK - pm_qos_remove_request(&dhd->dhd_bus_qos); -#endif /* FIX_BUS_MIN_CLOCK */ - DHD_ERROR(("pm_qos_add_requests called\n")); - - dhd->cpufreq_fix_status = FALSE; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&dhd->cpufreq_fix); -#endif -} -#endif /* FIX_CPU_MIN_CLOCK */ - -#if defined(BT_OVER_SDIO) - -void -dhdsdio_bus_usr_cnt_inc(dhd_pub_t *dhdp) -{ - dhdp->info->bus_user_count++; -} - -void -dhdsdio_bus_usr_cnt_dec(dhd_pub_t *dhdp) -{ - dhdp->info->bus_user_count--; -} - -/* Return values: - * Success: Returns 0 - * Failure: Returns -1 or errono code - */ -int -dhd_bus_get(wlan_bt_handle_t handle, bus_owner_t owner) -{ - dhd_pub_t *dhdp = (dhd_pub_t *)handle; - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - int ret = 0; - - mutex_lock(&dhd->bus_user_lock); - ++dhd->bus_user_count; - if (dhd->bus_user_count < 0) { - DHD_ERROR(("%s(): bus_user_count is negative, which is invalid\n", __FUNCTION__)); - ret = -1; - goto exit; - } - - if (dhd->bus_user_count == 1) { - - dhd->pub.hang_was_sent = 0; - - /* First user, turn on WL_REG, start the bus */ - DHD_ERROR(("%s(): First user Turn On WL_REG & start the bus", __FUNCTION__)); - - if (!wifi_platform_set_power(dhd->adapter, TRUE, WIFI_TURNON_DELAY)) { - /* Enable F1 */ - ret = dhd_bus_resume(dhdp, 0); - if (ret) { - DHD_ERROR(("%s(): Failed to enable F1, err=%d\n", - __FUNCTION__, ret)); - goto exit; - } - } - - dhd_update_fw_nv_path(dhd); - /* update firmware and nvram path to sdio bus */ - dhd_bus_update_fw_nv_path(dhd->pub.bus, - dhd->fw_path, dhd->nv_path); - /* download the firmware, Enable F2 */ - /* TODO: Should be done only in case of FW switch */ - ret = dhd_bus_devreset(dhdp, FALSE); - dhd_bus_resume(dhdp, 1); - if (!ret) { - if (dhd_sync_with_dongle(&dhd->pub) < 0) { - DHD_ERROR(("%s(): Sync with dongle failed!!\n", __FUNCTION__)); - ret = -EFAULT; - } - } else { - DHD_ERROR(("%s(): Failed to download, err=%d\n", __FUNCTION__, ret)); - } - } else { - DHD_ERROR(("%s(): BUS is already acquired, just increase the count %d \r\n", - __FUNCTION__, dhd->bus_user_count)); - } -exit: - mutex_unlock(&dhd->bus_user_lock); - return ret; -} -EXPORT_SYMBOL(dhd_bus_get); - -/* Return values: - * Success: Returns 0 - * Failure: Returns -1 or errono code - */ -int -dhd_bus_put(wlan_bt_handle_t handle, bus_owner_t owner) -{ - dhd_pub_t *dhdp = (dhd_pub_t *)handle; - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - int ret = 0; - BCM_REFERENCE(owner); - - mutex_lock(&dhd->bus_user_lock); - --dhd->bus_user_count; - if (dhd->bus_user_count < 0) { - DHD_ERROR(("%s(): bus_user_count is negative, which is invalid\n", __FUNCTION__)); - dhd->bus_user_count = 0; - ret = -1; - goto exit; - } - - if (dhd->bus_user_count == 0) { - /* Last user, stop the bus and turn Off WL_REG */ - DHD_ERROR(("%s(): There are no owners left Trunf Off WL_REG & stop the bus \r\n", - __FUNCTION__)); -#ifdef PROP_TXSTATUS - if (dhd->pub.wlfc_enabled) { - dhd_wlfc_deinit(&dhd->pub); - } -#endif /* PROP_TXSTATUS */ -#ifdef PNO_SUPPORT - if (dhd->pub.pno_state) { - dhd_pno_deinit(&dhd->pub); - } -#endif /* PNO_SUPPORT */ -#ifdef RTT_SUPPORT - if (dhd->pub.rtt_state) { - dhd_rtt_deinit(&dhd->pub); - } -#endif /* RTT_SUPPORT */ - ret = dhd_bus_devreset(dhdp, TRUE); - if (!ret) { - dhd_bus_suspend(dhdp); - wifi_platform_set_power(dhd->adapter, FALSE, WIFI_TURNOFF_DELAY); - } - } else { - DHD_ERROR(("%s(): Other owners using bus, decrease the count %d \r\n", - __FUNCTION__, dhd->bus_user_count)); - } -exit: - mutex_unlock(&dhd->bus_user_lock); - return ret; -} -EXPORT_SYMBOL(dhd_bus_put); - -int -dhd_net_bus_get(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - return dhd_bus_get(&dhd->pub, WLAN_MODULE); -} - -int -dhd_net_bus_put(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - return dhd_bus_put(&dhd->pub, WLAN_MODULE); -} - -/* - * Function to enable the Bus Clock - * Returns BCME_OK on success and BCME_xxx on failure - * - * This function is not callable from non-sleepable context - */ -int dhd_bus_clk_enable(wlan_bt_handle_t handle, bus_owner_t owner) -{ - dhd_pub_t *dhdp = (dhd_pub_t *)handle; - - int ret; - - dhd_os_sdlock(dhdp); - /* - * The second argument is TRUE, that means, we expect - * the function to "wait" until the clocks are really - * available - */ - ret = __dhdsdio_clk_enable(dhdp->bus, owner, TRUE); - dhd_os_sdunlock(dhdp); - - return ret; -} -EXPORT_SYMBOL(dhd_bus_clk_enable); - -/* - * Function to disable the Bus Clock - * Returns BCME_OK on success and BCME_xxx on failure - * - * This function is not callable from non-sleepable context - */ -int dhd_bus_clk_disable(wlan_bt_handle_t handle, bus_owner_t owner) -{ - dhd_pub_t *dhdp = (dhd_pub_t *)handle; - - int ret; - - dhd_os_sdlock(dhdp); - /* - * The second argument is TRUE, that means, we expect - * the function to "wait" until the clocks are really - * disabled - */ - ret = __dhdsdio_clk_disable(dhdp->bus, owner, TRUE); - dhd_os_sdunlock(dhdp); - - return ret; -} -EXPORT_SYMBOL(dhd_bus_clk_disable); - -/* - * Function to reset bt_use_count counter to zero. - * - * This function is not callable from non-sleepable context - */ -void dhd_bus_reset_bt_use_count(wlan_bt_handle_t handle) -{ - dhd_pub_t *dhdp = (dhd_pub_t *)handle; - - /* take the lock and reset bt use count */ - dhd_os_sdlock(dhdp); - dhdsdio_reset_bt_use_count(dhdp->bus); - dhd_os_sdunlock(dhdp); -} -EXPORT_SYMBOL(dhd_bus_reset_bt_use_count); - -#endif /* BT_OVER_SDIO */ - -#define MAX_TRY_CNT 5 /* Number of tries to disable deepsleep */ -int dhd_deepsleep(dhd_info_t *dhd, int flag) -{ - char iovbuf[20]; - uint powervar = 0; - dhd_pub_t *dhdp; - int cnt = 0; - int ret = 0; - - dhdp = &dhd->pub; - - switch (flag) { - case 1 : /* Deepsleep on */ - DHD_ERROR(("dhd_deepsleep: ON\n")); - /* give some time to sysioc_work before deepsleep */ - OSL_SLEEP(200); -#ifdef PKT_FILTER_SUPPORT - /* disable pkt filter */ - dhd_enable_packet_filter(0, dhdp); -#endif /* PKT_FILTER_SUPPORT */ - /* Disable MPC */ - powervar = 0; - memset(iovbuf, 0, sizeof(iovbuf)); - bcm_mkiovar("mpc", (char *)&powervar, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - - /* Enable Deepsleep */ - powervar = 1; - memset(iovbuf, 0, sizeof(iovbuf)); - bcm_mkiovar("deepsleep", (char *)&powervar, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - break; - - case 0: /* Deepsleep Off */ - DHD_ERROR(("dhd_deepsleep: OFF\n")); - - /* Disable Deepsleep */ - for (cnt = 0; cnt < MAX_TRY_CNT; cnt++) { - powervar = 0; - memset(iovbuf, 0, sizeof(iovbuf)); - bcm_mkiovar("deepsleep", (char *)&powervar, 4, - iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0); - - memset(iovbuf, 0, sizeof(iovbuf)); - bcm_mkiovar("deepsleep", (char *)&powervar, 4, - iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, - sizeof(iovbuf), FALSE, 0)) < 0) { - DHD_ERROR(("the error of dhd deepsleep status" - " ret value :%d\n", ret)); - } else { - if (!(*(int *)iovbuf)) { - DHD_ERROR(("deepsleep mode is 0," - " count: %d\n", cnt)); - break; - } - } - } - - /* Enable MPC */ - powervar = 1; - memset(iovbuf, 0, sizeof(iovbuf)); - bcm_mkiovar("mpc", (char *)&powervar, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - break; - } - - return 0; -} - -static int -dhd_stop(struct net_device *net) -{ - int ifidx = 0; -#ifdef WL_CFG80211 - unsigned long flags = 0; -#endif /* WL_CFG80211 */ - dhd_info_t *dhd = DHD_DEV_INFO(net); - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net)); - dhd->pub.rxcnt_timeout = 0; - dhd->pub.txcnt_timeout = 0; -#ifdef IDSUP_STATS - dhd->pub.wpa_state = WIFI_WPA_STATE_INTERFACE_DISABLED; -#endif /* IDSUP_STATS */ -#ifdef PF_SETUP_COMMAND - dhd_packet_filter_add_remove_ext(net, FALSE, -1, NULL, TRUE); -#endif /* PF_SETUP_COMMAND */ -#ifdef BCMPCIE - dhd->pub.d3ackcnt_timeout = 0; -#endif /* BCMPCIE */ - - if (dhd->pub.up == 0) { - goto exit; - } -#if defined(DHD_HANG_SEND_UP_TEST) - if (dhd->pub.req_hang_type) { - DHD_ERROR(("%s, Clear HANG test request 0x%x\n", - __FUNCTION__, dhd->pub.req_hang_type)); - dhd->pub.req_hang_type = 0; - } -#endif /* DHD_HANG_SEND_UP_TEST */ - - dhd_if_flush_sta(DHD_DEV_IFP(net)); - - /* Disable Runtime PM before interface down */ - DHD_DISABLE_RUNTIME_PM(&dhd->pub); - -#ifdef FIX_CPU_MIN_CLOCK - if (dhd_get_fw_mode(dhd) == DHD_FLAG_HOSTAP_MODE) - dhd_rollback_cpu_freq(dhd); -#endif /* FIX_CPU_MIN_CLOCK */ - - ifidx = dhd_net2idx(dhd, net); - BCM_REFERENCE(ifidx); - - /* Set state and stop OS transmissions */ - netif_stop_queue(net); -#ifdef WL_CFG80211 - spin_lock_irqsave(&dhd->pub.up_lock, flags); - dhd->pub.up = 0; - spin_unlock_irqrestore(&dhd->pub.up_lock, flags); -#else - dhd->pub.up = 0; -#endif /* WL_CFG80211 */ - -#ifdef WL_CFG80211 - if (ifidx == 0) { - dhd_if_t *ifp; - wl_cfg80211_down(net); - - ifp = dhd->iflist[0]; - ASSERT(ifp && ifp->net); - /* - * For CFG80211: Clean up all the left over virtual interfaces - * when the primary Interface is brought down. [ifconfig wlan0 down] - */ - if (!dhd_download_fw_on_driverload) { - if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) && - (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { - int i; -#ifdef WL_CFG80211_P2P_DEV_IF - wl_cfg80211_del_p2p_wdev(net); -#endif /* WL_CFG80211_P2P_DEV_IF */ - - dhd_net_if_lock_local(dhd); - for (i = 1; i < DHD_MAX_IFS; i++) - dhd_remove_if(&dhd->pub, i, FALSE); - - if (ifp && ifp->net) { - dhd_if_del_sta_list(ifp); - } -#ifdef ARP_OFFLOAD_SUPPORT - if (dhd_inetaddr_notifier_registered) { - dhd_inetaddr_notifier_registered = FALSE; - unregister_inetaddr_notifier(&dhd_inetaddr_notifier); - } -#endif /* ARP_OFFLOAD_SUPPORT */ -#if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT) - if (dhd_inet6addr_notifier_registered) { - dhd_inet6addr_notifier_registered = FALSE; - unregister_inet6addr_notifier(&dhd_inet6addr_notifier); - } -#endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ - dhd_net_if_unlock_local(dhd); - } -#if 0 - // terence 20161024: remove this to prevent dev_close() get stuck in dhd_hang_process - cancel_work_sync(dhd->dhd_deferred_wq); -#endif - -#ifdef SHOW_LOGTRACE - /* Wait till event_log_dispatcher_work finishes */ - cancel_work_sync(&dhd->event_log_dispatcher_work); -#endif /* SHOW_LOGTRACE */ - -#if defined(DHD_LB_RXP) - __skb_queue_purge(&dhd->rx_pend_queue); -#endif /* DHD_LB_RXP */ - -#if defined(DHD_LB_TXP) - skb_queue_purge(&dhd->tx_pend_queue); -#endif /* DHD_LB_TXP */ - } - - argos_register_notifier_deinit(); -#ifdef DHDTCPACK_SUPPRESS - dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF); -#endif /* DHDTCPACK_SUPPRESS */ -#if defined(DHD_LB_RXP) - if (ifp->net == dhd->rx_napi_netdev) { - DHD_INFO(("%s napi<%p> disabled ifp->net<%p,%s>\n", - __FUNCTION__, &dhd->rx_napi_struct, net, net->name)); - skb_queue_purge(&dhd->rx_napi_queue); - napi_disable(&dhd->rx_napi_struct); - netif_napi_del(&dhd->rx_napi_struct); - dhd->rx_napi_netdev = NULL; - } -#endif /* DHD_LB_RXP */ - } -#endif /* WL_CFG80211 */ - - DHD_SSSR_DUMP_DEINIT(&dhd->pub); - -#ifdef PROP_TXSTATUS - dhd_wlfc_cleanup(&dhd->pub, NULL, 0); -#endif -#ifdef SHOW_LOGTRACE - if (!dhd_download_fw_on_driverload) { - /* Release the skbs from queue for WLC_E_TRACE event */ - dhd_event_logtrace_flush_queue(&dhd->pub); - if (dhd->dhd_state & DHD_ATTACH_LOGTRACE_INIT) { - if (dhd->event_data.fmts) { - MFREE(dhd->pub.osh, dhd->event_data.fmts, - dhd->event_data.fmts_size); - dhd->event_data.fmts = NULL; - } - if (dhd->event_data.raw_fmts) { - MFREE(dhd->pub.osh, dhd->event_data.raw_fmts, - dhd->event_data.raw_fmts_size); - dhd->event_data.raw_fmts = NULL; - } - if (dhd->event_data.raw_sstr) { - MFREE(dhd->pub.osh, dhd->event_data.raw_sstr, - dhd->event_data.raw_sstr_size); - dhd->event_data.raw_sstr = NULL; - } - if (dhd->event_data.rom_raw_sstr) { - MFREE(dhd->pub.osh, dhd->event_data.rom_raw_sstr, - dhd->event_data.rom_raw_sstr_size); - dhd->event_data.rom_raw_sstr = NULL; - } - dhd->dhd_state &= ~DHD_ATTACH_LOGTRACE_INIT; - } - } -#endif /* SHOW_LOGTRACE */ -#ifdef APF - dhd_dev_apf_delete_filter(net); -#endif /* APF */ - - /* Stop the protocol module */ - dhd_prot_stop(&dhd->pub); - - OLD_MOD_DEC_USE_COUNT; -exit: - if (ifidx == 0 && !dhd_download_fw_on_driverload) { -#if defined(BT_OVER_SDIO) - dhd_bus_put(&dhd->pub, WLAN_MODULE); - wl_android_set_wifi_on_flag(FALSE); -#else - wl_android_wifi_off(net, TRUE); -#ifdef WL_EXT_IAPSTA - wl_ext_iapsta_dettach_netdev(); -#endif - } else { - if (dhd->pub.conf->deepsleep) - dhd_deepsleep(dhd, 1); -#endif /* BT_OVER_SDIO */ - } - dhd->pub.hang_was_sent = 0; - -#ifndef WL_CCODE_RELOAD - /* Clear country spec for for built-in type driver */ - if (!dhd_download_fw_on_driverload) { - dhd->pub.dhd_cspec.country_abbrev[0] = 0x00; - dhd->pub.dhd_cspec.rev = 0; - dhd->pub.dhd_cspec.ccode[0] = 0x00; - } -#endif /* WL_CCODE_RELOAD */ - -#ifdef BCMDBGFS - dhd_dbgfs_remove(); -#endif - - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - /* Destroy wakelock */ - if (!dhd_download_fw_on_driverload && - (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { - DHD_OS_WAKE_LOCK_DESTROY(dhd); - dhd->dhd_state &= ~DHD_ATTACH_STATE_WAKELOCKS_INIT; - } - DHD_TRACE(("%s: Exit\n", __FUNCTION__)); - - return 0; -} - -#if defined(WL_CFG80211) && defined(USE_INITIAL_SHORT_DWELL_TIME) -extern bool g_first_broadcast_scan; -#endif - -#ifdef WL11U -static int dhd_interworking_enable(dhd_pub_t *dhd) -{ - uint32 enable = true; - int ret = BCME_OK; - - ret = dhd_iovar(dhd, 0, "interworking", (char *)&enable, sizeof(enable), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: enableing interworking failed, ret=%d\n", __FUNCTION__, ret)); - } - - return ret; -} -#endif /* WL11u */ - -int dhd_get_hang_state(void) { - return atomic_read(&dhd_hang_state); -} - -static int -dhd_open(struct net_device *net) -{ - dhd_info_t *dhd = DHD_DEV_INFO(net); -#ifdef TOE - uint32 toe_ol; -#endif -#ifdef BCM_FD_AGGR - char iovbuf[WLC_IOCTL_SMLEN]; - dbus_config_t config; - uint32 agglimit = 0; - uint32 rpc_agg = BCM_RPC_TP_DNGL_AGG_DPC; /* host aggr not enabled yet */ -#endif /* BCM_FD_AGGR */ - int ifidx; - int32 ret = 0; -#if defined(OOB_INTR_ONLY) - uint32 bus_type = -1; - uint32 bus_num = -1; - uint32 slot_num = -1; - wifi_adapter_info_t *adapter = NULL; -#endif -#if defined(WL_EXT_IAPSTA) && defined(IAPSTA_PREINIT) - int bytes_written = 0; - struct dhd_conf *conf; -#endif -#ifdef DHD_BUILTIN - int drv_state = 0; -#endif /* DHD_BUILTIN */ - - if (!dhd_download_fw_on_driverload) { - if (!dhd_driver_init_done) { - DHD_ERROR(("%s: WLAN driver is not initialized\n", __FUNCTION__)); - return -1; - } - } - -#ifdef DHD_BUILTIN - drv_state = dhd_get_driver_state(); - if (drv_state < DHD_DRIVER_STATE_WARM) { - DHD_ERROR(("%s: abort, state %s\n", - __func__, get_dhd_drv_state_str(drv_state))); - return -1; - } -#endif /* DHD_BUILTIN */ - - DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net)); - DHD_MUTEX_LOCK(); - /* Init wakelock */ - if (!dhd_download_fw_on_driverload) { - if (!(dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { - DHD_OS_WAKE_LOCK_INIT(dhd); - dhd->dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; - } -#ifdef SHOW_LOGTRACE - skb_queue_head_init(&dhd->evt_trace_queue); - - if (!(dhd->dhd_state & DHD_ATTACH_LOGTRACE_INIT)) { - ret = dhd_init_logstrs_array(dhd->pub.osh, &dhd->event_data); - if (ret == BCME_OK) { - dhd_init_static_strs_array(dhd->pub.osh, &dhd->event_data, - st_str_file_path, map_file_path); - dhd_init_static_strs_array(dhd->pub.osh, &dhd->event_data, - rom_st_str_file_path, rom_map_file_path); - dhd->dhd_state |= DHD_ATTACH_LOGTRACE_INIT; - } - } -#endif /* SHOW_LOGTRACE */ - } - -#if defined(PREVENT_REOPEN_DURING_HANG) - /* WAR : to prevent calling dhd_open abnormally in quick succession after hang event */ - if (dhd->pub.hang_was_sent == 1) { - DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__)); - /* Force to bring down WLAN interface in case dhd_stop() is not called - * from the upper layer when HANG event is triggered. - */ - if (!dhd_download_fw_on_driverload && dhd->pub.up == 1) { - DHD_ERROR(("%s: WLAN interface is not brought down\n", __FUNCTION__)); - dhd_stop(net); - } else { - return -1; - } - } -#endif /* PREVENT_REOPEN_DURING_HANG */ - - - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - dhd->pub.dongle_trap_occured = 0; - dhd->pub.hang_was_sent = 0; - dhd->pub.hang_reason = 0; - dhd->pub.iovar_timeout_occured = 0; -#ifdef PCIE_FULL_DONGLE - dhd->pub.d3ack_timeout_occured = 0; -#endif /* PCIE_FULL_DONGLE */ - -#ifdef DHD_LOSSLESS_ROAMING - dhd->pub.dequeue_prec_map = ALLPRIO; -#endif -#if 0 - /* - * Force start if ifconfig_up gets called before START command - * We keep WEXT's wl_control_wl_start to provide backward compatibility - * This should be removed in the future - */ - ret = wl_control_wl_start(net); - if (ret != 0) { - DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); - ret = -1; - goto exit; - } -#endif - - ifidx = dhd_net2idx(dhd, net); - DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); - - if (ifidx < 0) { - DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__)); - ret = -1; - goto exit; - } - - if (!dhd->iflist[ifidx]) { - DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__)); - ret = -1; - goto exit; - } - - if (ifidx == 0) { - atomic_set(&dhd->pend_8021x_cnt, 0); - if (!dhd_download_fw_on_driverload) { - DHD_ERROR(("\n%s\n", dhd_version)); -#ifdef WL_EXT_IAPSTA - wl_ext_iapsta_attach_netdev(net, ifidx); -#endif -#if defined(USE_INITIAL_SHORT_DWELL_TIME) - g_first_broadcast_scan = TRUE; -#endif -#if defined(BT_OVER_SDIO) - ret = dhd_bus_get(&dhd->pub, WLAN_MODULE); - wl_android_set_wifi_on_flag(TRUE); -#else - ret = wl_android_wifi_on(net); -#endif /* BT_OVER_SDIO */ - if (ret != 0) { - DHD_ERROR(("%s : wl_android_wifi_on failed (%d)\n", - __FUNCTION__, ret)); - ret = -1; - goto exit; - } -#if defined(WL_EXT_IAPSTA) && defined(IAPSTA_PREINIT) - conf = dhd_get_conf(net); - if (conf) { - wl_android_ext_priv_cmd(net, conf->iapsta_init, 0, &bytes_written); - wl_android_ext_priv_cmd(net, conf->iapsta_config, 0, &bytes_written); - wl_android_ext_priv_cmd(net, conf->iapsta_enable, 0, &bytes_written); - } -#endif - } -#ifdef FIX_CPU_MIN_CLOCK - if (dhd_get_fw_mode(dhd) == DHD_FLAG_HOSTAP_MODE) { - dhd_init_cpufreq_fix(dhd); - dhd_fix_cpu_freq(dhd); - } -#endif /* FIX_CPU_MIN_CLOCK */ -#if defined(OOB_INTR_ONLY) - if (dhd->pub.conf->dpc_cpucore >= 0) { - dhd_bus_get_ids(dhd->pub.bus, &bus_type, &bus_num, &slot_num); - adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num); - if (adapter) { - DHD_INFO(("%s: set irq affinity hit %d\n", __FUNCTION__, dhd->pub.conf->dpc_cpucore)); - irq_set_affinity_hint(adapter->irq_num, cpumask_of(dhd->pub.conf->dpc_cpucore)); - } - } -#endif - - if (dhd->pub.busstate != DHD_BUS_DATA) { -#ifdef BCMDBUS - dhd_set_path(&dhd->pub); - DHD_MUTEX_UNLOCK(); - wait_event_interruptible_timeout(dhd->adapter->status_event, - wifi_get_adapter_status(dhd->adapter, WIFI_STATUS_FW_READY), - msecs_to_jiffies(DHD_FW_READY_TIMEOUT)); - DHD_MUTEX_LOCK(); - if ((ret = dbus_up(dhd->pub.bus)) != 0) { - DHD_ERROR(("%s: failed to dbus_up with code %d\n", __FUNCTION__, ret)); - goto exit; - } else { - dhd->pub.busstate = DHD_BUS_DATA; - } - if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) { - DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); - goto exit; - } -#else - /* try to bring up bus */ - DHD_PERIM_UNLOCK(&dhd->pub); - ret = dhd_bus_start(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - if (ret) { - DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); - ret = -1; - goto exit; - } -#endif /* !BCMDBUS */ - - } - if (dhd_download_fw_on_driverload) { - if (dhd->pub.conf->deepsleep) - dhd_deepsleep(dhd, 0); - } - -#ifdef BCM_FD_AGGR - config.config_id = DBUS_CONFIG_ID_AGGR_LIMIT; - - - memset(iovbuf, 0, sizeof(iovbuf)); - bcm_mkiovar("rpc_dngl_agglimit", (char *)&agglimit, 4, - iovbuf, sizeof(iovbuf)); - - if (!dhd_wl_ioctl_cmd(&dhd->pub, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) { - agglimit = *(uint32 *)iovbuf; - config.aggr_param.maxrxsf = agglimit >> BCM_RPC_TP_AGG_SF_SHIFT; - config.aggr_param.maxrxsize = agglimit & BCM_RPC_TP_AGG_BYTES_MASK; - DHD_ERROR(("rpc_dngl_agglimit %x : sf_limit %d bytes_limit %d\n", - agglimit, config.aggr_param.maxrxsf, config.aggr_param.maxrxsize)); - if (bcm_rpc_tp_set_config(dhd->pub.info->rpc_th, &config)) { - DHD_ERROR(("set tx/rx queue size and buffersize failed\n")); - } - } else { - DHD_ERROR(("get rpc_dngl_agglimit failed\n")); - rpc_agg &= ~BCM_RPC_TP_DNGL_AGG_DPC; - } - - /* Set aggregation for TX */ - bcm_rpc_tp_agg_set(dhd->pub.info->rpc_th, BCM_RPC_TP_HOST_AGG_MASK, - rpc_agg & BCM_RPC_TP_HOST_AGG_MASK); - - /* Set aggregation for RX */ - memset(iovbuf, 0, sizeof(iovbuf)); - bcm_mkiovar("rpc_agg", (char *)&rpc_agg, sizeof(rpc_agg), iovbuf, sizeof(iovbuf)); - if (!dhd_wl_ioctl_cmd(&dhd->pub, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) { - dhd->pub.info->fdaggr = 0; - if (rpc_agg & BCM_RPC_TP_HOST_AGG_MASK) - dhd->pub.info->fdaggr |= BCM_FDAGGR_H2D_ENABLED; - if (rpc_agg & BCM_RPC_TP_DNGL_AGG_MASK) - dhd->pub.info->fdaggr |= BCM_FDAGGR_D2H_ENABLED; - } else { - DHD_ERROR(("%s(): Setting RX aggregation failed %d\n", __FUNCTION__, ret)); - } -#endif /* BCM_FD_AGGR */ - -#ifdef BT_OVER_SDIO - if (dhd->pub.is_bt_recovery_required) { - DHD_ERROR(("%s: Send Hang Notification 2 to BT\n", __FUNCTION__)); - bcmsdh_btsdio_process_dhd_hang_notification(TRUE); - } - dhd->pub.is_bt_recovery_required = FALSE; -#endif - - /* dhd_sync_with_dongle has been called in dhd_bus_start or wl_android_wifi_on */ - memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); - -#ifdef TOE - /* Get current TOE mode from dongle */ - if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0) { - dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM; - } else { - dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM; - } -#endif /* TOE */ - -#if defined(DHD_LB_RXP) - __skb_queue_head_init(&dhd->rx_pend_queue); - if (dhd->rx_napi_netdev == NULL) { - dhd->rx_napi_netdev = dhd->iflist[ifidx]->net; - memset(&dhd->rx_napi_struct, 0, sizeof(struct napi_struct)); - netif_napi_add(dhd->rx_napi_netdev, &dhd->rx_napi_struct, - dhd_napi_poll, dhd_napi_weight); - DHD_INFO(("%s napi<%p> enabled ifp->net<%p,%s>\n", - __FUNCTION__, &dhd->rx_napi_struct, net, net->name)); - napi_enable(&dhd->rx_napi_struct); - DHD_INFO(("%s load balance init rx_napi_struct\n", __FUNCTION__)); - skb_queue_head_init(&dhd->rx_napi_queue); - } /* rx_napi_netdev == NULL */ -#endif /* DHD_LB_RXP */ - -#if defined(DHD_LB_TXP) - /* Use the variant that uses locks */ - skb_queue_head_init(&dhd->tx_pend_queue); -#endif /* DHD_LB_TXP */ - -#if defined(WL_CFG80211) - if (unlikely(wl_cfg80211_up(net))) { - DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__)); - ret = -1; - goto exit; - } - if (!dhd_download_fw_on_driverload) { -#ifdef ARP_OFFLOAD_SUPPORT - dhd->pend_ipaddr = 0; - if (!dhd_inetaddr_notifier_registered) { - dhd_inetaddr_notifier_registered = TRUE; - register_inetaddr_notifier(&dhd_inetaddr_notifier); - } -#endif /* ARP_OFFLOAD_SUPPORT */ -#if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT) - if (!dhd_inet6addr_notifier_registered) { - dhd_inet6addr_notifier_registered = TRUE; - register_inet6addr_notifier(&dhd_inet6addr_notifier); - } -#endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ - } - - argos_register_notifier_init(net); -#if defined(NUM_SCB_MAX_PROBE) - dhd_set_scb_probe(&dhd->pub); -#endif /* NUM_SCB_MAX_PROBE */ -#ifdef IDSUP_STATS - if (dhd_get_hang_state() == DHD_STATUS_HANGED) { - DHD_ERROR(("Driver is recovered.")); -#ifdef SDIO_TRAITS_STATS - dhd->pub.fw_need_reload = NO_FW_RELOAD; -#endif /* SDIO_TRAITS_STATS */ - atomic_set(&dhd_hang_state, DHD_STATUS_RECOVERED); - if (g_last_cspec.ccode[0] != 0) { - ret = dhd_iovar(&dhd->pub, 0, "country", (char *)&g_last_cspec, sizeof(wl_country_t), - NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: prev country code setting failed\n", __FUNCTION__)); - } else { - memcpy(&dhd->pub.dhd_cspec, &g_last_cspec, sizeof(wl_country_t)); -#ifdef WL_CFG80211 - wl_update_wiphybands(wl_get_cfg(net), true); -#endif - } - } - wl_state_event_sendup(wl_get_cfg(net), ndev_to_cfgdev(net), - NULL, EVT_RESET, NULL); - } -#endif /* IDSUP_STATS */ -#endif /* WL_CFG80211 */ - } - tcpka_sync.tcpka_noti_capture.type = -1; - tcpka_sync.tcpka_drop = FALSE; - tcpka_sync.tcpka_repair_block = 0; - /* Allow transmit calls */ - netif_start_queue(net); - dhd->pub.up = 1; - - OLD_MOD_INC_USE_COUNT; - -#ifdef BCMDBGFS - dhd_dbgfs_init(&dhd->pub); -#endif - - dhd_postinit_ioctls(&dhd->pub, net); -exit: - if (ret) { - dhd_stop(net); - } - - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - DHD_MUTEX_UNLOCK(); - - DHD_TRACE(("%s: Exit ret=%d\n", __FUNCTION__, ret)); - return ret; -} - -int dhd_do_driver_init(struct net_device *net) -{ - dhd_info_t *dhd = NULL; - - if (!net) { - DHD_ERROR(("Primary Interface not initialized \n")); - return -EINVAL; - } - - DHD_MUTEX_IS_LOCK_RETURN(); - - /* && defined(OEM_ANDROID) && defined(BCMSDIO) */ - dhd = DHD_DEV_INFO(net); - - /* If driver is already initialized, do nothing - */ - if (dhd->pub.busstate == DHD_BUS_DATA) { - DHD_TRACE(("Driver already Inititalized. Nothing to do")); - return 0; - } - - if (dhd_open(net) < 0) { - DHD_ERROR(("Driver Init Failed \n")); - return -1; - } - - return 0; -} - -int -dhd_event_ifadd(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac) -{ - -#ifdef WL_CFG80211 - if (wl_cfg80211_notify_ifadd(dhd_linux_get_primary_netdev(&dhdinfo->pub), - ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK) - return BCME_OK; -#endif - - /* handle IF event caused by wl commands, SoftAP, WEXT and - * anything else. This has to be done asynchronously otherwise - * DPC will be blocked (and iovars will timeout as DPC has no chance - * to read the response back) - */ - if (ifevent->ifidx > 0) { - dhd_if_event_t *if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t)); - if (if_event == NULL) { - DHD_ERROR(("dhd_event_ifadd: Failed MALLOC, malloced %d bytes", - MALLOCED(dhdinfo->pub.osh))); - return BCME_NOMEM; - } - - memcpy(&if_event->event, ifevent, sizeof(if_event->event)); - memcpy(if_event->mac, mac, ETHER_ADDR_LEN); - strncpy(if_event->name, name, IFNAMSIZ); - if_event->name[IFNAMSIZ - 1] = '\0'; - dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, - DHD_WQ_WORK_IF_ADD, dhd_ifadd_event_handler, DHD_WQ_WORK_PRIORITY_LOW); - } - - return BCME_OK; -} - -int -dhd_event_ifdel(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac) -{ - dhd_if_event_t *if_event; - -#ifdef WL_CFG80211 - if (wl_cfg80211_notify_ifdel(dhd_linux_get_primary_netdev(&dhdinfo->pub), - ifevent->ifidx, name, mac, ifevent->bssidx) == BCME_OK) - return BCME_OK; -#endif /* WL_CFG80211 */ - - /* handle IF event caused by wl commands, SoftAP, WEXT and - * anything else - */ - if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t)); - if (if_event == NULL) { - DHD_ERROR(("dhd_event_ifdel: malloc failed for if_event, malloced %d bytes", - MALLOCED(dhdinfo->pub.osh))); - return BCME_NOMEM; - } - memcpy(&if_event->event, ifevent, sizeof(if_event->event)); - memcpy(if_event->mac, mac, ETHER_ADDR_LEN); - strncpy(if_event->name, name, IFNAMSIZ); - if_event->name[IFNAMSIZ - 1] = '\0'; - dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, DHD_WQ_WORK_IF_DEL, - dhd_ifdel_event_handler, DHD_WQ_WORK_PRIORITY_LOW); - - return BCME_OK; -} - -int -dhd_event_ifchange(dhd_info_t *dhdinfo, wl_event_data_if_t *ifevent, char *name, uint8 *mac) -{ -#ifdef DHD_UPDATE_INTF_MAC - dhd_if_event_t *if_event; -#endif /* DHD_UPDATE_INTF_MAC */ - -#ifdef WL_CFG80211 - wl_cfg80211_notify_ifchange(dhd_linux_get_primary_netdev(&dhdinfo->pub), - ifevent->ifidx, name, mac, ifevent->bssidx); -#endif /* WL_CFG80211 */ - -#ifdef DHD_UPDATE_INTF_MAC - /* handle IF event caused by wl commands, SoftAP, WEXT, MBSS and - * anything else - */ - if_event = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_event_t)); - if (if_event == NULL) { - DHD_ERROR(("dhd_event_ifdel: malloc failed for if_event, malloced %d bytes", - MALLOCED(dhdinfo->pub.osh))); - return BCME_NOMEM; - } - memcpy(&if_event->event, ifevent, sizeof(if_event->event)); - // construct a change event - if_event->event.ifidx = dhd_ifname2idx(dhdinfo, name); - if_event->event.opcode = WLC_E_IF_CHANGE; - memcpy(if_event->mac, mac, ETHER_ADDR_LEN); - strncpy(if_event->name, name, IFNAMSIZ); - if_event->name[IFNAMSIZ - 1] = '\0'; - dhd_deferred_schedule_work(dhdinfo->dhd_deferred_wq, (void *)if_event, DHD_WQ_WORK_IF_UPDATE, - dhd_ifupdate_event_handler, DHD_WQ_WORK_PRIORITY_LOW); -#endif /* DHD_UPDATE_INTF_MAC */ - - return BCME_OK; -} - -/* unregister and free the existing net_device interface (if any) in iflist and - * allocate a new one. the slot is reused. this function does NOT register the - * new interface to linux kernel. dhd_register_if does the job - */ -struct net_device* -dhd_allocate_if(dhd_pub_t *dhdpub, int ifidx, const char *name, - uint8 *mac, uint8 bssidx, bool need_rtnl_lock, const char *dngl_name) -{ - dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info; - dhd_if_t *ifp; - - ASSERT(dhdinfo && (ifidx < DHD_MAX_IFS)); - ifp = dhdinfo->iflist[ifidx]; - - if (ifp != NULL) { - if (ifp->net != NULL) { - DHD_ERROR(("%s: free existing IF %s ifidx:%d \n", - __FUNCTION__, ifp->net->name, ifidx)); - - if (ifidx == 0) { - /* For primary ifidx (0), there shouldn't be - * any netdev present already. - */ - DHD_ERROR(("Primary ifidx populated already\n")); - ASSERT(0); - return NULL; - } - - dhd_dev_priv_clear(ifp->net); /* clear net_device private */ - - /* in unregister_netdev case, the interface gets freed by net->destructor - * (which is set to free_netdev) - */ - if (ifp->net->reg_state == NETREG_UNINITIALIZED) { - free_netdev(ifp->net); - } else { - netif_stop_queue(ifp->net); - if (need_rtnl_lock) - unregister_netdev(ifp->net); - else - unregister_netdevice(ifp->net); - } - ifp->net = NULL; - } - } else { - ifp = MALLOC(dhdinfo->pub.osh, sizeof(dhd_if_t)); - if (ifp == NULL) { - DHD_ERROR(("%s: OOM - dhd_if_t(%zu)\n", __FUNCTION__, sizeof(dhd_if_t))); - return NULL; - } - } - - memset(ifp, 0, sizeof(dhd_if_t)); - ifp->info = dhdinfo; - ifp->idx = ifidx; - ifp->bssidx = bssidx; -#ifdef DHD_MCAST_REGEN - ifp->mcast_regen_bss_enable = FALSE; -#endif - /* set to TRUE rx_pkt_chainable at alloc time */ - ifp->rx_pkt_chainable = TRUE; - - if (mac != NULL) - memcpy(&ifp->mac_addr, mac, ETHER_ADDR_LEN); - - /* Allocate etherdev, including space for private structure */ - ifp->net = alloc_etherdev(DHD_DEV_PRIV_SIZE); - if (ifp->net == NULL) { - DHD_ERROR(("%s: OOM - alloc_etherdev(%zu)\n", __FUNCTION__, sizeof(dhdinfo))); - goto fail; - } - - /* Setup the dhd interface's netdevice private structure. */ - dhd_dev_priv_save(ifp->net, dhdinfo, ifp, ifidx); - - if (name && name[0]) { - strncpy(ifp->net->name, name, IFNAMSIZ); - ifp->net->name[IFNAMSIZ - 1] = '\0'; - } - -#ifdef WL_CFG80211 - if (ifidx == 0) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) - ifp->net->destructor = free_netdev; -#else - ifp->net->needs_free_netdev = true; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) */ - } else { -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) - ifp->net->destructor = dhd_netdev_free; -#else - ifp->net->needs_free_netdev = true; - ifp->net->priv_destructor = dhd_netdev_free; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) */ - } -#else -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) - ifp->net->destructor = free_netdev; -#else - ifp->net->needs_free_netdev = true; -#endif -#endif /* WL_CFG80211 */ - strncpy(ifp->name, ifp->net->name, IFNAMSIZ); - ifp->name[IFNAMSIZ - 1] = '\0'; - dhdinfo->iflist[ifidx] = ifp; - -/* initialize the dongle provided if name */ - if (dngl_name) - strncpy(ifp->dngl_name, dngl_name, IFNAMSIZ); - else if (name) - strncpy(ifp->dngl_name, name, IFNAMSIZ); - -#ifdef PCIE_FULL_DONGLE - /* Initialize STA info list */ - INIT_LIST_HEAD(&ifp->sta_list); - DHD_IF_STA_LIST_LOCK_INIT(ifp); -#endif /* PCIE_FULL_DONGLE */ - -#ifdef DHD_L2_FILTER - ifp->phnd_arp_table = init_l2_filter_arp_table(dhdpub->osh); - ifp->parp_allnode = TRUE; -#endif /* DHD_L2_FILTER */ - - - DHD_CUMM_CTR_INIT(&ifp->cumm_ctr); - - return ifp->net; - -fail: - if (ifp != NULL) { - if (ifp->net != NULL) { -#if defined(DHD_LB_RXP) && defined(PCIE_FULL_DONGLE) - if (ifp->net == dhdinfo->rx_napi_netdev) { - napi_disable(&dhdinfo->rx_napi_struct); - netif_napi_del(&dhdinfo->rx_napi_struct); - skb_queue_purge(&dhdinfo->rx_napi_queue); - dhdinfo->rx_napi_netdev = NULL; - } -#endif /* DHD_LB_RXP && PCIE_FULL_DONGLE */ - dhd_dev_priv_clear(ifp->net); - free_netdev(ifp->net); - ifp->net = NULL; - } - MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp)); - ifp = NULL; - } - dhdinfo->iflist[ifidx] = NULL; - return NULL; -} - -/* unregister and free the the net_device interface associated with the indexed - * slot, also free the slot memory and set the slot pointer to NULL - */ -int -dhd_remove_if(dhd_pub_t *dhdpub, int ifidx, bool need_rtnl_lock) -{ - dhd_info_t *dhdinfo = (dhd_info_t *)dhdpub->info; - dhd_if_t *ifp; -#ifdef PCIE_FULL_DONGLE - if_flow_lkup_t *if_flow_lkup = (if_flow_lkup_t *)dhdpub->if_flow_lkup; -#endif /* PCIE_FULL_DONGLE */ - - ifp = dhdinfo->iflist[ifidx]; - - if (ifp != NULL) { - if (ifp->net != NULL) { - DHD_ERROR(("deleting interface '%s' idx %d\n", ifp->net->name, ifp->idx)); - - dhdinfo->iflist[ifidx] = NULL; - /* in unregister_netdev case, the interface gets freed by net->destructor - * (which is set to free_netdev) - */ - if (ifp->net->reg_state == NETREG_UNINITIALIZED) { - free_netdev(ifp->net); - } else { - netif_tx_disable(ifp->net); - - - -#if defined(SET_RPS_CPUS) - custom_rps_map_clear(ifp->net->_rx); -#endif /* SET_RPS_CPUS */ - if (need_rtnl_lock) - unregister_netdev(ifp->net); - else - unregister_netdevice(ifp->net); - } - ifp->net = NULL; - } -#ifdef DHD_WMF - dhd_wmf_cleanup(dhdpub, ifidx); -#endif /* DHD_WMF */ -#ifdef DHD_L2_FILTER - bcm_l2_filter_arp_table_update(dhdpub->osh, ifp->phnd_arp_table, TRUE, - NULL, FALSE, dhdpub->tickcnt); - deinit_l2_filter_arp_table(dhdpub->osh, ifp->phnd_arp_table); - ifp->phnd_arp_table = NULL; -#endif /* DHD_L2_FILTER */ - - - dhd_if_del_sta_list(ifp); -#ifdef PCIE_FULL_DONGLE - /* Delete flowrings of WDS interface */ - if (if_flow_lkup[ifidx].role == WLC_E_IF_ROLE_WDS) { - dhd_flow_rings_delete(dhdpub, ifidx); - } -#endif /* PCIE_FULL_DONGLE */ - DHD_CUMM_CTR_INIT(&ifp->cumm_ctr); - - MFREE(dhdinfo->pub.osh, ifp, sizeof(*ifp)); - ifp = NULL; - } - - return BCME_OK; -} - - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) -static struct net_device_ops dhd_ops_pri = { - .ndo_open = dhd_open, - .ndo_stop = dhd_stop, - .ndo_get_stats = dhd_get_stats, - .ndo_do_ioctl = dhd_ioctl_entry, - .ndo_start_xmit = dhd_start_xmit, - .ndo_set_mac_address = dhd_set_mac_address, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) - .ndo_set_rx_mode = dhd_set_multicast_list, -#else - .ndo_set_multicast_list = dhd_set_multicast_list, -#endif -}; - -static struct net_device_ops dhd_ops_virt = { - .ndo_get_stats = dhd_get_stats, - .ndo_do_ioctl = dhd_ioctl_entry, - .ndo_start_xmit = dhd_start_xmit, - .ndo_set_mac_address = dhd_set_mac_address, -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)) - .ndo_set_rx_mode = dhd_set_multicast_list, -#else - .ndo_set_multicast_list = dhd_set_multicast_list, -#endif -}; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ - -#ifdef DEBUGGER -extern void debugger_init(void *bus_handle); -#endif - - -#ifdef SHOW_LOGTRACE -int -dhd_os_read_file(void *file, char *buf, uint32 size) -{ - struct file *filep = (struct file *)file; - - if (!file || !buf) - return -1; - - return vfs_read(filep, buf, size, &filep->f_pos); -} - -int -dhd_os_seek_file(void *file, int64 offset) -{ - struct file *filep = (struct file *)file; - if (!file) - return -1; - - /* offset can be -ve */ - filep->f_pos = filep->f_pos + offset; - - return 0; -} - -static int -dhd_init_logstrs_array(osl_t *osh, dhd_event_log_t *temp) -{ - struct file *filep = NULL; - struct kstat stat; - mm_segment_t fs; - char *raw_fmts = NULL; - int logstrs_size = 0; - int error = 0; - - fs = get_fs(); - set_fs(KERNEL_DS); - - filep = filp_open(logstrs_path, O_RDONLY, 0); - - if (IS_ERR(filep)) { - DHD_ERROR(("%s: Failed to open the file %s \n", __FUNCTION__, logstrs_path)); - goto fail; - } - error = vfs_stat(logstrs_path, &stat); - if (error) { - DHD_ERROR(("%s: Failed to stat file %s \n", __FUNCTION__, logstrs_path)); - goto fail; - } - logstrs_size = (int) stat.size; - - if (logstrs_size == 0) { - DHD_ERROR(("%s: return as logstrs_size is 0\n", __FUNCTION__)); - goto fail1; - } - - raw_fmts = MALLOC(osh, logstrs_size); - if (raw_fmts == NULL) { - DHD_ERROR(("%s: Failed to allocate memory \n", __FUNCTION__)); - goto fail; - } - if (vfs_read(filep, raw_fmts, logstrs_size, &filep->f_pos) != logstrs_size) { - DHD_ERROR(("%s: Failed to read file %s\n", __FUNCTION__, logstrs_path)); - goto fail; - } - - if (dhd_parse_logstrs_file(osh, raw_fmts, logstrs_size, temp) - == BCME_OK) { - filp_close(filep, NULL); - set_fs(fs); - return BCME_OK; - } - -fail: - if (raw_fmts) { - MFREE(osh, raw_fmts, logstrs_size); - raw_fmts = NULL; - } - -fail1: - if (!IS_ERR(filep)) - filp_close(filep, NULL); - - set_fs(fs); - temp->fmts = NULL; - return BCME_ERROR; -} - -static int -dhd_read_map(osl_t *osh, char *fname, uint32 *ramstart, uint32 *rodata_start, - uint32 *rodata_end) -{ - struct file *filep = NULL; - mm_segment_t fs; - int err = BCME_ERROR; - - if (fname == NULL) { - DHD_ERROR(("%s: ERROR fname is NULL \n", __FUNCTION__)); - return BCME_ERROR; - } - - fs = get_fs(); - set_fs(KERNEL_DS); - - filep = filp_open(fname, O_RDONLY, 0); - if (IS_ERR(filep)) { - DHD_ERROR(("%s: Failed to open %s \n", __FUNCTION__, fname)); - goto fail; - } - - if ((err = dhd_parse_map_file(osh, filep, ramstart, - rodata_start, rodata_end)) < 0) - goto fail; - -fail: - if (!IS_ERR(filep)) - filp_close(filep, NULL); - - set_fs(fs); - - return err; -} - -static int -dhd_init_static_strs_array(osl_t *osh, dhd_event_log_t *temp, char *str_file, char *map_file) -{ - struct file *filep = NULL; - mm_segment_t fs; - char *raw_fmts = NULL; - uint32 logstrs_size = 0; - - int error = 0; - uint32 ramstart = 0; - uint32 rodata_start = 0; - uint32 rodata_end = 0; - uint32 logfilebase = 0; - - error = dhd_read_map(osh, map_file, &ramstart, &rodata_start, &rodata_end); - if (error != BCME_OK) { - DHD_ERROR(("readmap Error!! \n")); - /* don't do event log parsing in actual case */ - if (strstr(str_file, ram_file_str) != NULL) { - temp->raw_sstr = NULL; - } else if (strstr(str_file, rom_file_str) != NULL) { - temp->rom_raw_sstr = NULL; - } - return error; - } - DHD_ERROR(("ramstart: 0x%x, rodata_start: 0x%x, rodata_end:0x%x\n", - ramstart, rodata_start, rodata_end)); - - fs = get_fs(); - set_fs(KERNEL_DS); - - filep = filp_open(str_file, O_RDONLY, 0); - if (IS_ERR(filep)) { - DHD_ERROR(("%s: Failed to open the file %s \n", __FUNCTION__, str_file)); - goto fail; - } - - /* Full file size is huge. Just read required part */ - logstrs_size = rodata_end - rodata_start; - - if (logstrs_size == 0) { - DHD_ERROR(("%s: return as logstrs_size is 0\n", __FUNCTION__)); - goto fail1; - } - - raw_fmts = MALLOC(osh, logstrs_size); - if (raw_fmts == NULL) { - DHD_ERROR(("%s: Failed to allocate raw_fmts memory \n", __FUNCTION__)); - goto fail; - } - - logfilebase = rodata_start - ramstart; - - error = generic_file_llseek(filep, logfilebase, SEEK_SET); - if (error < 0) { - DHD_ERROR(("%s: %s llseek failed %d \n", __FUNCTION__, str_file, error)); - goto fail; - } - - error = vfs_read(filep, raw_fmts, logstrs_size, (&filep->f_pos)); - if (error != logstrs_size) { - DHD_ERROR(("%s: %s read failed %d \n", __FUNCTION__, str_file, error)); - goto fail; - } - - if (strstr(str_file, ram_file_str) != NULL) { - temp->raw_sstr = raw_fmts; - temp->raw_sstr_size = logstrs_size; - temp->ramstart = ramstart; - temp->rodata_start = rodata_start; - temp->rodata_end = rodata_end; - } else if (strstr(str_file, rom_file_str) != NULL) { - temp->rom_raw_sstr = raw_fmts; - temp->rom_raw_sstr_size = logstrs_size; - temp->rom_ramstart = ramstart; - temp->rom_rodata_start = rodata_start; - temp->rom_rodata_end = rodata_end; - } - - filp_close(filep, NULL); - set_fs(fs); - - return BCME_OK; - -fail: - if (raw_fmts) { - MFREE(osh, raw_fmts, logstrs_size); - raw_fmts = NULL; - } - -fail1: - if (!IS_ERR(filep)) - filp_close(filep, NULL); - - set_fs(fs); - - if (strstr(str_file, ram_file_str) != NULL) { - temp->raw_sstr = NULL; - } else if (strstr(str_file, rom_file_str) != NULL) { - temp->rom_raw_sstr = NULL; - } - - return error; -} - -#endif /* SHOW_LOGTRACE */ - -#ifdef BCMDBUS -uint -dhd_get_rxsz(dhd_pub_t *pub) -{ - struct net_device *net = NULL; - dhd_info_t *dhd = NULL; - uint rxsz; - - /* Assign rxsz for dbus_attach */ - dhd = pub->info; - net = dhd->iflist[0]->net; - net->hard_header_len = ETH_HLEN + pub->hdrlen; - rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); - - return rxsz; -} - -void -dhd_set_path(dhd_pub_t *pub) -{ - dhd_info_t *dhd = NULL; - - dhd = pub->info; - - /* try to download image and nvram to the dongle */ - if (dhd_update_fw_nv_path(dhd) && dhd->pub.bus) { - DHD_INFO(("%s: fw %s, nv %s, conf %s, reg %s\n", - __FUNCTION__, dhd->fw_path, dhd->nv_path, - dhd->conf_path, dhd->reg_path)); - dhd_bus_update_fw_nv_path(dhd->pub.bus, - dhd->fw_path, dhd->nv_path, dhd->clm_path, - dhd->conf_path, dhd->reg_path); - } -} -#endif - -#ifdef TCPKA_REPAIR -static void dhd_tcpka_reset_work(struct work_struct * work) -{ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - struct dhd_info *dhd = - container_of(work, struct dhd_info, tcpka_reset_work); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - - if (dhd) { -#if defined(BCOL_TCPKA_SYNC) && defined(RESUME_INIT) - struct net_device * net = dhd_idx2net(&dhd->pub, 0); - if (!net) { - DHD_ERROR(("%s: netdev is null\n", __func__)); - return; - } - DHD_INFO(("%s: dhd_tcpka_reset()\n", __func__)); - dhd_tcpka_reset(&dhd->pub, net); -#endif /* defined(BCOL_TCPKA_SYNC) && defined(RESUME_INIT) */ - } -} -#endif /* TCPKA_REPAIR */ - -dhd_pub_t * -dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen -#ifdef BCMDBUS - , void *data -#endif -) -{ - dhd_info_t *dhd = NULL; - struct net_device *net = NULL; - char if_name[IFNAMSIZ] = {'\0'}; -#ifdef SHOW_LOGTRACE - int ret; -#endif /* SHOW_LOGTRACE */ -#if defined(BCMSDIO) || defined(BCMPCIE) - uint32 bus_type = -1; - uint32 bus_num = -1; - uint32 slot_num = -1; - wifi_adapter_info_t *adapter = NULL; -#elif defined(BCMDBUS) - wifi_adapter_info_t *adapter = data; -#endif - - dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - -#ifdef STBLINUX - DHD_ERROR(("%s\n", driver_target)); -#endif /* STBLINUX */ - /* will implement get_ids for DBUS later */ -#if defined(BCMSDIO) - dhd_bus_get_ids(bus, &bus_type, &bus_num, &slot_num); -#endif -#if defined(BCMSDIO) || defined(BCMPCIE) - adapter = dhd_wifi_platform_get_adapter(bus_type, bus_num, slot_num); -#endif - - /* Allocate primary dhd_info */ - dhd = wifi_platform_prealloc(adapter, DHD_PREALLOC_DHD_INFO, sizeof(dhd_info_t)); - if (dhd == NULL) { - dhd = MALLOC(osh, sizeof(dhd_info_t)); - if (dhd == NULL) { - DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__)); - goto dhd_null_flag; - } - } - memset(dhd, 0, sizeof(dhd_info_t)); - dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC; - - dhd->unit = dhd_found + instance_base; /* do not increment dhd_found, yet */ - - dhd->pub.osh = osh; -#ifdef DUMP_IOCTL_IOV_LIST - dll_init(&(dhd->pub.dump_iovlist_head)); -#endif /* DUMP_IOCTL_IOV_LIST */ - dhd->adapter = adapter; - dhd->pub.adapter = (void *)adapter; -#ifdef DHD_DEBUG - dll_init(&(dhd->pub.mw_list_head)); -#endif /* DHD_DEBUG */ -#ifdef BT_OVER_SDIO - dhd->pub.is_bt_recovery_required = FALSE; - mutex_init(&dhd->bus_user_lock); -#endif /* BT_OVER_SDIO */ - -#ifdef EVENT_DATA_HOSTWAKE - dhd->pub.evt_data_sendup = TRUE; - dhd->pub.pending_evt_data = FALSE; - dhd->pub.hal_req_sched_wake = FALSE; -#endif /* EVENT_DATA_HOSTWAKE */ -#ifdef GET_CUSTOM_MAC_ENABLE - wifi_platform_get_mac_addr(dhd->adapter, dhd->pub.mac.octet); -#endif /* GET_CUSTOM_MAC_ENABLE */ -#ifdef CUSTOM_FORCE_NODFS_FLAG - dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; - dhd->pub.force_country_change = TRUE; -#endif /* CUSTOM_FORCE_NODFS_FLAG */ -#if defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) - get_customized_country_code(dhd->adapter, - dhd->pub.dhd_cspec.country_abbrev, &dhd->pub.dhd_cspec, - dhd->pub.dhd_cflags); -#else - get_customized_country_code(dhd->adapter, - dhd->pub.dhd_cspec.country_abbrev, &dhd->pub.dhd_cspec); -#endif /* defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) */ -#ifndef BCMDBUS - dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID; - dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID; -#ifdef DHD_WET - dhd->pub.wet_info = dhd_get_wet_info(&dhd->pub); -#endif /* DHD_WET */ - /* Initialize thread based operation and lock */ - sema_init(&dhd->sdsem, 1); -#endif /* !BCMDBUS */ - - /* Link to info module */ - dhd->pub.info = dhd; - - - /* Link to bus module */ - dhd->pub.bus = bus; - dhd->pub.hdrlen = bus_hdrlen; - - /* dhd_conf must be attached after linking dhd to dhd->pub.info, - * because dhd_detech will check .info is NULL or not. - */ - if (dhd_conf_attach(&dhd->pub) != 0) { - DHD_ERROR(("dhd_conf_attach failed\n")); - goto fail; - } -#ifndef BCMDBUS - dhd_conf_reset(&dhd->pub); - dhd_conf_set_chiprev(&dhd->pub, dhd_bus_chip(bus), dhd_bus_chiprev(bus)); - dhd_conf_preinit(&dhd->pub); -#endif /* !BCMDBUS */ - - /* Some DHD modules (e.g. cfg80211) configures operation mode based on firmware name. - * This is indeed a hack but we have to make it work properly before we have a better - * solution - */ - dhd_update_fw_nv_path(dhd); - - /* Set network interface name if it was provided as module parameter */ - if (iface_name[0]) { - int len; - char ch; - strncpy(if_name, iface_name, IFNAMSIZ); - if_name[IFNAMSIZ - 1] = 0; - len = strlen(if_name); - ch = if_name[len - 1]; - if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2)) - strncat(if_name, "%d", 2); - } - - /* Passing NULL to dngl_name to ensure host gets if_name in dngl_name member */ - net = dhd_allocate_if(&dhd->pub, 0, if_name, NULL, 0, TRUE, NULL); - if (net == NULL) { - goto fail; - } - - - dhd_state |= DHD_ATTACH_STATE_ADD_IF; -#ifdef DHD_L2_FILTER - /* initialize the l2_filter_cnt */ - dhd->pub.l2_filter_cnt = 0; -#endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - net->open = NULL; -#else - net->netdev_ops = NULL; -#endif - - mutex_init(&dhd->dhd_iovar_mutex); - sema_init(&dhd->proto_sem, 1); -#ifdef DHD_ULP - if (!(dhd_ulp_init(osh, &dhd->pub))) - goto fail; -#endif /* DHD_ULP */ - -#if defined(DHD_HANG_SEND_UP_TEST) - dhd->pub.req_hang_type = 0; -#endif /* DHD_HANG_SEND_UP_TEST */ - -#ifdef PROP_TXSTATUS - spin_lock_init(&dhd->wlfc_spinlock); - - dhd->pub.skip_fc = dhd_wlfc_skip_fc; - dhd->pub.plat_init = dhd_wlfc_plat_init; - dhd->pub.plat_deinit = dhd_wlfc_plat_deinit; - -#ifdef DHD_WLFC_THREAD - init_waitqueue_head(&dhd->pub.wlfc_wqhead); - dhd->pub.wlfc_thread = kthread_create(dhd_wlfc_transfer_packets, &dhd->pub, "wlfc-thread"); - if (IS_ERR(dhd->pub.wlfc_thread)) { - DHD_ERROR(("create wlfc thread failed\n")); - goto fail; - } else { - wake_up_process(dhd->pub.wlfc_thread); - } -#endif /* DHD_WLFC_THREAD */ -#endif /* PROP_TXSTATUS */ - - /* Initialize other structure content */ - init_waitqueue_head(&dhd->ioctl_resp_wait); - init_waitqueue_head(&dhd->d3ack_wait); -#ifdef PCIE_INB_DW - init_waitqueue_head(&dhd->ds_exit_wait); -#endif /* PCIE_INB_DW */ - init_waitqueue_head(&dhd->ctrl_wait); - init_waitqueue_head(&dhd->dhd_bus_busy_state_wait); - dhd->pub.dhd_bus_busy_state = 0; - - /* Initialize the spinlocks */ - spin_lock_init(&dhd->sdlock); - spin_lock_init(&dhd->txqlock); - spin_lock_init(&dhd->rxqlock); - spin_lock_init(&dhd->dhd_lock); - spin_lock_init(&dhd->rxf_lock); -#ifdef WLTDLS - spin_lock_init(&dhd->pub.tdls_lock); -#endif /* WLTDLS */ -#if defined(RXFRAME_THREAD) - dhd->rxthread_enabled = TRUE; -#endif /* defined(RXFRAME_THREAD) */ - -#ifdef DHDTCPACK_SUPPRESS - spin_lock_init(&dhd->tcpack_lock); -#endif /* DHDTCPACK_SUPPRESS */ - - /* Initialize Wakelock stuff */ - spin_lock_init(&dhd->wakelock_spinlock); - spin_lock_init(&dhd->wakelock_evt_spinlock); - DHD_OS_WAKE_LOCK_INIT(dhd); - dhd->wakelock_counter = 0; -#ifdef CONFIG_HAS_WAKELOCK - // terence 20161023: can not destroy wl_wifi when wlan down, it will happen null pointer in dhd_ioctl_entry - wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); - wake_lock_init(&dhd->wl_wdwake, WAKE_LOCK_SUSPEND, "wlan_wd_wake"); -#endif /* CONFIG_HAS_WAKELOCK */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_init(&dhd->dhd_net_if_mutex); - mutex_init(&dhd->dhd_suspend_mutex); -#ifdef TCPKA_REPAIR - mutex_init(&dhd->pub.dhd_tcpka_mutex); -#endif /* TCPKA_REPAIR */ -#if defined(PKT_FILTER_SUPPORT) && defined(APF) - mutex_init(&dhd->dhd_apf_mutex); -#endif /* PKT_FILTER_SUPPORT && APF */ -#endif - dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; - - /* Attach and link in the protocol */ - if (dhd_prot_attach(&dhd->pub) != 0) { - DHD_ERROR(("dhd_prot_attach failed\n")); - goto fail; - } - dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH; - -#ifdef DHD_TIMESYNC - /* attach the timesync module */ - if (dhd_timesync_attach(&dhd->pub) != 0) { - DHD_ERROR(("dhd_timesync_attach failed\n")); - goto fail; - } - dhd_state |= DHD_ATTACH_TIMESYNC_ATTACH_DONE; -#endif /* DHD_TIMESYNC */ - -#ifdef WL_CFG80211 - spin_lock_init(&dhd->pub.up_lock); - /* Attach and link in the cfg80211 */ - if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) { - DHD_ERROR(("wl_cfg80211_attach failed\n")); - goto fail; - } - - dhd_monitor_init(&dhd->pub); - dhd_state |= DHD_ATTACH_STATE_CFG80211; -#endif -#ifdef DHD_LOG_DUMP - dhd_log_dump_init(&dhd->pub); -#endif /* DHD_LOG_DUMP */ -#if defined(WL_WIRELESS_EXT) - /* Attach and link in the iw */ - if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) { - if (wl_iw_attach(net, (void *)&dhd->pub) != 0) { - DHD_ERROR(("wl_iw_attach failed\n")); - goto fail; - } - dhd_state |= DHD_ATTACH_STATE_WL_ATTACH; - } -#ifdef WL_ESCAN - wl_escan_attach(net, &dhd->pub); -#endif /* WL_ESCAN */ -#endif /* defined(WL_WIRELESS_EXT) */ - -#ifdef SHOW_LOGTRACE - ret = dhd_init_logstrs_array(osh, &dhd->event_data); - if (ret == BCME_OK) { - dhd_init_static_strs_array(osh, &dhd->event_data, st_str_file_path, map_file_path); - dhd_init_static_strs_array(osh, &dhd->event_data, rom_st_str_file_path, - rom_map_file_path); - dhd_state |= DHD_ATTACH_LOGTRACE_INIT; - } -#endif /* SHOW_LOGTRACE */ - -#ifdef DEBUGABILITY - /* attach debug if support */ - if (dhd_os_dbg_attach(&dhd->pub)) { - DHD_ERROR(("%s debug module attach failed\n", __FUNCTION__)); - goto fail; - } - -#ifdef DBG_PKT_MON - dhd->pub.dbg->pkt_mon_lock = dhd_os_spin_lock_init(dhd->pub.osh); -#ifdef DBG_PKT_MON_INIT_DEFAULT - dhd_os_dbg_attach_pkt_monitor(&dhd->pub); -#endif /* DBG_PKT_MON_INIT_DEFAULT */ -#endif /* DBG_PKT_MON */ -#endif /* DEBUGABILITY */ -#ifdef DHD_PKT_LOGGING - dhd_os_attach_pktlog(&dhd->pub); -#endif /* DHD_PKT_LOGGING */ - - if (dhd_sta_pool_init(&dhd->pub, DHD_MAX_STA) != BCME_OK) { - DHD_ERROR(("%s: Initializing %u sta\n", __FUNCTION__, DHD_MAX_STA)); - goto fail; - } - - - -#ifndef BCMDBUS - /* Set up the watchdog timer */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) - timer_setup(&dhd->timer, dhd_watchdog, 0); -#else - init_timer(&dhd->timer); - dhd->timer.data = (ulong)dhd; - dhd->timer.function = dhd_watchdog; -#endif - dhd->default_wd_interval = dhd_watchdog_ms; - - if (dhd_watchdog_prio >= 0) { - /* Initialize watchdog thread */ - PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0, "dhd_watchdog_thread"); - if (dhd->thr_wdt_ctl.thr_pid < 0) { - goto fail; - } - - } else { - dhd->thr_wdt_ctl.thr_pid = -1; - } - -#ifdef TCPKA_REPAIR - /* Setup up the runtime PM Idlecount timer */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) - timer_setup(&dhd->tcpka_rp_timer, dhd_tcpka_repair_pkt_sendup_action, 0); -#else - init_timer(&dhd->tcpka_rp_timer); - dhd->tcpka_rp_timer.data = (ulong)dhd; - dhd->tcpka_rp_timer.function = dhd_tcpka_repair_pkt_sendup_action; -#endif -#endif /* TCPKA_REPAIR */ - -#ifdef DHD_PCIE_RUNTIMEPM - /* Setup up the runtime PM Idlecount timer */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) - timer_setup(&dhd->rpm_timer, dhd_runtimepm, 0); -#else - init_timer(&dhd->rpm_timer); - dhd->rpm_timer.data = (ulong)dhd; - dhd->rpm_timer.function = dhd_runtimepm; -#endif - dhd->rpm_timer_valid = FALSE; - - dhd->thr_rpm_ctl.thr_pid = DHD_PID_KT_INVALID; - PROC_START(dhd_rpm_state_thread, dhd, &dhd->thr_rpm_ctl, 0, "dhd_rpm_state_thread"); - if (dhd->thr_rpm_ctl.thr_pid < 0) { - goto fail; - } -#endif /* DHD_PCIE_RUNTIMEPM */ - -#ifdef DEBUGGER - debugger_init((void *) bus); -#endif -#ifdef SHOW_LOGTRACE - skb_queue_head_init(&dhd->evt_trace_queue); -#endif /* SHOW_LOGTRACE */ - - /* Set up the bottom half handler */ - if (dhd_dpc_prio >= 0) { - /* Initialize DPC thread */ - PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0, "dhd_dpc"); - if (dhd->thr_dpc_ctl.thr_pid < 0) { - goto fail; - } - } else { - /* use tasklet for dpc */ - tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); - dhd->thr_dpc_ctl.thr_pid = -1; - } - - if (dhd->rxthread_enabled) { - bzero(&dhd->pub.skbbuf[0], sizeof(void *) * MAXSKBPEND); - /* Initialize RXF thread */ - PROC_START(dhd_rxf_thread, dhd, &dhd->thr_rxf_ctl, 0, "dhd_rxf"); - if (dhd->thr_rxf_ctl.thr_pid < 0) { - goto fail; - } - } -#endif /* !BCMDBUS */ - - dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; - -#if defined(CONFIG_PM_SLEEP) - if (!dhd_pm_notifier_registered) { - dhd_pm_notifier_registered = TRUE; - dhd->pm_notifier.notifier_call = dhd_pm_callback; - dhd->pm_notifier.priority = 10; - register_pm_notifier(&dhd->pm_notifier); - } - -#endif /* CONFIG_PM_SLEEP */ - -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) - dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20; - dhd->early_suspend.suspend = dhd_early_suspend; - dhd->early_suspend.resume = dhd_late_resume; - register_early_suspend(&dhd->early_suspend); - dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE; -#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ - -#ifdef ARP_OFFLOAD_SUPPORT - dhd->pend_ipaddr = 0; - if (!dhd_inetaddr_notifier_registered) { - dhd_inetaddr_notifier_registered = TRUE; - register_inetaddr_notifier(&dhd_inetaddr_notifier); - } -#endif /* ARP_OFFLOAD_SUPPORT */ - -#if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT) - if (!dhd_inet6addr_notifier_registered) { - dhd_inet6addr_notifier_registered = TRUE; - register_inet6addr_notifier(&dhd_inet6addr_notifier); - } -#endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ - dhd->dhd_deferred_wq = dhd_deferred_work_init((void *)dhd); -#ifdef DEBUG_CPU_FREQ - dhd->new_freq = alloc_percpu(int); - dhd->freq_trans.notifier_call = dhd_cpufreq_notifier; - cpufreq_register_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER); -#endif -#ifdef DHDTCPACK_SUPPRESS - dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_DEFAULT); -#endif /* DHDTCPACK_SUPPRESS */ - -#if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) -#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */ - - -#ifdef DHD_DEBUG_PAGEALLOC - register_page_corrupt_cb(dhd_page_corrupt_cb, &dhd->pub); -#endif /* DHD_DEBUG_PAGEALLOC */ - -#if defined(DHD_LB) - - dhd_lb_set_default_cpus(dhd); - - /* Initialize the CPU Masks */ - if (dhd_cpumasks_init(dhd) == 0) { - /* Now we have the current CPU maps, run through candidacy */ - dhd_select_cpu_candidacy(dhd); - /* - * If we are able to initialize CPU masks, lets register to the - * CPU Hotplug framework to change the CPU for each job dynamically - * using candidacy algorithm. - */ - dhd->cpu_notifier.notifier_call = dhd_cpu_callback; - register_hotcpu_notifier(&dhd->cpu_notifier); /* Register a callback */ - } else { - /* - * We are unable to initialize CPU masks, so candidacy algorithm - * won't run, but still Load Balancing will be honoured based - * on the CPUs allocated for a given job statically during init - */ - dhd->cpu_notifier.notifier_call = NULL; - DHD_ERROR(("%s():dhd_cpumasks_init failed CPUs for JOB would be static\n", - __FUNCTION__)); - } - -#ifdef DHD_LB_TXP -#ifdef DHD_LB_TXP_DEFAULT_ENAB - /* Trun ON the feature by default */ - atomic_set(&dhd->lb_txp_active, 1); -#else - /* Trun OFF the feature by default */ - atomic_set(&dhd->lb_txp_active, 0); -#endif /* DHD_LB_TXP_DEFAULT_ENAB */ -#endif /* DHD_LB_TXP */ - - DHD_LB_STATS_INIT(&dhd->pub); - - /* Initialize the Load Balancing Tasklets and Napi object */ -#if defined(DHD_LB_TXC) - tasklet_init(&dhd->tx_compl_tasklet, - dhd_lb_tx_compl_handler, (ulong)(&dhd->pub)); - INIT_WORK(&dhd->tx_compl_dispatcher_work, dhd_tx_compl_dispatcher_fn); - DHD_INFO(("%s load balance init tx_compl_tasklet\n", __FUNCTION__)); -#endif /* DHD_LB_TXC */ - -#if defined(DHD_LB_RXC) - tasklet_init(&dhd->rx_compl_tasklet, - dhd_lb_rx_compl_handler, (ulong)(&dhd->pub)); - DHD_INFO(("%s load balance init rx_compl_tasklet\n", __FUNCTION__)); -#endif /* DHD_LB_RXC */ - -#if defined(DHD_LB_RXP) - __skb_queue_head_init(&dhd->rx_pend_queue); - skb_queue_head_init(&dhd->rx_napi_queue); - /* Initialize the work that dispatches NAPI job to a given core */ - INIT_WORK(&dhd->rx_napi_dispatcher_work, dhd_rx_napi_dispatcher_fn); - DHD_INFO(("%s load balance init rx_napi_queue\n", __FUNCTION__)); -#endif /* DHD_LB_RXP */ - -#if defined(DHD_LB_TXP) - INIT_WORK(&dhd->tx_dispatcher_work, dhd_tx_dispatcher_work); - skb_queue_head_init(&dhd->tx_pend_queue); - /* Initialize the work that dispatches TX job to a given core */ - tasklet_init(&dhd->tx_tasklet, - dhd_lb_tx_handler, (ulong)(dhd)); - DHD_INFO(("%s load balance init tx_pend_queue\n", __FUNCTION__)); -#endif /* DHD_LB_TXP */ - - dhd_state |= DHD_ATTACH_STATE_LB_ATTACH_DONE; -#endif /* DHD_LB */ - -#ifdef SHOW_LOGTRACE - INIT_WORK(&dhd->event_log_dispatcher_work, dhd_event_logtrace_process); -#endif /* SHOW_LOGTRACE */ - - DHD_SSSR_MEMPOOL_INIT(&dhd->pub); - -#ifdef REPORT_FATAL_TIMEOUTS - init_dhd_timeouts(&dhd->pub); -#endif /* REPORT_FATAL_TIMEOUTS */ -#ifdef BCMPCIE - dhd->pub.extended_trap_data = MALLOCZ(osh, BCMPCIE_EXT_TRAP_DATA_MAXLEN); - if (dhd->pub.extended_trap_data == NULL) { - DHD_ERROR(("%s: Failed to alloc extended_trap_data\n", __FUNCTION__)); - } -#endif /* BCMPCIE */ -#ifdef TCPKA_REPAIR - INIT_WORK(&dhd->tcpka_reset_work, dhd_tcpka_reset_work); -#endif /* TCPKA_REPAIR */ - dhd_state |= DHD_ATTACH_STATE_DONE; - dhd->dhd_state = dhd_state; - - dhd_found++; - - return &dhd->pub; - -fail: - if (dhd_state >= DHD_ATTACH_STATE_DHD_ALLOC) { - DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n", - __FUNCTION__, dhd_state, &dhd->pub)); - dhd->dhd_state = dhd_state; - dhd_detach(&dhd->pub); - dhd_free(&dhd->pub); - } -dhd_null_flag: - return NULL; -} - -int dhd_get_fw_mode(dhd_info_t *dhdinfo) -{ - if (strstr(dhdinfo->fw_path, "_apsta") != NULL) - return DHD_FLAG_HOSTAP_MODE; - if (strstr(dhdinfo->fw_path, "_p2p") != NULL) - return DHD_FLAG_P2P_MODE; - if (strstr(dhdinfo->fw_path, "_ibss") != NULL) - return DHD_FLAG_IBSS_MODE; - if (strstr(dhdinfo->fw_path, "_mfg") != NULL) - return DHD_FLAG_MFG_MODE; - - return DHD_FLAG_STA_MODE; -} - -int dhd_bus_get_fw_mode(dhd_pub_t *dhdp) -{ - return dhd_get_fw_mode(dhdp->info); -} - -bool dhd_update_fw_nv_path(dhd_info_t *dhdinfo) -{ - int fw_len; - int nv_len; - int clm_len; - int conf_len; - int reg_len; - const char *fw = NULL; - const char *nv = NULL; - const char *clm = NULL; - const char *conf = NULL; - const char *reg = NULL; -#ifdef DHD_UCODE_DOWNLOAD - int uc_len; - const char *uc = NULL; -#endif /* DHD_UCODE_DOWNLOAD */ - wifi_adapter_info_t *adapter = dhdinfo->adapter; - int fw_path_len = sizeof(dhdinfo->fw_path); - int nv_path_len = sizeof(dhdinfo->nv_path); - - - /* Update firmware and nvram path. The path may be from adapter info or module parameter - * The path from adapter info is used for initialization only (as it won't change). - * - * The firmware_path/nvram_path module parameter may be changed by the system at run - * time. When it changes we need to copy it to dhdinfo->fw_path. Also Android private - * command may change dhdinfo->fw_path. As such we need to clear the path info in - * module parameter after it is copied. We won't update the path until the module parameter - * is changed again (first character is not '\0') - */ - - /* set default firmware and nvram path for built-in type driver */ -// if (!dhd_download_fw_on_driverload) { -#ifdef CONFIG_BCMDHD_FW_PATH - fw = CONFIG_BCMDHD_FW_PATH; -#endif /* CONFIG_BCMDHD_FW_PATH */ -#ifdef CONFIG_BCMDHD_NVRAM_PATH - nv = CONFIG_BCMDHD_NVRAM_PATH; -#endif /* CONFIG_BCMDHD_NVRAM_PATH */ -// } - - /* check if we need to initialize the path */ - if (dhdinfo->fw_path[0] == '\0') { - if (adapter && adapter->fw_path && adapter->fw_path[0] != '\0') - fw = adapter->fw_path; - - } - if (dhdinfo->nv_path[0] == '\0') { - if (adapter && adapter->nv_path && adapter->nv_path[0] != '\0') - nv = adapter->nv_path; - } - if (dhdinfo->clm_path[0] == '\0') { - if (adapter && adapter->clm_path && adapter->clm_path[0] != '\0') - clm = adapter->clm_path; - } - if (dhdinfo->conf_path[0] == '\0') { - if (adapter && adapter->conf_path && adapter->conf_path[0] != '\0') - conf = adapter->conf_path; - } - if (dhdinfo->reg_path[0] == '\0') { - if (adapter && adapter->reg_path && adapter->reg_path[0] != '\0') - reg = adapter->reg_path; - } - - /* Use module parameter if it is valid, EVEN IF the path has not been initialized - * - * TODO: need a solution for multi-chip, can't use the same firmware for all chips - */ - if (firmware_path[0] != '\0') - fw = firmware_path; - if (nvram_path[0] != '\0') - nv = nvram_path; - if (clm_path[0] != '\0') - clm = clm_path; - if (config_path[0] != '\0') - conf = config_path; - if (reg_path[0] != '\0') - reg = reg_path; -#ifdef DHD_UCODE_DOWNLOAD - if (ucode_path[0] != '\0') - uc = ucode_path; -#endif /* DHD_UCODE_DOWNLOAD */ - - if (fw && fw[0] != '\0') { - fw_len = strlen(fw); - if (fw_len >= fw_path_len) { - DHD_ERROR(("fw path len exceeds max len of dhdinfo->fw_path\n")); - return FALSE; - } - strncpy(dhdinfo->fw_path, fw, fw_path_len); - if (dhdinfo->fw_path[fw_len-1] == '\n') - dhdinfo->fw_path[fw_len-1] = '\0'; - } - if (nv && nv[0] != '\0') { - nv_len = strlen(nv); - if (nv_len >= nv_path_len) { - DHD_ERROR(("nvram path len exceeds max len of dhdinfo->nv_path\n")); - return FALSE; - } - memset(dhdinfo->nv_path, 0, nv_path_len); - strncpy(dhdinfo->nv_path, nv, nv_path_len); -#ifdef DHD_USE_SINGLE_NVRAM_FILE - /* Remove "_net" or "_mfg" tag from current nvram path */ - { - char *nvram_tag = "nvram_"; - char *ext_tag = ".txt"; - char *sp_nvram = strnstr(dhdinfo->nv_path, nvram_tag, nv_path_len); - bool valid_buf = sp_nvram && ((uint32)(sp_nvram + strlen(nvram_tag) + - strlen(ext_tag) - dhdinfo->nv_path) <= nv_path_len); - if (valid_buf) { - char *sp = sp_nvram + strlen(nvram_tag) - 1; - uint32 padding_size = (uint32)(dhdinfo->nv_path + - nv_path_len - sp); - memset(sp, 0, padding_size); - strncat(dhdinfo->nv_path, ext_tag, strlen(ext_tag)); - nv_len = strlen(dhdinfo->nv_path); - DHD_INFO(("%s: new nvram path = %s\n", - __FUNCTION__, dhdinfo->nv_path)); - } else if (sp_nvram) { - DHD_ERROR(("%s: buffer space for nvram path is not enough\n", - __FUNCTION__)); - return FALSE; - } else { - DHD_ERROR(("%s: Couldn't find the nvram tag. current" - " nvram path = %s\n", __FUNCTION__, dhdinfo->nv_path)); - } - } -#endif /* DHD_USE_SINGLE_NVRAM_FILE */ - if (dhdinfo->nv_path[nv_len-1] == '\n') - dhdinfo->nv_path[nv_len-1] = '\0'; - } - if (clm && clm[0] != '\0') { - clm_len = strlen(clm); - if (clm_len >= sizeof(dhdinfo->clm_path)) { - DHD_ERROR(("clm path len exceeds max len of dhdinfo->clm_path\n")); - return FALSE; - } - strncpy(dhdinfo->clm_path, clm, sizeof(dhdinfo->clm_path)); - if (dhdinfo->clm_path[clm_len-1] == '\n') - dhdinfo->clm_path[clm_len-1] = '\0'; - } - if (conf && conf[0] != '\0') { - conf_len = strlen(conf); - if (conf_len >= sizeof(dhdinfo->conf_path)) { - DHD_ERROR(("config path len exceeds max len of dhdinfo->conf_path\n")); - return FALSE; - } - strncpy(dhdinfo->conf_path, conf, sizeof(dhdinfo->conf_path)); - if (dhdinfo->conf_path[conf_len-1] == '\n') - dhdinfo->conf_path[conf_len-1] = '\0'; - } - - if (reg && reg[0] != '\0') { - reg_len = strlen(reg); - if (reg_len >= sizeof(dhdinfo->reg_path)) { - DHD_ERROR(("reg path len exceeds max len of dhdinfo->reg_path\n")); - return FALSE; - } - strncpy(dhdinfo->reg_path, reg, sizeof(dhdinfo->reg_path)); - if (dhdinfo->reg_path[reg_len-1] == '\n') - dhdinfo->reg_path[reg_len-1] = '\0'; - } - -#ifdef DHD_UCODE_DOWNLOAD - if (uc && uc[0] != '\0') { - uc_len = strlen(uc); - if (uc_len >= sizeof(dhdinfo->uc_path)) { - DHD_ERROR(("uc path len exceeds max len of dhdinfo->uc_path\n")); - return FALSE; - } - strncpy(dhdinfo->uc_path, uc, sizeof(dhdinfo->uc_path)); - if (dhdinfo->uc_path[uc_len-1] == '\n') - dhdinfo->uc_path[uc_len-1] = '\0'; - } -#endif /* DHD_UCODE_DOWNLOAD */ - -#if 0 - /* clear the path in module parameter */ - if (dhd_download_fw_on_driverload) { - firmware_path[0] = '\0'; - nvram_path[0] = '\0'; - clm_path[0] = '\0'; - config_path[0] = '\0'; - } -#endif -#ifdef DHD_UCODE_DOWNLOAD - ucode_path[0] = '\0'; - DHD_ERROR(("ucode path: %s\n", dhdinfo->uc_path)); -#endif /* DHD_UCODE_DOWNLOAD */ - -#ifndef BCMEMBEDIMAGE - /* fw_path and nv_path are not mandatory for BCMEMBEDIMAGE */ - if (dhdinfo->fw_path[0] == '\0') { - DHD_ERROR(("firmware path not found\n")); - return FALSE; - } - if (dhdinfo->nv_path[0] == '\0') { - DHD_ERROR(("nvram path not found\n")); - return FALSE; - } -#endif /* BCMEMBEDIMAGE */ - - return TRUE; -} - -#if defined(BT_OVER_SDIO) -extern bool dhd_update_btfw_path(dhd_info_t *dhdinfo, char* btfw_path) -{ - int fw_len; - const char *fw = NULL; - wifi_adapter_info_t *adapter = dhdinfo->adapter; - - - /* Update bt firmware path. The path may be from adapter info or module parameter - * The path from adapter info is used for initialization only (as it won't change). - * - * The btfw_path module parameter may be changed by the system at run - * time. When it changes we need to copy it to dhdinfo->btfw_path. Also Android private - * command may change dhdinfo->btfw_path. As such we need to clear the path info in - * module parameter after it is copied. We won't update the path until the module parameter - * is changed again (first character is not '\0') - */ - - /* set default firmware and nvram path for built-in type driver */ - if (!dhd_download_fw_on_driverload) { -#ifdef CONFIG_BCMDHD_BTFW_PATH - fw = CONFIG_BCMDHD_BTFW_PATH; -#endif /* CONFIG_BCMDHD_FW_PATH */ - } - - /* check if we need to initialize the path */ - if (dhdinfo->btfw_path[0] == '\0') { - if (adapter && adapter->btfw_path && adapter->btfw_path[0] != '\0') - fw = adapter->btfw_path; - } - - /* Use module parameter if it is valid, EVEN IF the path has not been initialized - */ - if (btfw_path[0] != '\0') - fw = btfw_path; - - if (fw && fw[0] != '\0') { - fw_len = strlen(fw); - if (fw_len >= sizeof(dhdinfo->btfw_path)) { - DHD_ERROR(("fw path len exceeds max len of dhdinfo->btfw_path\n")); - return FALSE; - } - strncpy(dhdinfo->btfw_path, fw, sizeof(dhdinfo->btfw_path)); - if (dhdinfo->btfw_path[fw_len-1] == '\n') - dhdinfo->btfw_path[fw_len-1] = '\0'; - } - - /* clear the path in module parameter */ - btfw_path[0] = '\0'; - - if (dhdinfo->btfw_path[0] == '\0') { - DHD_ERROR(("bt firmware path not found\n")); - return FALSE; - } - - return TRUE; -} -#endif /* defined (BT_OVER_SDIO) */ - - -#ifdef CUSTOMER_HW4_DEBUG -bool dhd_validate_chipid(dhd_pub_t *dhdp) -{ - uint chipid = dhd_bus_chip_id(dhdp); - uint config_chipid; - -#ifdef BCM4361_CHIP - config_chipid = BCM4361_CHIP_ID; -#elif defined(BCM4359_CHIP) - config_chipid = BCM4359_CHIP_ID; -#elif defined(BCM4358_CHIP) - config_chipid = BCM4358_CHIP_ID; -#elif defined(BCM4354_CHIP) - config_chipid = BCM4354_CHIP_ID; -#elif defined(BCM4339_CHIP) - config_chipid = BCM4339_CHIP_ID; -#elif defined(BCM43349_CHIP) - config_chipid = BCM43349_CHIP_ID; -#elif defined(BCM4335_CHIP) - config_chipid = BCM4335_CHIP_ID; -#elif defined(BCM43241_CHIP) - config_chipid = BCM4324_CHIP_ID; -#elif defined(BCM4330_CHIP) - config_chipid = BCM4330_CHIP_ID; -#elif defined(BCM43430_CHIP) - config_chipid = BCM43430_CHIP_ID; -#elif defined(BCM43018_CHIP) - config_chipid = BCM43018_CHIP_ID; -#elif defined(BCM43455_CHIP) - config_chipid = BCM4345_CHIP_ID; -#elif defined(BCM4334W_CHIP) - config_chipid = BCM43342_CHIP_ID; -#elif defined(BCM43454_CHIP) - config_chipid = BCM43454_CHIP_ID; -#elif defined(BCM43012_CHIP_) - config_chipid = BCM43012_CHIP_ID; -#else - DHD_ERROR(("%s: Unknown chip id, if you use new chipset," - " please add CONFIG_BCMXXXX into the Kernel and" - " BCMXXXX_CHIP definition into the DHD driver\n", - __FUNCTION__)); - config_chipid = 0; - - return FALSE; -#endif /* BCM4354_CHIP */ - -#ifdef SUPPORT_MULTIPLE_CHIP_4345X - if (config_chipid == BCM43454_CHIP_ID || config_chipid == BCM4345_CHIP_ID) { - return TRUE; - } -#endif /* SUPPORT_MULTIPLE_CHIP_4345X */ -#if defined(BCM4359_CHIP) - if (chipid == BCM4355_CHIP_ID && config_chipid == BCM4359_CHIP_ID) { - return TRUE; - } -#endif /* BCM4359_CHIP */ -#if defined(BCM4361_CHIP) - if (chipid == BCM4347_CHIP_ID && config_chipid == BCM4361_CHIP_ID) { - return TRUE; - } -#endif /* BCM4361_CHIP */ - - return config_chipid == chipid; -} -#endif /* CUSTOMER_HW4_DEBUG */ - -#if defined(BT_OVER_SDIO) -wlan_bt_handle_t dhd_bt_get_pub_hndl(void) -{ - DHD_ERROR(("%s: g_dhd_pub %p\n", __FUNCTION__, g_dhd_pub)); - /* assuming that dhd_pub_t type pointer is available from a global variable */ - return (wlan_bt_handle_t) g_dhd_pub; -} EXPORT_SYMBOL(dhd_bt_get_pub_hndl); - -int dhd_download_btfw(wlan_bt_handle_t handle, char* btfw_path) -{ - int ret = -1; - dhd_pub_t *dhdp = (dhd_pub_t *)handle; - dhd_info_t *dhd = (dhd_info_t*)dhdp->info; - - - /* Download BT firmware image to the dongle */ - if (dhd->pub.busstate == DHD_BUS_DATA && dhd_update_btfw_path(dhd, btfw_path)) { - DHD_INFO(("%s: download btfw from: %s\n", __FUNCTION__, dhd->btfw_path)); - ret = dhd_bus_download_btfw(dhd->pub.bus, dhd->pub.osh, dhd->btfw_path); - if (ret < 0) { - DHD_ERROR(("%s: failed to download btfw from: %s\n", - __FUNCTION__, dhd->btfw_path)); - return ret; - } - } - return ret; -} EXPORT_SYMBOL(dhd_download_btfw); -#endif /* defined (BT_OVER_SDIO) */ - -#ifndef BCMDBUS -int -dhd_bus_start(dhd_pub_t *dhdp) -{ - int ret = -1; - dhd_info_t *dhd = (dhd_info_t*)dhdp->info; - unsigned long flags; - -#if defined(DHD_DEBUG) && defined(BCMSDIO) - int fw_download_start = 0, fw_download_end = 0, f2_sync_start = 0, f2_sync_end = 0; -#endif /* DHD_DEBUG && BCMSDIO */ - ASSERT(dhd); - - DHD_TRACE(("Enter %s:\n", __FUNCTION__)); - - DHD_PERIM_LOCK(dhdp); -#ifdef HOFFLOAD_MODULES - dhd_linux_get_modfw_address(dhdp); -#endif - /* try to download image and nvram to the dongle */ - if (dhd->pub.busstate == DHD_BUS_DOWN && dhd_update_fw_nv_path(dhd)) { - /* Indicate FW Download has not yet done */ - dhd->pub.fw_download_done = FALSE; - DHD_INFO(("%s download fw %s, nv %s, conf %s, reg %s\n", - __FUNCTION__, dhd->fw_path, dhd->nv_path, - dhd->conf_path, dhd->reg_path)); -#if defined(DHD_DEBUG) && defined(BCMSDIO) - fw_download_start = OSL_SYSUPTIME(); -#endif /* DHD_DEBUG && BCMSDIO */ - ret = dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, - dhd->fw_path, dhd->nv_path, dhd->clm_path, - dhd->conf_path, dhd->reg_path); -#if defined(DHD_DEBUG) && defined(BCMSDIO) - fw_download_end = OSL_SYSUPTIME(); -#endif /* DHD_DEBUG && BCMSDIO */ - if (ret < 0) { - DHD_ERROR(("%s: failed to download firmware %s\n", - __FUNCTION__, dhd->fw_path)); - DHD_PERIM_UNLOCK(dhdp); - return ret; - } - /* Indicate FW Download has succeeded */ - dhd->pub.fw_download_done = TRUE; - } - if (dhd->pub.busstate != DHD_BUS_LOAD) { - DHD_PERIM_UNLOCK(dhdp); - return -ENETDOWN; - } - -#ifdef BCMSDIO - dhd_os_sdlock(dhdp); -#endif /* BCMSDIO */ - - /* Start the watchdog timer */ - dhd->pub.tickcnt = 0; - dhd->default_wd_interval = dhd_watchdog_ms; - dhd_set_idletime(&dhd->pub, dhd_idletime); - dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); - - /* Bring up the bus */ - if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) { - - DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret)); -#ifdef BCMSDIO - dhd_os_sdunlock(dhdp); -#endif /* BCMSDIO */ - DHD_PERIM_UNLOCK(dhdp); - return ret; - } - - DHD_ENABLE_RUNTIME_PM(&dhd->pub); - -#ifdef DHD_ULP - dhd_ulp_set_ulp_state(dhdp, DHD_ULP_DISABLED); -#endif /* DHD_ULP */ -#if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE) - /* Host registration for OOB interrupt */ - if (dhd_bus_oob_intr_register(dhdp)) { - /* deactivate timer and wait for the handler to finish */ -#if !defined(BCMPCIE_OOB_HOST_WAKE) - DHD_GENERAL_LOCK(&dhd->pub, flags); - dhd->wd_timer_valid = FALSE; - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - del_timer_sync(&dhd->timer); - -#endif /* !BCMPCIE_OOB_HOST_WAKE */ - DHD_DISABLE_RUNTIME_PM(&dhd->pub); - DHD_PERIM_UNLOCK(dhdp); - DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__)); - return -ENODEV; - } - -#if defined(BCMPCIE_OOB_HOST_WAKE) - dhd_bus_oob_intr_set(dhdp, TRUE); -#else - /* Enable oob at firmware */ - dhd_enable_oob_intr(dhd->pub.bus, TRUE); -#endif /* BCMPCIE_OOB_HOST_WAKE */ -#elif defined(FORCE_WOWLAN) - /* Enable oob at firmware */ - dhd_enable_oob_intr(dhd->pub.bus, TRUE); -#endif -#ifdef PCIE_FULL_DONGLE - { - /* max_h2d_rings includes H2D common rings */ - uint32 max_h2d_rings = dhd_bus_max_h2d_queues(dhd->pub.bus); - - DHD_ERROR(("%s: Initializing %u h2drings\n", __FUNCTION__, - max_h2d_rings)); - if ((ret = dhd_flow_rings_init(&dhd->pub, max_h2d_rings)) != BCME_OK) { -#ifdef BCMSDIO - dhd_os_sdunlock(dhdp); -#endif /* BCMSDIO */ - DHD_PERIM_UNLOCK(dhdp); - return ret; - } - } -#endif /* PCIE_FULL_DONGLE */ - - /* Do protocol initialization necessary for IOCTL/IOVAR */ - ret = dhd_prot_init(&dhd->pub); - if (unlikely(ret) != BCME_OK) { - DHD_PERIM_UNLOCK(dhdp); - DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); - return ret; - } - - /* If bus is not ready, can't come up */ - if (dhd->pub.busstate != DHD_BUS_DATA) { - DHD_GENERAL_LOCK(&dhd->pub, flags); - dhd->wd_timer_valid = FALSE; - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - del_timer_sync(&dhd->timer); - DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); - DHD_DISABLE_RUNTIME_PM(&dhd->pub); -#ifdef BCMSDIO - dhd_os_sdunlock(dhdp); -#endif /* BCMSDIO */ - DHD_PERIM_UNLOCK(dhdp); - return -ENODEV; - } - -#ifdef BCMSDIO - dhd_os_sdunlock(dhdp); - /* restore bus level setting to enable communication */ - if (dhd_chip_alive) { - DHD_INFO(("chip alive, set txglom %d\n", dhdp->conf->bus_rxglom)); - dhd_txglom_enable(dhdp, dhdp->conf->bus_rxglom); - } -#endif /* BCMSDIO */ - - /* Bus is ready, query any dongle information */ -#if defined(DHD_DEBUG) && defined(BCMSDIO) - f2_sync_start = OSL_SYSUPTIME(); -#endif /* DHD_DEBUG && BCMSDIO */ - if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) { - DHD_GENERAL_LOCK(&dhd->pub, flags); - dhd->wd_timer_valid = FALSE; - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - del_timer_sync(&dhd->timer); - DHD_ERROR(("%s failed to sync with dongle\n", __FUNCTION__)); - DHD_OS_WD_WAKE_UNLOCK(&dhd->pub); - DHD_PERIM_UNLOCK(dhdp); - return ret; - } -#if defined(CONFIG_SOC_EXYNOS8895) - DHD_ERROR(("%s: Enable L1ss EP side\n", __FUNCTION__)); - exynos_pcie_l1ss_ctrl(1, PCIE_L1SS_CTRL_WIFI); -#endif /* CONFIG_SOC_EXYNOS8895 */ - -#if defined(DHD_DEBUG) && defined(BCMSDIO) - f2_sync_end = OSL_SYSUPTIME(); - DHD_INFO(("Time taken for FW download and F2 ready is: %d msec\n", - (fw_download_end - fw_download_start) + (f2_sync_end - f2_sync_start))); -#endif /* DHD_DEBUG && BCMSDIO */ - -#ifdef ARP_OFFLOAD_SUPPORT - if (dhd->pend_ipaddr) { -#ifdef AOE_IP_ALIAS_SUPPORT - aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE, 0); -#endif /* AOE_IP_ALIAS_SUPPORT */ - dhd->pend_ipaddr = 0; - } -#endif /* ARP_OFFLOAD_SUPPORT */ - -#if defined(TRAFFIC_MGMT_DWM) - bzero(&dhd->pub.dhd_tm_dwm_tbl, sizeof(dhd_trf_mgmt_dwm_tbl_t)); -#endif - DHD_PERIM_UNLOCK(dhdp); - -#ifdef RESUME_INIT - dhdp->resume_init = dhd_chip_alive; -#endif /* RESUME_INIT */ - if (dhd_chip_alive) { - DHD_INFO(("%s: reset dhd_chip_alive\n", __FUNCTION__)); - dhd_chip_alive = 0; - sdio_set_chip_alive(dhd_chip_alive); - } - return 0; -} -#endif /* !BCMDBUS */ - -#ifdef WLTDLS -int _dhd_tdls_enable(dhd_pub_t *dhd, bool tdls_on, bool auto_on, struct ether_addr *mac) -{ - uint32 tdls = tdls_on; - int ret = 0; - uint32 tdls_auto_op = 0; - uint32 tdls_idle_time = CUSTOM_TDLS_IDLE_MODE_SETTING; - int32 tdls_rssi_high = CUSTOM_TDLS_RSSI_THRESHOLD_HIGH; - int32 tdls_rssi_low = CUSTOM_TDLS_RSSI_THRESHOLD_LOW; - BCM_REFERENCE(mac); - if (!FW_SUPPORTED(dhd, tdls)) - return BCME_ERROR; - - if (dhd->tdls_enable == tdls_on) - goto auto_mode; - ret = dhd_iovar(dhd, 0, "tdls_enable", (char *)&tdls, sizeof(tdls), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: tdls %d failed %d\n", __FUNCTION__, tdls, ret)); - goto exit; - } - dhd->tdls_enable = tdls_on; -auto_mode: - - tdls_auto_op = auto_on; - ret = dhd_iovar(dhd, 0, "tdls_auto_op", (char *)&tdls_auto_op, sizeof(tdls_auto_op), NULL, - 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: tdls_auto_op failed %d\n", __FUNCTION__, ret)); - goto exit; - } - - if (tdls_auto_op) { - ret = dhd_iovar(dhd, 0, "tdls_idle_time", (char *)&tdls_idle_time, - sizeof(tdls_idle_time), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: tdls_idle_time failed %d\n", __FUNCTION__, ret)); - goto exit; - } - ret = dhd_iovar(dhd, 0, "tdls_rssi_high", (char *)&tdls_rssi_high, - sizeof(tdls_rssi_high), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: tdls_rssi_high failed %d\n", __FUNCTION__, ret)); - goto exit; - } - ret = dhd_iovar(dhd, 0, "tdls_rssi_low", (char *)&tdls_rssi_low, - sizeof(tdls_rssi_low), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: tdls_rssi_low failed %d\n", __FUNCTION__, ret)); - goto exit; - } - } - -exit: - return ret; -} - -int dhd_tdls_enable(struct net_device *dev, bool tdls_on, bool auto_on, struct ether_addr *mac) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - if (dhd) - ret = _dhd_tdls_enable(&dhd->pub, tdls_on, auto_on, mac); - else - ret = BCME_ERROR; - return ret; -} - -int -dhd_tdls_set_mode(dhd_pub_t *dhd, bool wfd_mode) -{ - int ret = 0; - bool auto_on = false; - uint32 mode = wfd_mode; - -#ifdef ENABLE_TDLS_AUTO_MODE - if (wfd_mode) { - auto_on = false; - } else { - auto_on = true; - } -#else - auto_on = false; -#endif /* ENABLE_TDLS_AUTO_MODE */ - ret = _dhd_tdls_enable(dhd, false, auto_on, NULL); - if (ret < 0) { - DHD_ERROR(("Disable tdls_auto_op failed. %d\n", ret)); - return ret; - } - - ret = dhd_iovar(dhd, 0, "tdls_wfd_mode", (char *)&mode, sizeof(mode), NULL, 0, TRUE); - if ((ret < 0) && (ret != BCME_UNSUPPORTED)) { - DHD_ERROR(("%s: tdls_wfd_mode faile_wfd_mode %d\n", __FUNCTION__, ret)); - return ret; - } - - ret = _dhd_tdls_enable(dhd, true, auto_on, NULL); - if (ret < 0) { - DHD_ERROR(("enable tdls_auto_op failed. %d\n", ret)); - return ret; - } - - dhd->tdls_mode = mode; - return ret; -} -#ifdef PCIE_FULL_DONGLE -int dhd_tdls_update_peer_info(dhd_pub_t *dhdp, wl_event_msg_t *event) -{ - dhd_pub_t *dhd_pub = dhdp; - tdls_peer_node_t *cur = dhd_pub->peer_tbl.node; - tdls_peer_node_t *new = NULL, *prev = NULL; - int ifindex = dhd_ifname2idx(dhd_pub->info, event->ifname); - uint8 *da = (uint8 *)&event->addr.octet[0]; - bool connect = FALSE; - uint32 reason = ntoh32(event->reason); - unsigned long flags; - - if (reason == WLC_E_TDLS_PEER_CONNECTED) - connect = TRUE; - else if (reason == WLC_E_TDLS_PEER_DISCONNECTED) - connect = FALSE; - else - { - DHD_ERROR(("%s: TDLS Event reason is unknown\n", __FUNCTION__)); - return BCME_ERROR; - } - if (ifindex == DHD_BAD_IF) - return BCME_ERROR; - - if (connect) { - while (cur != NULL) { - if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) { - DHD_ERROR(("%s: TDLS Peer exist already %d\n", - __FUNCTION__, __LINE__)); - return BCME_ERROR; - } - cur = cur->next; - } - - new = MALLOC(dhd_pub->osh, sizeof(tdls_peer_node_t)); - if (new == NULL) { - DHD_ERROR(("%s: Failed to allocate memory\n", __FUNCTION__)); - return BCME_ERROR; - } - memcpy(new->addr, da, ETHER_ADDR_LEN); - DHD_TDLS_LOCK(&dhdp->tdls_lock, flags); - new->next = dhd_pub->peer_tbl.node; - dhd_pub->peer_tbl.node = new; - dhd_pub->peer_tbl.tdls_peer_count++; - DHD_TDLS_UNLOCK(&dhdp->tdls_lock, flags); - - } else { - while (cur != NULL) { - if (!memcmp(da, cur->addr, ETHER_ADDR_LEN)) { - dhd_flow_rings_delete_for_peer(dhd_pub, (uint8)ifindex, da); - DHD_TDLS_LOCK(&dhdp->tdls_lock, flags); - if (prev) - prev->next = cur->next; - else - dhd_pub->peer_tbl.node = cur->next; - MFREE(dhd_pub->osh, cur, sizeof(tdls_peer_node_t)); - dhd_pub->peer_tbl.tdls_peer_count--; - DHD_TDLS_UNLOCK(&dhdp->tdls_lock, flags); - return BCME_OK; - } - prev = cur; - cur = cur->next; - } - DHD_ERROR(("%s: TDLS Peer Entry Not found\n", __FUNCTION__)); - } - return BCME_OK; -} -#endif /* PCIE_FULL_DONGLE */ -#endif - -bool dhd_is_concurrent_mode(dhd_pub_t *dhd) -{ - if (!dhd) - return FALSE; - - if (dhd->op_mode & DHD_FLAG_CONCURR_MULTI_CHAN_MODE) - return TRUE; - else if ((dhd->op_mode & DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) == - DHD_FLAG_CONCURR_SINGLE_CHAN_MODE) - return TRUE; - else - return FALSE; -} -#if !defined(AP) && defined(WLP2P) -/* From Android JerryBean release, the concurrent mode is enabled by default and the firmware - * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA - * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware - * would still be named as fw_bcmdhd_apsta. - */ -uint32 -dhd_get_concurrent_capabilites(dhd_pub_t *dhd) -{ - int32 ret = 0; - char buf[WLC_IOCTL_SMLEN]; - bool mchan_supported = FALSE; - /* if dhd->op_mode is already set for HOSTAP and Manufacturing - * test mode, that means we only will use the mode as it is - */ - if (dhd->op_mode & (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE)) - return 0; - if (FW_SUPPORTED(dhd, vsdb)) { - mchan_supported = TRUE; - } - if (!FW_SUPPORTED(dhd, p2p)) { - DHD_TRACE(("Chip does not support p2p\n")); - return 0; - } else { - /* Chip supports p2p but ensure that p2p is really implemented in firmware or not */ - memset(buf, 0, sizeof(buf)); - ret = dhd_iovar(dhd, 0, "p2p", NULL, 0, (char *)&buf, - sizeof(buf), FALSE); - if (ret < 0) { - DHD_ERROR(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret)); - return 0; - } else { - if (buf[0] == 1) { - /* By default, chip supports single chan concurrency, - * now lets check for mchan - */ - ret = DHD_FLAG_CONCURR_SINGLE_CHAN_MODE; - if (mchan_supported) - ret |= DHD_FLAG_CONCURR_MULTI_CHAN_MODE; - if (FW_SUPPORTED(dhd, rsdb)) { - ret |= DHD_FLAG_RSDB_MODE; - } -#ifdef WL_SUPPORT_MULTIP2P - if (FW_SUPPORTED(dhd, mp2p)) { - ret |= DHD_FLAG_MP2P_MODE; - } -#endif /* WL_SUPPORT_MULTIP2P */ -#if defined(WL_ENABLE_P2P_IF) || defined(WL_CFG80211_P2P_DEV_IF) - return ret; -#else - return 0; -#endif /* WL_ENABLE_P2P_IF || WL_CFG80211_P2P_DEV_IF */ - } - } - } - return 0; -} -#endif - -#ifdef SUPPORT_AP_POWERSAVE -#define RXCHAIN_PWRSAVE_PPS 10 -#define RXCHAIN_PWRSAVE_QUIET_TIME 10 -#define RXCHAIN_PWRSAVE_STAS_ASSOC_CHECK 0 -int dhd_set_ap_powersave(dhd_pub_t *dhdp, int ifidx, int enable) -{ - int32 pps = RXCHAIN_PWRSAVE_PPS; - int32 quiet_time = RXCHAIN_PWRSAVE_QUIET_TIME; - int32 stas_assoc_check = RXCHAIN_PWRSAVE_STAS_ASSOC_CHECK; - int ret; - - if (enable) { - ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_enable", (char *)&enable, sizeof(enable), - NULL, 0, TRUE); - if (ret != BCME_OK) { - DHD_ERROR(("Failed to enable AP power save\n")); - } - ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_pps", (char *)&pps, sizeof(pps), NULL, 0, - TRUE); - if (ret != BCME_OK) { - DHD_ERROR(("Failed to set pps\n")); - } - ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_quiet_time", (char *)&quiet_time, - sizeof(quiet_time), NULL, 0, TRUE); - if (ret != BCME_OK) { - DHD_ERROR(("Failed to set quiet time\n")); - } - ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_stas_assoc_check", - (char *)&stas_assoc_check, sizeof(stas_assoc_check), NULL, 0, TRUE); - if (ret != BCME_OK) { - DHD_ERROR(("Failed to set stas assoc check\n")); - } - } else { - ret = dhd_iovar(dhdp, 0, "rxchain_pwrsave_enable", (char *)&enable, sizeof(enable), - NULL, 0, TRUE); - if (ret != BCME_OK) { - DHD_ERROR(("Failed to disable AP power save\n")); - } - } - - return 0; -} -#endif /* SUPPORT_AP_POWERSAVE */ - - - - -#if defined(WLADPS) || defined(WLADPS_PRIVATE_CMD) -int -dhd_enable_adps(dhd_pub_t *dhd, uint8 on) -{ - int i; - int len; - int ret = BCME_OK; - - bcm_iov_buf_t *iov_buf = NULL; - wl_adps_params_v1_t *data = NULL; - char buf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ - - len = OFFSETOF(bcm_iov_buf_t, data) + sizeof(*data); - iov_buf = kmalloc(len, GFP_KERNEL); - if (iov_buf == NULL) { - DHD_ERROR(("%s - failed to allocate %d bytes for iov_buf\n", __FUNCTION__, len)); - ret = BCME_NOMEM; - goto exit; - } - - iov_buf->version = WL_ADPS_IOV_VER; - iov_buf->len = sizeof(*data); - iov_buf->id = WL_ADPS_IOV_MODE; - - data = (wl_adps_params_v1_t *)iov_buf->data; - data->version = ADPS_SUB_IOV_VERSION_1; - data->length = sizeof(*data); - data->mode = on; - - for (i = 1; i <= MAX_BANDS; i++) { - data->band = i; - bcm_mkiovar("adps", (char *)iov_buf, len, buf, sizeof(buf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0)) < 0) { - if (ret == BCME_UNSUPPORTED) { - DHD_ERROR(("%s adps is not supported\n", __FUNCTION__)); - ret = BCME_OK; - goto exit; - } - else { - DHD_ERROR(("%s fail to set adps %s for band %d (%d)\n", - __FUNCTION__, on ? "On" : "Off", i, ret)); - goto exit; - } - } - } - -exit: - if (iov_buf) { - kfree(iov_buf); - } - return ret; -} -#endif /* WLADPS || WLADPS_PRIVATE_CMD */ - -#ifdef RESUME_INIT -#ifdef WIFI_STATS -char *ip_ntoa(uint32_t ia, char *buf) { - snprintf(buf, 16, "%d.%d.%d.%d", - ((ia) & 0xff), ((ia >> 8) & 0xff), - ((ia >> 16) & 0xff), ((ia >> 24) & 0xff)); - return (buf); -} - -static void -dhd_dump_wifi_stats(dhd_pub_t *dhd, bool *is_tcpka6) -{ - wifi_fw_stats_t *wstats = &g_wstats; - wake_counts_t *wcp = dhd_bus_get_wakecount(dhd); - wifi_stats_ap_info_t *ap; - wifi_stats_sleep_cfg_t *cfg = &wstats->sleep_cfg; - wifi_stats_host_wake_t *wake = &wstats->wake_stats; - int i, ret = 0; - - ret = dhd_iovar(dhd, 0, "wifi_stats", NULL, 0, - (char *)wstats, sizeof(wifi_fw_stats_t), FALSE); - if (ret) { - DHD_ERROR(("%s: get wifi stats failed, ret = %d\n", - __func__, ret)); - return; - } - - wstats->wake_stats.rx_wakes = wcp->rxwake; - memcpy(&wstats->wake_stats.ctrl_wakes, &wcp->event, - sizeof(wstats->wake_stats.ctrl_wakes)); - - for (i = 0; i < wstats->ap_cnt; i ++) { - char etoa_buf[ETHER_ADDR_LEN * 3]; - - ap = &wstats->ap_info[i]; - DHD_ERROR(("AP[%d]: bssid %s chan %d rssi [min %d max %d] " - "bi %d dtim %d wsec 0x%04x wpa_auth 0x%04x len (%d) SSID \"%s\"", - i, bcm_ether_ntoa(&ap->bssid, etoa_buf), - ap->channel, ap->rssi_min, ap->rssi_max, - ap->bi_us, ap->dtim_period, ap->wsec, ap->wpa_auth, - ap->ssid_len, ap->ssid)); - } - - DHD_ERROR(("SLEEP: pm %d mpc %d msm %d dtim_skip %d pretbtt %d is_connected %s", - cfg->pm_mode, cfg->mpc, cfg->max_sleep_ms, cfg->dtim_skip, - cfg->pretbtt, cfg->is_connected ? "true" : "false")); - for (i = 0; i < cfg->mka_cnt; i++) { - sleep_cfg_mkeepalive_t *mka = &cfg->mka[i]; - DHD_ERROR(("SLEEP: mkeepalive[%d]: period %d len %d", - mka->id, mka->period, mka->len)); - } - for (i = 0; i < cfg->tcpka_cnt; i++) { - sleep_cfg_tcpka_t *tcpka = &cfg->tcpka[i]; - char src_ip[18], dst_ip[18]; - DHD_ERROR(("SLEEP: tcpka[%d]: txenab %s src %s:%d dst %s:%d", - i, tcpka->tx_enable ? "true" : "false", - ip_ntoa(tcpka->src_ip, src_ip), tcpka->src_port, - ip_ntoa(tcpka->dst_ip, dst_ip), tcpka->dst_port)); - if (IPV4_ADDR_NULL(&tcpka->src_ip) && IPV4_ADDR_NULL(&tcpka->dst_ip) && - cfg->is_tcp_connected) { - if (is_tcpka6) - *is_tcpka6 = true; - } - } - - DHD_ERROR(("WAKE: rx_wakes %d ctrl_wakes 0x%08x sleep_dur %d pm_dur %d " - "bcn %d rxbadplcp %d rxbadfcs %d", - wake->rx_wakes, wake->ctrl_wakes, wake->sleep_duration, wake->pm_duration, - wake->beacons, wake->rx_badplcp, wake->rx_badfcs)); - for (i = 0; i < wake->pf_cnt; i++) { - wake_stats_pktfilter_t *pf = &wake->pf[i]; - DHD_ERROR(("WAKE: pf[%d]: polarity %d timeout %d num_pkts_matched %d timed_out %s", - pf->id, pf->polarity, pf->timeout, pf->num_pkts_matched, - pf->timed_out ? "true" : "false")); - } -} -#endif /* WIFI_STATS */ - -static void -dhd_resumeinit_ioctls(dhd_pub_t *dhd, struct net_device *dev) -{ - int ret = 0; - uint32 val = 0; - bool is_tcpka6 = false; -#ifdef BCOL_TCPKA_SYNC - uint32 is_blocked = 0; -#endif /* BCOL_TCPKA_SYNC */ - -#ifdef BCOL_TCPKA_SYNC - /* can not remove pkt filter here for handing tcpka from server */ - dhd_wl_ioctl_get_intiovar(dhd, "tcpka_conn_repair", &val, - WLC_GET_VAR, FALSE, 0); - /* Reset TCPKA if it is blocked */ - dhd_wl_ioctl_get_intiovar(dhd, "tcpka_conn_repair_block", &is_blocked, - WLC_GET_VAR, FALSE, 0); - DHD_ERROR(("%s: repair %d isv6 %d block %d\n", __func__, - val, is_tcpka6, is_blocked)); - if (!val || is_tcpka6 || is_blocked) { - dhd_tcpka_reset(dhd, dev); - } -#endif /* BCOL_TCPKA_SYNC */ - -#ifdef WIFI_STATS - dhd_dump_wifi_stats(dhd, &is_tcpka6); -#endif /* WIFI_STATS */ - -#ifdef EVENT_DATA_HOSTWAKE - ret = dhd_sched_wake_setup(dhd, 0); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to clear sched wake, ret=%d\n", - __FUNCTION__, ret)); - } -#endif /* EVENT_DATA_HOSTWAKE */ - -#ifdef UART_HB_CONFIG - dhd->wowl_alive &= ~WOWL_ALIVE_HB; - ret = dhd_wl_ioctl_set_intiovar(dhd, "wowl_alive", dhd->wowl_alive, - WLC_SET_VAR, TRUE, 0); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to disable heartbeat, ret=%d\n", - __FUNCTION__, ret)); - } -#endif /* UART_HB_CONFIG */ - - ret = dhd_wl_ioctl_set_intiovar(dhd, "dyn_dtim_skip", 0, - WLC_SET_VAR, TRUE, 0); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to disable dyn_dtim_skip, ret=%d\n", - __FUNCTION__, ret)); - } - - dhd->resume_init = FALSE; -} -#endif /* RESUME_INIT */ - -static void -dhd_postinit_ioctls(dhd_pub_t *dhd, struct net_device *dev) -{ - char buf[WLC_IOCTL_SMLEN] = {0}; - char macstr[ETHER_ADDR_STR_LEN] = {0}; - int ret = 0; - - memset(buf, 0, WLC_IOCTL_SMLEN); - ret = dhd_iovar(dhd, 0, "cur_etheraddr", NULL, 0, - (char *)buf, WLC_IOCTL_SMLEN, FALSE); - if (ret < 0) { - DHD_ERROR(("%s: get cur_etheraddr failed\n", dhd_ifname(dhd, 0))); - } else { - DHD_MAC_TO_STR(buf, macstr); - DHD_ERROR(("DEV MACADDR %s\n", macstr)); - } - -#ifdef PF_SETUP_COMMAND - /* Unblock pkt filter default forward mode after host reboot */ - /* disable default packet filter rules */ - dhd_enable_packet_filter(0, dhd); -#endif /* PF_SETUP_COMMAND */ - -#ifdef RESUME_INIT - if (dhd->resume_init) - dhd_resumeinit_ioctls(dhd, dev); -#endif -} - -#ifdef RELOAD_WIFI -void -dhd_trigger_crash(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - struct net_device *dev = dhd_idx2net(&dhd->pub, 0); - uint32 val = 0; - - if (event != DHD_WQ_RELOAD_FW) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - } - - if (!dhd) { - DHD_ERROR(("%s: dhd info not available \n", __FUNCTION__)); - return; - } - - if (!dhd->pub.up) { - DHD_ERROR(("%s: is not up\n", __FUNCTION__)); - goto done; - } - - if (dev) { - wl_state_event_sendup(wl_get_cfg(dev), ndev_to_cfgdev(dev), - NULL, EVT_RECOVER, NULL); - } - - dhd_wl_ioctl_get_intiovar(&dhd->pub, "block_list_backoff_time", - &fw_reload_new_backoff, - WLC_GET_VAR, FALSE, 0); - - if (fw_reload_new_backoff < - (FW_RELOAD_BACKOFF_UNIT_SEC * FW_RELOAD_BACKOFF_MAX_INCR_CNT)) { - fw_reload_new_backoff += FW_RELOAD_BACKOFF_UNIT_SEC; - } - - dhd_wl_ioctl_get_intiovar(&dhd->pub, "crash", &val, - WLC_GET_VAR, FALSE, 0); - -done: - return; -} - -void -dhd_schedule_reload_work(dhd_pub_t *dhdp) -{ - dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, NULL, - DHD_WQ_RELOAD_FW, - dhd_trigger_crash, - DHD_WQ_WORK_PRIORITY_HIGH); -} -#endif /* RELOAD_WIFI */ - -#ifdef WIFI_STATS -void -dhd_set_stats_id(dhd_pub_t *dhd) -{ - struct timeval time; - unsigned long local_time; - struct rtc_time tm; - wifi_fw_stats_t *wstats = &g_wstats; - - if (wstats && !wstats->id) { - do_gettimeofday(&time); - local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60)); - rtc_time_to_tm(local_time, &tm); - wstats->id = tm.tm_sec + - 100 * tm.tm_min + - 10000 * tm.tm_hour + - 1000000 * tm.tm_mday + - 100000000 * (tm.tm_mon+1); - DHD_INFO(("%s: %010d\n", __func__, wstats->id)); - } -} -#endif /* WIFI_STATS */ - -int -dhd_preinit_ioctls(dhd_pub_t *dhd) -{ - int ret = 0; - char eventmask[WL_EVENTING_MASK_LEN]; - char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ - uint32 buf_key_b4_m4 = 1; - uint8 msglen; - eventmsgs_ext_t *eventmask_msg = NULL; - char* iov_buf = NULL; - int ret2 = 0; - uint32 wnm_cap = 0; -#if defined(CUSTOM_AMPDU_BA_WSIZE) - uint32 ampdu_ba_wsize = 0; -#endif -#if defined(CUSTOM_AMPDU_MPDU) - int32 ampdu_mpdu = 0; -#endif -#if defined(CUSTOM_AMPDU_RELEASE) - int32 ampdu_release = 0; -#endif -#if defined(CUSTOM_AMSDU_AGGSF) - int32 amsdu_aggsf = 0; -#endif -#ifdef SUPPORT_SENSORHUB - shub_control_t shub_ctl; -#endif - -#if defined(BCMSDIO) || defined(BCMDBUS) -#ifdef PROP_TXSTATUS - int wlfc_enable = TRUE; -#ifndef DISABLE_11N - uint32 hostreorder = 1; - uint wl_down = 1; -#endif /* DISABLE_11N */ -#endif /* PROP_TXSTATUS */ -#endif /* BCMSDIO || BCMDBUS */ -#ifndef PCIE_FULL_DONGLE - uint32 wl_ap_isolate; -#endif /* PCIE_FULL_DONGLE */ - uint32 frameburst = CUSTOM_FRAMEBURST_SET; - uint wnm_bsstrans_resp = 0; -#ifdef SUPPORT_SET_CAC - uint32 cac = 1; -#endif /* SUPPORT_SET_CAC */ -#ifdef DHD_ENABLE_LPC - uint32 lpc = 1; -#endif /* DHD_ENABLE_LPC */ - uint power_mode = PM_FAST; -#if defined(BCMSDIO) - uint32 dongle_align = DHD_SDALIGN; - uint32 glom = CUSTOM_GLOM_SETTING; -#endif /* defined(BCMSDIO) */ -#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL) - uint32 credall = 1; -#endif - uint bcn_timeout = CUSTOM_BCN_TIMEOUT; - uint scancache_enab = TRUE; -#ifdef ENABLE_BCN_LI_BCN_WAKEUP - uint32 bcn_li_bcn = 1; -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ - uint retry_max = CUSTOM_ASSOC_RETRY_MAX; -#if defined(ARP_OFFLOAD_SUPPORT) - int arpoe = 1; -#endif - int scan_assoc_time = DHD_SCAN_ASSOC_ACTIVE_TIME; - int scan_unassoc_time = DHD_SCAN_UNASSOC_ACTIVE_TIME; - int scan_passive_time = DHD_SCAN_PASSIVE_TIME; - char buf[WLC_IOCTL_SMLEN]; - char *ptr; - uint32 listen_interval = CUSTOM_LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ -#if defined(DHD_8021X_DUMP) && defined(SHOW_LOGTRACE) - wl_el_tag_params_t *el_tag = NULL; -#endif /* DHD_8021X_DUMP */ -#ifdef ROAM_ENABLE - uint roamvar = 0; - int roam_trigger[2] = {CUSTOM_ROAM_TRIGGER_SETTING, WLC_BAND_ALL}; - int roam_scan_period[2] = {10, WLC_BAND_ALL}; - int roam_delta[2] = {CUSTOM_ROAM_DELTA_SETTING, WLC_BAND_ALL}; -#ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC - int roam_fullscan_period = 60; -#else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ - int roam_fullscan_period = 120; -#endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ -#ifdef DISABLE_BCNLOSS_ROAM - uint roam_bcnloss_off = 1; -#endif /* DISABLE_BCNLOSS_ROAM */ -#else -#ifdef DISABLE_BUILTIN_ROAM - uint roamvar = 1; -#endif /* DISABLE_BUILTIN_ROAM */ -#endif /* ROAM_ENABLE */ - -#if defined(SOFTAP) - uint dtim = 1; -#endif -#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) - struct ether_addr p2p_ea; -#endif -#ifdef SOFTAP_UAPSD_OFF - uint32 wme_apsd = 0; -#endif /* SOFTAP_UAPSD_OFF */ -#if (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC) - uint32 apsta = 1; /* Enable APSTA mode */ -#elif defined(SOFTAP_AND_GC) - uint32 apsta = 0; - int ap_mode = 1; -#endif /* (defined(AP) || defined(WLP2P)) && !defined(SOFTAP_AND_GC) */ -#ifdef GET_CUSTOM_MAC_ENABLE - struct ether_addr ea_addr; - char hw_ether[62]; -#endif /* GET_CUSTOM_MAC_ENABLE */ - -#ifdef DISABLE_11N - uint32 nmode = 0; -#endif /* DISABLE_11N */ - -#ifdef USE_WL_TXBF - uint32 txbf = 1; -#endif /* USE_WL_TXBF */ -#ifdef DISABLE_TXBFR - uint32 txbf_bfr_cap = 0; -#endif /* DISABLE_TXBFR */ -#if defined(PROP_TXSTATUS) -#ifdef USE_WFA_CERT_CONF - uint32 proptx = 0; -#endif /* USE_WFA_CERT_CONF */ -#endif /* PROP_TXSTATUS */ -#if defined(SUPPORT_5G_1024QAM_VHT) - uint32 vht_features = 0; /* init to 0, will be set based on each support */ -#endif -#ifdef DISABLE_11N_PROPRIETARY_RATES - uint32 ht_features = 0; -#endif /* DISABLE_11N_PROPRIETARY_RATES */ -#ifdef CUSTOM_PSPRETEND_THR - uint32 pspretend_thr = CUSTOM_PSPRETEND_THR; -#endif -#ifdef CUSTOM_EVENT_PM_WAKE - uint32 pm_awake_thresh = CUSTOM_EVENT_PM_WAKE; -#endif /* CUSTOM_EVENT_PM_WAKE */ - uint32 rsdb_mode = 0; -#ifdef ENABLE_TEMP_THROTTLING - wl_temp_control_t temp_control; -#endif /* ENABLE_TEMP_THROTTLING */ -#ifdef DISABLE_PRUNED_SCAN - uint32 scan_features = 0; -#endif /* DISABLE_PRUNED_SCAN */ -#ifdef HAL_API - uint32 nd_ra_filter = 0; - uint32 slaac_enable = 0; -#endif /* HAL_API */ -#ifdef PKT_FILTER_SUPPORT - dhd_pkt_filter_enable = TRUE; -#ifdef APF - dhd->apf_set = FALSE; -#endif /* APF */ -#endif /* PKT_FILTER_SUPPORT */ -#ifdef WLTDLS - dhd->tdls_enable = FALSE; - dhd_tdls_set_mode(dhd, false); -#endif /* WLTDLS */ - dhd->suspend_bcn_li_dtim = CUSTOM_SUSPEND_BCN_LI_DTIM; -#ifdef ENABLE_MAX_DTIM_IN_SUSPEND - dhd->max_dtim_enable = TRUE; -#else - dhd->max_dtim_enable = FALSE; -#endif /* ENABLE_MAX_DTIM_IN_SUSPEND */ -#ifdef CUSTOM_SET_OCLOFF - dhd->ocl_off = FALSE; -#endif /* CUSTOM_SET_OCLOFF */ - DHD_TRACE(("Enter %s\n", __FUNCTION__)); - -#ifdef DHDTCPACK_SUPPRESS - DHD_INFO(("%s: Set tcpack_sup_mode %d\n", __FUNCTION__, dhd->conf->tcpack_sup_mode)); - dhd_tcpack_suppress_set(dhd, dhd->conf->tcpack_sup_mode); -#endif - dhd->op_mode = 0; -#if defined(CUSTOM_COUNTRY_CODE) && defined(CUSTOMER_HW2) - /* clear AP flags */ - dhd->dhd_cflags &= ~WLAN_PLAT_AP_FLAG; -#endif /* CUSTOM_COUNTRY_CODE && CUSTOMER_HW2 */ - -#ifdef CUSTOMER_HW4_DEBUG - if (!dhd_validate_chipid(dhd)) { - DHD_ERROR(("%s: CONFIG_BCMXXX and CHIP ID(%x) is mismatched\n", - __FUNCTION__, dhd_bus_chip_id(dhd))); -#ifndef SUPPORT_MULTIPLE_CHIPS - ret = BCME_BADARG; - goto done; -#endif /* !SUPPORT_MULTIPLE_CHIPS */ - } -#endif /* CUSTOMER_HW4_DEBUG */ - if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) || - (op_mode == DHD_FLAG_MFG_MODE)) { - dhd->op_mode = DHD_FLAG_MFG_MODE; -#ifdef DHD_PCIE_RUNTIMEPM - /* Disable RuntimePM in mfg mode */ - DHD_DISABLE_RUNTIME_PM(dhd); - DHD_ERROR(("%s : Disable RuntimePM in Manufactring Firmware\n", __FUNCTION__)); -#endif /* DHD_PCIE_RUNTIME_PM */ - /* Check and adjust IOCTL response timeout for Manufactring firmware */ - dhd_os_set_ioctl_resp_timeout(MFG_IOCTL_RESP_TIMEOUT); - DHD_ERROR(("%s : Set IOCTL response time for Manufactring Firmware\n", - __FUNCTION__)); - } else { - dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT); - DHD_INFO(("%s : Set IOCTL response time.\n", __FUNCTION__)); - } -#ifdef GET_CUSTOM_MAC_ENABLE - ret = wifi_platform_get_mac_addr(dhd->info->adapter, hw_ether); - if (!ret) { - memset(buf, 0, sizeof(buf)); - bcopy(hw_ether, ea_addr.octet, sizeof(struct ether_addr)); - bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); - if (ret < 0) { - memset(buf, 0, sizeof(buf)); - bcm_mkiovar("hw_ether", hw_ether, sizeof(hw_ether), buf, sizeof(buf)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); - if (ret) { - int i; - DHD_ERROR(("%s: can't set MAC address MAC="MACDBG", error=%d\n", - __FUNCTION__, MAC2STRDBG(hw_ether), ret)); - for (i=0; i<sizeof(hw_ether)-ETHER_ADDR_LEN; i++) { - DHD_ERROR(("0x%02x,", hw_ether[i+ETHER_ADDR_LEN])); - if ((i+1)%8 == 0) - DHD_ERROR(("\n")); - } - ret = BCME_NOTUP; - goto done; - } - } - } else { - DHD_ERROR(("%s: can't get custom MAC address, ret=%d\n", __FUNCTION__, ret)); - ret = BCME_NOTUP; - goto done; - } -#endif /* GET_CUSTOM_MAC_ENABLE */ - if (!ETHER_ISNULLADDR(g_dev_addr.octet)) { - _dhd_set_mac_address(dhd->info, 0, g_dev_addr.octet); - } - /* Get the default device MAC address directly from firmware */ - memset(buf, 0, sizeof(buf)); - bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), - FALSE, 0)) < 0) { - DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret)); - ret = BCME_NOTUP; - goto done; - } - /* Update public MAC address after reading from Firmware */ - memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN); - - if (!dhd_chip_alive) { - if ((ret = dhd_apply_default_clm(dhd, dhd->clm_path)) < 0) { - DHD_ERROR(("%s: CLM set failed. Abort initialization.\n", __FUNCTION__)); - goto done; - } - } else { - DHD_INFO(("chip alive skip download clm\n")); - } - - /* get a capabilities from firmware */ - { - uint32 cap_buf_size = sizeof(dhd->fw_capabilities); - memset(dhd->fw_capabilities, 0, cap_buf_size); - ret = dhd_iovar(dhd, 0, "cap", NULL, 0, dhd->fw_capabilities, (cap_buf_size - 1), - FALSE); - if (ret < 0) { - DHD_ERROR(("%s: Get Capability failed (error=%d)\n", - __FUNCTION__, ret)); - return 0; - } - - memmove(&dhd->fw_capabilities[1], dhd->fw_capabilities, (cap_buf_size - 1)); - dhd->fw_capabilities[0] = ' '; - dhd->fw_capabilities[cap_buf_size - 2] = ' '; - dhd->fw_capabilities[cap_buf_size - 1] = '\0'; - } - - if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_HOSTAP_MODE) || - (op_mode == DHD_FLAG_HOSTAP_MODE)) { -#ifdef SET_RANDOM_MAC_SOFTAP - uint rand_mac; -#endif /* SET_RANDOM_MAC_SOFTAP */ - dhd->op_mode = DHD_FLAG_HOSTAP_MODE; -#if defined(ARP_OFFLOAD_SUPPORT) - arpoe = 0; -#endif -#ifdef PKT_FILTER_SUPPORT - dhd_pkt_filter_enable = FALSE; -#endif -#ifdef SET_RANDOM_MAC_SOFTAP - SRANDOM32((uint)jiffies); - rand_mac = RANDOM32(); - iovbuf[0] = (unsigned char)(vendor_oui >> 16) | 0x02; /* local admin bit */ - iovbuf[1] = (unsigned char)(vendor_oui >> 8); - iovbuf[2] = (unsigned char)vendor_oui; - iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0; - iovbuf[4] = (unsigned char)(rand_mac >> 8); - iovbuf[5] = (unsigned char)(rand_mac >> 16); - - ret = dhd_iovar(dhd, 0, "cur_etheraddr", (char *)&iovbuf, ETHER_ADDR_LEN, NULL, 0, - TRUE); - if (ret < 0) { - DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); - } else - memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); -#endif /* SET_RANDOM_MAC_SOFTAP */ -#ifdef USE_DYNAMIC_F2_BLKSIZE - dhdsdio_func_blocksize(dhd, 2, DYNAMIC_F2_BLKSIZE_FOR_NONLEGACY); -#endif /* USE_DYNAMIC_F2_BLKSIZE */ -#ifdef SUPPORT_AP_POWERSAVE - dhd_set_ap_powersave(dhd, 0, TRUE); -#endif /* SUPPORT_AP_POWERSAVE */ -#ifdef SOFTAP_UAPSD_OFF - ret = dhd_iovar(dhd, 0, "wme_apsd", (char *)&wme_apsd, sizeof(wme_apsd), NULL, 0, - TRUE); - if (ret < 0) { - DHD_ERROR(("%s: set wme_apsd 0 fail (error=%d)\n", - __FUNCTION__, ret)); - } -#endif /* SOFTAP_UAPSD_OFF */ -#if defined(CUSTOM_COUNTRY_CODE) && defined(CUSTOMER_HW2) - /* set AP flag for specific country code of SOFTAP */ - dhd->dhd_cflags |= WLAN_PLAT_AP_FLAG | WLAN_PLAT_NODFS_FLAG; -#endif /* CUSTOM_COUNTRY_CODE && CUSTOMER_HW2 */ - } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_MFG_MODE) || - (op_mode == DHD_FLAG_MFG_MODE)) { -#if defined(ARP_OFFLOAD_SUPPORT) - arpoe = 0; -#endif /* ARP_OFFLOAD_SUPPORT */ -#ifdef PKT_FILTER_SUPPORT - dhd_pkt_filter_enable = FALSE; -#endif /* PKT_FILTER_SUPPORT */ - dhd->op_mode = DHD_FLAG_MFG_MODE; -#ifdef USE_DYNAMIC_F2_BLKSIZE - dhdsdio_func_blocksize(dhd, 2, DYNAMIC_F2_BLKSIZE_FOR_NONLEGACY); -#endif /* USE_DYNAMIC_F2_BLKSIZE */ - if (FW_SUPPORTED(dhd, rsdb)) { - rsdb_mode = 0; - ret = dhd_iovar(dhd, 0, "rsdb_mode", (char *)&rsdb_mode, sizeof(rsdb_mode), - NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Disable rsdb_mode is failed ret= %d\n", - __FUNCTION__, ret)); - } - } - } else { - uint32 concurrent_mode = 0; - if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_P2P_MODE) || - (op_mode == DHD_FLAG_P2P_MODE)) { -#if defined(ARP_OFFLOAD_SUPPORT) - arpoe = 0; -#endif -#ifdef PKT_FILTER_SUPPORT - dhd_pkt_filter_enable = FALSE; -#endif - dhd->op_mode = DHD_FLAG_P2P_MODE; - } else if ((!op_mode && dhd_get_fw_mode(dhd->info) == DHD_FLAG_IBSS_MODE) || - (op_mode == DHD_FLAG_IBSS_MODE)) { - dhd->op_mode = DHD_FLAG_IBSS_MODE; - } else - dhd->op_mode = DHD_FLAG_STA_MODE; -#if !defined(AP) && defined(WLP2P) - if (dhd->op_mode != DHD_FLAG_IBSS_MODE && - (concurrent_mode = dhd_get_concurrent_capabilites(dhd))) { -#if defined(ARP_OFFLOAD_SUPPORT) - arpoe = 1; -#endif - dhd->op_mode |= concurrent_mode; - } - - /* Check if we are enabling p2p */ - if (dhd->op_mode & DHD_FLAG_P2P_MODE) { - ret = dhd_iovar(dhd, 0, "apsta", (char *)&apsta, sizeof(apsta), NULL, 0, - TRUE); - if (ret < 0) - DHD_ERROR(("%s APSTA for P2P failed ret= %d\n", __FUNCTION__, ret)); - -#if defined(SOFTAP_AND_GC) - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_AP, - (char *)&ap_mode, sizeof(ap_mode), TRUE, 0)) < 0) { - DHD_ERROR(("%s WLC_SET_AP failed %d\n", __FUNCTION__, ret)); - } -#endif - memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN); - ETHER_SET_LOCALADDR(&p2p_ea); - ret = dhd_iovar(dhd, 0, "p2p_da_override", (char *)&p2p_ea, sizeof(p2p_ea), - NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s p2p_da_override ret= %d\n", __FUNCTION__, ret)); - else - DHD_INFO(("dhd_preinit_ioctls: p2p_da_override succeeded\n")); - } -#else - (void)concurrent_mode; -#endif - } -#ifdef BCMSDIO - if (dhd->conf->sd_f2_blocksize) - dhdsdio_func_blocksize(dhd, 2, dhd->conf->sd_f2_blocksize); -#endif - -#if defined(RSDB_MODE_FROM_FILE) - (void)dhd_rsdb_mode_from_file(dhd); -#endif - -#ifdef DISABLE_PRUNED_SCAN - if (FW_SUPPORTED(dhd, rsdb)) { - ret = dhd_iovar(dhd, 0, "scan_features", (char *)&scan_features, - sizeof(scan_features), iovbuf, sizeof(iovbuf), FALSE); - if (ret < 0) { - DHD_ERROR(("%s get scan_features is failed ret=%d\n", - __FUNCTION__, ret)); - } else { - memcpy(&scan_features, iovbuf, 4); - scan_features &= ~RSDB_SCAN_DOWNGRADED_CH_PRUNE_ROAM; - ret = dhd_iovar(dhd, 0, "scan_features", (char *)&scan_features, - sizeof(scan_features), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s set scan_features is failed ret=%d\n", - __FUNCTION__, ret)); - } - } - } -#endif /* DISABLE_PRUNED_SCAN */ - - DHD_INFO(("Firmware up: op_mode=0x%04x, MAC="MACDBG"\n", - dhd->op_mode, MAC2STRDBG(dhd->mac.octet))); -#ifdef CUSTOMER_HW2 -#if defined(DHD_BLOB_EXISTENCE_CHECK) - if (!dhd->pub.is_blob) -#endif /* DHD_BLOB_EXISTENCE_CHECK */ - { - /* get a ccode and revision for the country code */ -#if defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) - get_customized_country_code(dhd->info->adapter, dhd->dhd_cspec.country_abbrev, - &dhd->dhd_cspec, dhd->dhd_cflags); -#else - get_customized_country_code(dhd->info->adapter, dhd->dhd_cspec.country_abbrev, - &dhd->dhd_cspec); -#endif /* defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) */ - } -#endif /* CUSTOMER_HW2 */ - -#if defined(RXFRAME_THREAD) && defined(RXTHREAD_ONLYSTA) - if (dhd->op_mode == DHD_FLAG_HOSTAP_MODE) - dhd->info->rxthread_enabled = FALSE; - else - dhd->info->rxthread_enabled = TRUE; -#endif - /* Set Country code */ - if (dhd->dhd_cspec.ccode[0] != 0) { - ret = dhd_iovar(dhd, 0, "country", (char *)&dhd->dhd_cspec, sizeof(wl_country_t), - NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__)); - } - - /* Set Listen Interval */ - ret = dhd_iovar(dhd, 0, "assoc_listen", (char *)&listen_interval, sizeof(listen_interval), - NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret)); - -#if defined(ROAM_ENABLE) || defined(DISABLE_BUILTIN_ROAM) -#ifdef USE_WFA_CERT_CONF - if (sec_get_param_wfa_cert(dhd, SET_PARAM_ROAMOFF, &roamvar) == BCME_OK) { - DHD_ERROR(("%s: read roam_off param =%d\n", __FUNCTION__, roamvar)); - } -#endif /* USE_WFA_CERT_CONF */ - /* Disable built-in roaming to allowed ext supplicant to take care of roaming */ - dhd_iovar(dhd, 0, "roam_off", (char *)&roamvar, sizeof(roamvar), NULL, 0, TRUE); -#endif /* ROAM_ENABLE || DISABLE_BUILTIN_ROAM */ -#if defined(ROAM_ENABLE) -#ifdef DISABLE_BCNLOSS_ROAM - dhd_iovar(dhd, 0, "roam_bcnloss_off", (char *)&roam_bcnloss_off, sizeof(roam_bcnloss_off), - NULL, 0, TRUE); -#endif /* DISABLE_BCNLOSS_ROAM */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger, - sizeof(roam_trigger), TRUE, 0)) < 0) - DHD_ERROR(("%s: roam trigger set failed %d\n", __FUNCTION__, ret)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period, - sizeof(roam_scan_period), TRUE, 0)) < 0) - DHD_ERROR(("%s: roam scan period set failed %d\n", __FUNCTION__, ret)); - if ((dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta, - sizeof(roam_delta), TRUE, 0)) < 0) - DHD_ERROR(("%s: roam delta set failed %d\n", __FUNCTION__, ret)); - ret = dhd_iovar(dhd, 0, "fullroamperiod", (char *)&roam_fullscan_period, - sizeof(roam_fullscan_period), NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s: roam fullscan period set failed %d\n", __FUNCTION__, ret)); -#endif /* ROAM_ENABLE */ - -#ifdef CUSTOM_EVENT_PM_WAKE - ret = dhd_iovar(dhd, 0, "const_awake_thresh", (char *)&pm_awake_thresh, - sizeof(pm_awake_thresh), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s set const_awake_thresh failed %d\n", __FUNCTION__, ret)); - } -#endif /* CUSTOM_EVENT_PM_WAKE */ -#ifdef WLTDLS -#ifdef ENABLE_TDLS_AUTO_MODE - /* by default TDLS on and auto mode on */ - _dhd_tdls_enable(dhd, true, true, NULL); -#else - /* by default TDLS on and auto mode off */ - _dhd_tdls_enable(dhd, true, false, NULL); -#endif /* ENABLE_TDLS_AUTO_MODE */ -#endif /* WLTDLS */ - -#ifdef DHD_ENABLE_LPC - /* Set lpc 1 */ - ret = dhd_iovar(dhd, 0, "lpc", (char *)&lpc, sizeof(lpc), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set lpc failed %d\n", __FUNCTION__, ret)); - - if (ret == BCME_NOTDOWN) { - uint wl_down = 1; - ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, - (char *)&wl_down, sizeof(wl_down), TRUE, 0); - DHD_ERROR(("%s lpc fail WL_DOWN : %d, lpc = %d\n", __FUNCTION__, ret, lpc)); - - ret = dhd_iovar(dhd, 0, "lpc", (char *)&lpc, sizeof(lpc), NULL, 0, TRUE); - DHD_ERROR(("%s Set lpc ret --> %d\n", __FUNCTION__, ret)); - } - } -#endif /* DHD_ENABLE_LPC */ - -#ifdef WLADPS -#ifdef WLADPS_SEAK_AP_WAR - dhd->disabled_adps = FALSE; -#endif /* WLADPS_SEAK_AP_WAR */ - if (dhd->op_mode & DHD_FLAG_STA_MODE) { -#ifdef ADPS_MODE_FROM_FILE - dhd_adps_mode_from_file(dhd); -#else - if ((ret = dhd_enable_adps(dhd, ADPS_ENABLE)) != BCME_OK) { - DHD_ERROR(("%s dhd_enable_adps failed %d\n", - __FUNCTION__, ret)); - } -#endif /* ADPS_MODE_FROM_FILE */ - } -#endif /* WLADPS */ - - /* Set PowerSave mode */ - (void) dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); - -#if defined(BCMSDIO) - /* Match Host and Dongle rx alignment */ - dhd_iovar(dhd, 0, "bus:txglomalign", (char *)&dongle_align, sizeof(dongle_align), - NULL, 0, TRUE); - -#if defined(CUSTOMER_HW2) && defined(USE_WL_CREDALL) - /* enable credall to reduce the chance of no bus credit happened. */ - dhd_iovar(dhd, 0, "bus:credall", (char *)&credall, sizeof(credall), NULL, 0, TRUE); -#endif - -#ifdef USE_WFA_CERT_CONF - if (sec_get_param_wfa_cert(dhd, SET_PARAM_BUS_TXGLOM_MODE, &glom) == BCME_OK) { - DHD_ERROR(("%s, read txglom param =%d\n", __FUNCTION__, glom)); - } -#endif /* USE_WFA_CERT_CONF */ - if (glom != DEFAULT_GLOM_VALUE) { - DHD_INFO(("%s set glom=0x%X\n", __FUNCTION__, glom)); - dhd_iovar(dhd, 0, "bus:txglom", (char *)&glom, sizeof(glom), NULL, 0, TRUE); - } -#endif /* defined(BCMSDIO) */ - - /* Setup timeout if Beacons are lost and roam is off to report link down */ - dhd_iovar(dhd, 0, "bcn_timeout", (char *)&bcn_timeout, sizeof(bcn_timeout), NULL, 0, TRUE); - - /* Setup assoc_retry_max count to reconnect target AP in dongle */ - dhd_iovar(dhd, 0, "assoc_retry_max", (char *)&retry_max, sizeof(retry_max), NULL, 0, TRUE); - -#if defined(AP) && !defined(WLP2P) - dhd_iovar(dhd, 0, "apsta", (char *)&apsta, sizeof(apsta), NULL, 0, TRUE); - -#endif /* defined(AP) && !defined(WLP2P) */ - -#ifdef MIMO_ANT_SETTING - dhd_sel_ant_from_file(dhd); -#endif /* MIMO_ANT_SETTING */ - -#if defined(SOFTAP) - if (ap_fw_loaded == TRUE) { - dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0); - } -#endif - -#if defined(KEEP_ALIVE) - { - /* Set Keep Alive : be sure to use FW with -keepalive */ - int res; - -#if defined(SOFTAP) - if (ap_fw_loaded == FALSE) -#endif - if (!(dhd->op_mode & - (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_MFG_MODE))) { - if ((res = dhd_keep_alive_onoff(dhd)) < 0) - DHD_ERROR(("%s set keeplive failed %d\n", - __FUNCTION__, res)); - } - } -#endif /* defined(KEEP_ALIVE) */ - -#ifdef USE_WL_TXBF - ret = dhd_iovar(dhd, 0, "txbf", (char *)&txbf, sizeof(txbf), NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s Set txbf failed %d\n", __FUNCTION__, ret)); - -#endif /* USE_WL_TXBF */ - - ret = dhd_iovar(dhd, 0, "scancache", (char *)&scancache_enab, sizeof(scancache_enab), NULL, - 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set scancache failed %d\n", __FUNCTION__, ret)); - } - -#ifdef DISABLE_TXBFR - ret = dhd_iovar(dhd, 0, "txbf_bfr_cap", (char *)&txbf_bfr_cap, sizeof(txbf_bfr_cap), NULL, - 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Clear txbf_bfr_cap failed %d\n", __FUNCTION__, ret)); - } -#endif /* DISABLE_TXBFR */ - -#ifdef USE_WFA_CERT_CONF -#ifdef USE_WL_FRAMEBURST - if (sec_get_param_wfa_cert(dhd, SET_PARAM_FRAMEBURST, &frameburst) == BCME_OK) { - DHD_ERROR(("%s, read frameburst param=%d\n", __FUNCTION__, frameburst)); - } -#endif /* USE_WL_FRAMEBURST */ -#ifdef DISABLE_FRAMEBURST_VSDB - g_frameburst = frameburst; -#endif /* DISABLE_FRAMEBURST_VSDB */ -#endif /* USE_WFA_CERT_CONF */ -#ifdef DISABLE_WL_FRAMEBURST_SOFTAP - /* Disable Framebursting for SofAP */ - if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) { - frameburst = 0; - } -#endif /* DISABLE_WL_FRAMEBURST_SOFTAP */ - /* Set frameburst to value */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_FAKEFRAG, (char *)&frameburst, - sizeof(frameburst), TRUE, 0)) < 0) { - DHD_INFO(("%s frameburst not supported %d\n", __FUNCTION__, ret)); - } - - iov_buf = (char*)kmalloc(WLC_IOCTL_SMLEN, GFP_KERNEL); - if (iov_buf == NULL) { - DHD_ERROR(("failed to allocate %d bytes for iov_buf\n", WLC_IOCTL_SMLEN)); - ret = BCME_NOMEM; - goto done; - } - - -#if defined(CUSTOM_AMPDU_BA_WSIZE) - /* Set ampdu ba wsize to 64 or 16 */ -#ifdef CUSTOM_AMPDU_BA_WSIZE - ampdu_ba_wsize = CUSTOM_AMPDU_BA_WSIZE; -#endif - if (ampdu_ba_wsize != 0) { - ret = dhd_iovar(dhd, 0, "ampdu_ba_wsize", (char *)&du_ba_wsize, - sizeof(ampdu_ba_wsize), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set ampdu_ba_wsize to %d failed %d\n", - __FUNCTION__, ampdu_ba_wsize, ret)); - } - } -#endif - -#ifdef ENABLE_TEMP_THROTTLING - if (dhd->op_mode & DHD_FLAG_STA_MODE) { - memset(&temp_control, 0, sizeof(temp_control)); - temp_control.enable = 1; - temp_control.control_bit = TEMP_THROTTLE_CONTROL_BIT; - ret = dhd_iovar(dhd, 0, "temp_throttle_control", (char *)&temp_control, - sizeof(temp_control), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set temp_throttle_control to %d failed \n", - __FUNCTION__, ret)); - } - } -#endif /* ENABLE_TEMP_THROTTLING */ - -#if defined(CUSTOM_AMPDU_MPDU) - ampdu_mpdu = CUSTOM_AMPDU_MPDU; - if (ampdu_mpdu != 0 && (ampdu_mpdu <= ampdu_ba_wsize)) { - ret = dhd_iovar(dhd, 0, "ampdu_mpdu", (char *)&du_mpdu, sizeof(ampdu_mpdu), - NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set ampdu_mpdu to %d failed %d\n", - __FUNCTION__, CUSTOM_AMPDU_MPDU, ret)); - } - } -#endif /* CUSTOM_AMPDU_MPDU */ - -#if defined(CUSTOM_AMPDU_RELEASE) - ampdu_release = CUSTOM_AMPDU_RELEASE; - if (ampdu_release != 0 && (ampdu_release <= ampdu_ba_wsize)) { - ret = dhd_iovar(dhd, 0, "ampdu_release", (char *)&du_release, - sizeof(ampdu_release), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set ampdu_release to %d failed %d\n", - __FUNCTION__, CUSTOM_AMPDU_RELEASE, ret)); - } - } -#endif /* CUSTOM_AMPDU_RELEASE */ - -#if defined(CUSTOM_AMSDU_AGGSF) - amsdu_aggsf = CUSTOM_AMSDU_AGGSF; - if (amsdu_aggsf != 0) { - ret = dhd_iovar(dhd, 0, "amsdu_aggsf", (char *)&amsdu_aggsf, sizeof(amsdu_aggsf), - NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set amsdu_aggsf to %d failed %d\n", - __FUNCTION__, CUSTOM_AMSDU_AGGSF, ret)); - } - } -#endif /* CUSTOM_AMSDU_AGGSF */ - -#if defined(SUPPORT_5G_1024QAM_VHT) -#ifdef SUPPORT_5G_1024QAM_VHT - if (dhd_get_chipid(dhd) == BCM4361_CHIP_ID) { - vht_features |= 0x6; /* 5G 1024 QAM support */ - } -#endif /* SUPPORT_5G_1024QAM_VHT */ - if (vht_features) { - ret = dhd_iovar(dhd, 0, "vht_features", (char *)&vht_features, sizeof(vht_features), - NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s vht_features set failed %d\n", __FUNCTION__, ret)); - - if (ret == BCME_NOTDOWN) { - uint wl_down = 1; - ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, - (char *)&wl_down, sizeof(wl_down), TRUE, 0); - DHD_ERROR(("%s vht_features fail WL_DOWN : %d," - " vht_features = 0x%x\n", - __FUNCTION__, ret, vht_features)); - - ret = dhd_iovar(dhd, 0, "vht_features", (char *)&vht_features, - sizeof(vht_features), NULL, 0, TRUE); - DHD_ERROR(("%s vht_features set. ret --> %d\n", __FUNCTION__, ret)); - } - } - } -#endif -#ifdef DISABLE_11N_PROPRIETARY_RATES - ret = dhd_iovar(dhd, 0, "ht_features", (char *)&ht_features, sizeof(ht_features), NULL, 0, - TRUE); - if (ret < 0) { - DHD_ERROR(("%s ht_features set failed %d\n", __FUNCTION__, ret)); - } -#endif /* DISABLE_11N_PROPRIETARY_RATES */ -#ifdef CUSTOM_PSPRETEND_THR - /* Turn off MPC in AP mode */ - ret = dhd_iovar(dhd, 0, "pspretend_threshold", (char *)&pspretend_thr, - sizeof(pspretend_thr), NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s pspretend_threshold for HostAPD failed %d\n", - __FUNCTION__, ret)); - } -#endif - - ret = dhd_iovar(dhd, 0, "buf_key_b4_m4", (char *)&buf_key_b4_m4, sizeof(buf_key_b4_m4), - NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s buf_key_b4_m4 set failed %d\n", __FUNCTION__, ret)); - } -#ifdef SUPPORT_SET_CAC - bcm_mkiovar("cac", (char *)&cac, sizeof(cac), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s Failed to set cac to %d, %d\n", __FUNCTION__, cac, ret)); - } -#endif /* SUPPORT_SET_CAC */ -#ifdef DHD_ULP - /* Get the required details from dongle during preinit ioctl */ - dhd_ulp_preinit(dhd); -#endif /* DHD_ULP */ - - /* Read event_msgs mask */ - ret = dhd_iovar(dhd, 0, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, - sizeof(iovbuf), FALSE); - if (ret < 0) { - DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret)); - goto done; - } - bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); - - /* Setup event_msgs */ - setbit(eventmask, WLC_E_SET_SSID); - setbit(eventmask, WLC_E_PRUNE); - setbit(eventmask, WLC_E_AUTH); - setbit(eventmask, WLC_E_AUTH_IND); - setbit(eventmask, WLC_E_ASSOC); - setbit(eventmask, WLC_E_REASSOC); - setbit(eventmask, WLC_E_REASSOC_IND); - if (!(dhd->op_mode & DHD_FLAG_IBSS_MODE)) - setbit(eventmask, WLC_E_DEAUTH); - setbit(eventmask, WLC_E_DEAUTH_IND); - setbit(eventmask, WLC_E_DISASSOC_IND); - setbit(eventmask, WLC_E_DISASSOC); - setbit(eventmask, WLC_E_JOIN); - setbit(eventmask, WLC_E_BSSID); - setbit(eventmask, WLC_E_START); - setbit(eventmask, WLC_E_ASSOC_IND); - setbit(eventmask, WLC_E_PSK_SUP); - setbit(eventmask, WLC_E_LINK); - setbit(eventmask, WLC_E_MIC_ERROR); - setbit(eventmask, WLC_E_ASSOC_REQ_IE); - setbit(eventmask, WLC_E_ASSOC_RESP_IE); -#ifdef LIMIT_BORROW - setbit(eventmask, WLC_E_ALLOW_CREDIT_BORROW); -#endif -#ifdef EVENT_DATA_HOSTWAKE - setbit(eventmask, WLC_E_HOSTWAKE); -#endif /* EVENT_DATA_HOSTWAKE */ -#ifndef WL_CFG80211 - setbit(eventmask, WLC_E_PMKID_CACHE); - setbit(eventmask, WLC_E_TXFAIL); -#endif - setbit(eventmask, WLC_E_JOIN_START); -// setbit(eventmask, WLC_E_SCAN_COMPLETE); // terence 20150628: remove redundant event -#ifdef DHD_DEBUG - setbit(eventmask, WLC_E_SCAN_CONFIRM_IND); -#endif -#ifdef WLMEDIA_HTSF - setbit(eventmask, WLC_E_HTSFSYNC); -#endif /* WLMEDIA_HTSF */ -#ifdef PNO_SUPPORT - //setbit(eventmask, WLC_E_PFN_NET_FOUND); - //setbit(eventmask, WLC_E_PFN_BEST_BATCHING); - //setbit(eventmask, WLC_E_PFN_BSSID_NET_FOUND); - //setbit(eventmask, WLC_E_PFN_BSSID_NET_LOST); -#endif /* PNO_SUPPORT */ - /* enable dongle roaming event */ - setbit(eventmask, WLC_E_ROAM); -#ifdef WLTDLS - setbit(eventmask, WLC_E_TDLS_PEER_EVENT); -#endif /* WLTDLS */ -#ifdef WL_ESCAN - setbit(eventmask, WLC_E_ESCAN_RESULT); -#endif /* WL_ESCAN */ -#ifdef RTT_SUPPORT - setbit(eventmask, WLC_E_PROXD); -#endif /* RTT_SUPPORT */ -#ifdef IDSUP_STATS - setbit(eventmask, WLC_E_COUNTRY_CODE_CHANGED); - setbit(eventmask, WLC_E_WPA_STATE); - setbit(eventmask, WLC_E_SLAAC_INFO); -#endif /* IDSUP_STATS */ -#ifdef RELOAD_WIFI - setbit(eventmask, WLC_E_RELOAD); -#endif /* RELOAD_WIFI */ -#ifdef WL_CFG80211 - setbit(eventmask, WLC_E_ESCAN_RESULT); - setbit(eventmask, WLC_E_AP_STARTED); - setbit(eventmask, WLC_E_ACTION_FRAME_RX); - //if (dhd->op_mode & DHD_FLAG_P2P_MODE) { - // setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE); - //} -#endif /* WL_CFG80211 */ - -#if defined(SHOW_LOGTRACE) && defined(LOGTRACE_FROM_FILE) - if (dhd_logtrace_from_file(dhd)) { - setbit(eventmask, WLC_E_TRACE); - } else { - clrbit(eventmask, WLC_E_TRACE); - } -#elif defined(SHOW_LOGTRACE) - setbit(eventmask, WLC_E_TRACE); -#else - clrbit(eventmask, WLC_E_TRACE); -#endif /* defined(SHOW_LOGTRACE) && defined(LOGTRACE_FROM_FILE) */ - - setbit(eventmask, WLC_E_CSA_COMPLETE_IND); -#ifdef DHD_WMF - setbit(eventmask, WLC_E_PSTA_PRIMARY_INTF_IND); -#endif -#ifdef CUSTOM_EVENT_PM_WAKE - setbit(eventmask, WLC_E_EXCESS_PM_WAKE_EVENT); -#endif /* CUSTOM_EVENT_PM_WAKE */ -#ifdef DHD_LOSSLESS_ROAMING - setbit(eventmask, WLC_E_ROAM_PREP); -#endif -#ifdef IDSUP_STATS - setbit(eventmask, WLC_E_ROAM_START); - setbit(eventmask, WLC_E_RECOVER); -#endif /* IDSUP_STATS */ -#ifdef ONLINECHK_SUPPORT - setbit(eventmask, WLC_E_ONLINE_CHK_HOSTWAKE); -#endif /* ONLINECHK_SUPPORT */ -#if defined(PCIE_FULL_DONGLE) && defined(DHD_LOSSLESS_ROAMING) - dhd_update_flow_prio_map(dhd, DHD_FLOW_PRIO_LLR_MAP); -#endif /* defined(PCIE_FULL_DONGLE) && defined(DHD_LOSSLESS_ROAMING) */ - -#if defined(BCMPCIE) && defined(EAPOL_PKT_PRIO) - dhd_update_flow_prio_map(dhd, DHD_FLOW_PRIO_LLR_MAP); -#endif /* defined(BCMPCIE) && defined(EAPOL_PKT_PRIO) */ - -#ifdef SUSPEND_EVENT - bcopy(eventmask, dhd->conf->resume_eventmask, WL_EVENTING_MASK_LEN); -#endif - /* Write updated Event mask */ - ret = dhd_iovar(dhd, 0, "event_msgs", eventmask, WL_EVENTING_MASK_LEN, NULL, 0, TRUE); - if (ret < 0) { - DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret)); - goto done; - } - - /* make up event mask ext message iovar for event larger than 128 */ - msglen = ROUNDUP(WLC_E_LAST, NBBY)/NBBY + EVENTMSGS_EXT_STRUCT_SIZE; - eventmask_msg = (eventmsgs_ext_t*)kmalloc(msglen, GFP_KERNEL); - if (eventmask_msg == NULL) { - DHD_ERROR(("failed to allocate %d bytes for event_msg_ext\n", msglen)); - ret = BCME_NOMEM; - goto done; - } - bzero(eventmask_msg, msglen); - eventmask_msg->ver = EVENTMSGS_VER; - eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY; - - /* Read event_msgs_ext mask */ - ret2 = dhd_iovar(dhd, 0, "event_msgs_ext", (char *)eventmask_msg, msglen, iov_buf, - WLC_IOCTL_SMLEN, FALSE); - - if (ret2 == 0) { /* event_msgs_ext must be supported */ - bcopy(iov_buf, eventmask_msg, msglen); -#ifdef RSSI_MONITOR_SUPPORT - setbit(eventmask_msg->mask, WLC_E_RSSI_LQM); -#endif /* RSSI_MONITOR_SUPPORT */ -#ifdef GSCAN_SUPPORT - setbit(eventmask_msg->mask, WLC_E_PFN_GSCAN_FULL_RESULT); - setbit(eventmask_msg->mask, WLC_E_PFN_SCAN_COMPLETE); - setbit(eventmask_msg->mask, WLC_E_PFN_SSID_EXT); - setbit(eventmask_msg->mask, WLC_E_ROAM_EXP_EVENT); -#endif /* GSCAN_SUPPORT */ - //setbit(eventmask_msg->mask, WLC_E_RSSI_LQM); -#ifdef BT_WIFI_HANDOVER - setbit(eventmask_msg->mask, WLC_E_BT_WIFI_HANDOVER_REQ); -#endif /* BT_WIFI_HANDOVER */ -#ifdef DBG_PKT_MON - setbit(eventmask_msg->mask, WLC_E_ROAM_PREP); -#endif /* DBG_PKT_MON */ -#ifdef DHD_ULP - setbit(eventmask_msg->mask, WLC_E_ULP); -#endif -#ifdef ENABLE_TEMP_THROTTLING - setbit(eventmask_msg->mask, WLC_E_TEMP_THROTTLE); -#endif /* ENABLE_TEMP_THROTTLING */ -#if defined(PKT_FILTER_SUPPORT) && defined(PF_HOSTWAKE) - setbit(eventmask_msg->mask, WLC_E_PKT_FILTER); -#endif /* defined(PKT_FILTER_SUPPORT) && defined(PF_HOSTWAKE) */ -#ifdef DHCPC_SUPPORT - setbit(eventmask_msg->mask, WLC_E_DHCPC_EVENT); -#endif /* DHCPC_SUPPORT */ -#ifdef IDSUP_STATS - setbit(eventmask_msg->mask, WLC_E_ID_AUTH); - setbit(eventmask_msg->mask, WLC_E_BSSTRANS); -#endif /* IDSUP_STATS */ -#ifdef HAL_API - setbit(eventmask_msg->mask, WLC_E_TIMEOUT_EXHAUSTED); -#endif /* HAL_API */ -#ifdef ONLINECHK_SUPPORT - setbit(eventmask_msg->mask, WLC_E_ONLINE_CHK_EVENT); -#endif /* ONLINECHK_SUPPORT */ -#ifdef BCOL_TCPKA_SYNC - setbit(eventmask_msg->mask, WLC_E_TKO); -#endif /* BCOL_TCPKA_SYNC */ - - /* Write updated Event mask */ - eventmask_msg->ver = EVENTMSGS_VER; - eventmask_msg->command = EVENTMSGS_SET_MASK; - eventmask_msg->len = ROUNDUP(WLC_E_LAST, NBBY)/NBBY; - ret = dhd_iovar(dhd, 0, "event_msgs_ext", (char *)eventmask_msg, msglen, NULL, 0, - TRUE); - if (ret < 0) { - DHD_ERROR(("%s write event mask ext failed %d\n", __FUNCTION__, ret)); - goto done; - } - } else if (ret2 == BCME_UNSUPPORTED || ret2 == BCME_VERSION) { - /* Skip for BCME_UNSUPPORTED or BCME_VERSION */ - DHD_ERROR(("%s event_msgs_ext not support or version mismatch %d\n", - __FUNCTION__, ret2)); - } else { - DHD_ERROR(("%s read event mask ext failed %d\n", __FUNCTION__, ret2)); - ret = ret2; - goto done; - } - -#if defined(DHD_8021X_DUMP) && defined(SHOW_LOGTRACE) - /* Enabling event log trace for EAP events */ - el_tag = (wl_el_tag_params_t *)kmalloc(sizeof(wl_el_tag_params_t), GFP_KERNEL); - if (el_tag == NULL) { - DHD_ERROR(("failed to allocate %d bytes for event_msg_ext\n", - (int)sizeof(wl_el_tag_params_t))); - ret = BCME_NOMEM; - goto done; - } - el_tag->tag = EVENT_LOG_TAG_4WAYHANDSHAKE; - el_tag->set = 1; - el_tag->flags = EVENT_LOG_TAG_FLAG_LOG; - bcm_mkiovar("event_log_tag_control", (char *)el_tag, - sizeof(*el_tag), iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* DHD_8021X_DUMP */ - - dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time, - sizeof(scan_assoc_time), TRUE, 0); - dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, - sizeof(scan_unassoc_time), TRUE, 0); - dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time, - sizeof(scan_passive_time), TRUE, 0); - -#ifdef ARP_OFFLOAD_SUPPORT - /* Set and enable ARP offload feature for STA only */ -#if defined(SOFTAP) - if (arpoe && !ap_fw_loaded) -#else - if (arpoe) -#endif - { - dhd_arp_offload_enable(dhd, TRUE); - dhd_arp_offload_set(dhd, dhd_arp_mode); - } else { - dhd_arp_offload_enable(dhd, FALSE); - dhd_arp_offload_set(dhd, 0); - } - dhd_arp_enable = arpoe; -#endif /* ARP_OFFLOAD_SUPPORT */ - -#ifdef PKT_FILTER_SUPPORT -#ifdef PF_SETUP_COMMAND - dhd->pktfilter_count_ext = 0; -#endif /* PF_SETUP_COMMAND */ - /* Setup default defintions for pktfilter , enable in suspend */ - if (dhd_master_mode) { - dhd->pktfilter_count = 6; - dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = NULL; -#ifdef PF_SETUP_COMMAND - dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL; - dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; -#else - if (!FW_SUPPORTED(dhd, pf6)) { - dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = NULL; - dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; - } else { - /* Immediately pkt filter TYPE 6 Discard IPv4/IPv6 Multicast Packet */ - dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = DISCARD_IPV4_MCAST; - dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = DISCARD_IPV6_MCAST; - } -#endif /* PF_SETUP_COMMAND */ - -#ifdef PF_SETUP_COMMAND - /* apply APP pktfilter */ - dhd->pktfilter[DHD_ARP_FILTER_NUM] = NULL; - - /* Setup filter to allow only unicast */ - dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = NULL; -#else - /* apply APP pktfilter */ - dhd->pktfilter[DHD_ARP_FILTER_NUM] = "105 0 0 12 0xFFFF 0x0806"; - - /* Setup filter to allow only unicast */ - dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0x01 0x00"; -#endif /* PF_SETUP_COMMAND */ - - /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */ - dhd->pktfilter[DHD_MDNS_FILTER_NUM] = NULL; - - dhd->pktfilter[DHD_BROADCAST_ARP_FILTER_NUM] = NULL; -#ifndef PF_SETUP_COMMAND - if (FW_SUPPORTED(dhd, pf6)) { - /* Immediately pkt filter TYPE 6 Dicard Broadcast IP packet */ - dhd->pktfilter[DHD_IP4BCAST_DROP_FILTER_NUM] = - "107 1 6 IP4_H:16 0xf0 !0xe0 IP4_H:19 0xff 0xff"; - dhd->pktfilter_count = 8; - } -#endif /* PF_SETUP_COMMAND */ - -#ifdef GAN_LITE_NAT_KEEPALIVE_FILTER - dhd->pktfilter_count = 4; - /* Setup filter to block broadcast and NAT Keepalive packets */ - /* discard all broadcast packets */ - dhd->pktfilter[DHD_UNICAST_FILTER_NUM] = "100 0 0 0 0xffffff 0xffffff"; - /* discard NAT Keepalive packets */ - dhd->pktfilter[DHD_BROADCAST_FILTER_NUM] = "102 0 0 36 0xffffffff 0x11940009"; - /* discard NAT Keepalive packets */ - dhd->pktfilter[DHD_MULTICAST4_FILTER_NUM] = "104 0 0 38 0xffffffff 0x11940009"; - dhd->pktfilter[DHD_MULTICAST6_FILTER_NUM] = NULL; -#endif /* GAN_LITE_NAT_KEEPALIVE_FILTER */ - } else - dhd_conf_discard_pkt_filter(dhd); -#ifndef PF_SETUP_COMMAND - dhd_conf_add_pkt_filter(dhd); -#endif /* PF_SETUP_COMMAND */ - -#if defined(SOFTAP) - if (ap_fw_loaded) { - dhd_enable_packet_filter(0, dhd); - } -#endif /* defined(SOFTAP) */ - dhd_set_packet_filter(dhd); -#endif /* PKT_FILTER_SUPPORT */ -#ifdef DISABLE_11N - ret = dhd_iovar(dhd, 0, "nmode", (char *)&nmode, sizeof(nmode), NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s wl nmode 0 failed %d\n", __FUNCTION__, ret)); -#endif /* DISABLE_11N */ - -#ifdef ENABLE_BCN_LI_BCN_WAKEUP - dhd_iovar(dhd, 0, "bcn_li_bcn", (char *)&bcn_li_bcn, sizeof(bcn_li_bcn), NULL, 0, TRUE); -#endif /* ENABLE_BCN_LI_BCN_WAKEUP */ - /* query for 'clmver' to get clm version info from firmware */ - memset(buf, 0, sizeof(buf)); - ret = dhd_iovar(dhd, 0, "clmver", NULL, 0, buf, sizeof(buf), FALSE); - if (ret < 0) - DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret)); - else { - char *clmver_temp_buf = NULL; - - if ((clmver_temp_buf = bcmstrstr(buf, "Customization:")) == NULL) { - DHD_ERROR(("Couldn't find \"Data:\"\n")); - } else { - ptr = (clmver_temp_buf + strlen("Customization:")); - if ((clmver_temp_buf = bcmstrtok(&ptr, "\n", 0)) == NULL) { - DHD_ERROR(("Couldn't find New line character\n")); - } else { - memset(clm_version, 0, CLM_VER_STR_LEN); - strncpy(clm_version, clmver_temp_buf, - MIN(strlen(clmver_temp_buf), CLM_VER_STR_LEN - 1)); - } - } - } - - /* query for 'ver' to get version info from firmware */ - memset(buf, 0, sizeof(buf)); - ptr = buf; - ret = dhd_iovar(dhd, 0, "ver", NULL, 0, (char *)&buf, sizeof(buf), FALSE); - if (ret < 0) - DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret)); - else { - bcmstrtok(&ptr, "\n", 0); - strncpy(fw_version, buf, FW_VER_STR_LEN); - fw_version[FW_VER_STR_LEN-1] = '\0'; - dhd_set_version_info(dhd, buf); -#ifdef WRITE_WLANINFO - sec_save_wlinfo(buf, EPI_VERSION_STR, dhd->info->nv_path, clm_version); -#endif /* WRITE_WLANINFO */ - } -#ifdef GEN_SOFTAP_INFO_FILE - sec_save_softap_info(); -#endif /* GEN_SOFTAP_INFO_FILE */ - -#if defined(BCMSDIO) - dhd_txglom_enable(dhd, dhd->conf->bus_rxglom); -#endif /* defined(BCMSDIO) */ - -#if defined(BCMSDIO) || defined(BCMDBUS) -#ifdef PROP_TXSTATUS - if (disable_proptx || -#ifdef PROP_TXSTATUS_VSDB - /* enable WLFC only if the firmware is VSDB when it is in STA mode */ - (dhd->op_mode != DHD_FLAG_HOSTAP_MODE && - dhd->op_mode != DHD_FLAG_IBSS_MODE) || -#endif /* PROP_TXSTATUS_VSDB */ - FALSE) { - wlfc_enable = FALSE; - } - ret = dhd_conf_get_disable_proptx(dhd); - if (ret == 0){ - disable_proptx = 0; - wlfc_enable = TRUE; - } else if (ret >= 1) { - disable_proptx = 1; - wlfc_enable = FALSE; - /* terence 20161229: we should set ampdu_hostreorder=0 when disalbe_proptx=1 */ - hostreorder = 0; - } - -#if defined(PROP_TXSTATUS) -#ifdef USE_WFA_CERT_CONF - if (sec_get_param_wfa_cert(dhd, SET_PARAM_PROPTX, &proptx) == BCME_OK) { - DHD_ERROR(("%s , read proptx param=%d\n", __FUNCTION__, proptx)); - wlfc_enable = proptx; - } -#endif /* USE_WFA_CERT_CONF */ -#endif /* PROP_TXSTATUS */ - -#ifndef DISABLE_11N - ret = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, (char *)&wl_down, sizeof(wl_down), TRUE, 0); - ret2 = dhd_iovar(dhd, 0, "ampdu_hostreorder", (char *)&hostreorder, sizeof(hostreorder), - NULL, 0, TRUE); - if (ret2 < 0) { - DHD_ERROR(("%s wl ampdu_hostreorder failed %d\n", __FUNCTION__, ret2)); - if (ret2 != BCME_UNSUPPORTED) - ret = ret2; - - if (ret == BCME_NOTDOWN) { - uint wl_down = 1; - ret2 = dhd_wl_ioctl_cmd(dhd, WLC_DOWN, (char *)&wl_down, - sizeof(wl_down), TRUE, 0); - DHD_ERROR(("%s ampdu_hostreorder fail WL_DOWN : %d, hostreorder :%d\n", - __FUNCTION__, ret2, hostreorder)); - - ret2 = dhd_iovar(dhd, 0, "ampdu_hostreorder", (char *)&hostreorder, - sizeof(hostreorder), NULL, 0, TRUE); - DHD_ERROR(("%s wl ampdu_hostreorder. ret --> %d\n", __FUNCTION__, ret2)); - if (ret2 != BCME_UNSUPPORTED) - ret = ret2; - } - if (ret2 != BCME_OK) - hostreorder = 0; - } -#endif /* DISABLE_11N */ - - - if (wlfc_enable) { - dhd_wlfc_init(dhd); - /* terence 20161229: enable ampdu_hostreorder if tlv enabled */ - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "ampdu_hostreorder", 1, 0, TRUE); - } -#ifndef DISABLE_11N - else if (hostreorder) - dhd_wlfc_hostreorder_init(dhd); -#endif /* DISABLE_11N */ -#else - /* disable ampdu_hostreorder if PROP_TXSTATUS not defined */ - DHD_INFO(("%s: not define PROP_TXSTATUS\n", __FUNCTION__)); - dhd_conf_set_intiovar(dhd, WLC_SET_VAR, "ampdu_hostreorder", 0, 0, TRUE); -#endif /* PROP_TXSTATUS */ -#endif /* BCMSDIO || BCMDBUS */ -#ifndef PCIE_FULL_DONGLE - /* For FD we need all the packets at DHD to handle intra-BSS forwarding */ - if (FW_SUPPORTED(dhd, ap)) { - wl_ap_isolate = AP_ISOLATE_SENDUP_ALL; - ret = dhd_iovar(dhd, 0, "ap_isolate", (char *)&wl_ap_isolate, sizeof(wl_ap_isolate), - NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret)); - } -#endif /* PCIE_FULL_DONGLE */ -#ifdef PNO_SUPPORT - if (!dhd->pno_state) { - dhd_pno_init(dhd); - } -#endif -#ifdef RTT_SUPPORT - if (!dhd->rtt_state) { - ret = dhd_rtt_init(dhd); - if (ret < 0) { - DHD_ERROR(("%s failed to initialize RTT\n", __FUNCTION__)); - } - } -#endif -#ifdef WL11U - dhd_interworking_enable(dhd); -#endif /* WL11U */ - -#ifdef SUPPORT_SENSORHUB - DHD_INFO(("%s: SensorHub enabled %d\n", - __FUNCTION__, dhd->info->shub_enable)); - ret2 = dhd_iovar(dhd, 0, "shub", NULL, 0, - (char *)&shub_ctl, sizeof(shub_ctl), FALSE); - if (ret2 < 0) { - DHD_ERROR(("%s failed to get shub hub enable information %d\n", - __FUNCTION__, ret2)); - dhd->info->shub_enable = 0; - } else { - dhd->info->shub_enable = shub_ctl.enable; - DHD_ERROR(("%s: checking sensorhub enable %d\n", - __FUNCTION__, dhd->info->shub_enable)); - } -#endif /* SUPPORT_SENSORHUB */ - - -#ifdef NDO_CONFIG_SUPPORT - dhd->ndo_enable = FALSE; - dhd->ndo_host_ip_overflow = FALSE; - dhd->ndo_max_host_ip = NDO_MAX_HOST_IP_ENTRIES; -#endif /* NDO_CONFIG_SUPPORT */ - - /* ND offload version supported */ - dhd->ndo_version = dhd_ndo_get_version(dhd); - if (dhd->ndo_version > 0) { - DHD_INFO(("%s: ndo version %d\n", __FUNCTION__, dhd->ndo_version)); - -#ifdef NDO_CONFIG_SUPPORT - /* enable Unsolicited NA filter */ - ret = dhd_ndo_unsolicited_na_filter_enable(dhd, 1); - if (ret < 0) { - DHD_ERROR(("%s failed to enable Unsolicited NA filter\n", __FUNCTION__)); - } -#endif /* NDO_CONFIG_SUPPORT */ - } - - /* check dongle supports wbtext or not */ - dhd->wbtext_support = FALSE; - if (dhd_wl_ioctl_get_intiovar(dhd, "wnm_bsstrans_resp", &wnm_bsstrans_resp, - WLC_GET_VAR, FALSE, 0) != BCME_OK) { - DHD_ERROR(("failed to get wnm_bsstrans_resp\n")); - } - if (wnm_bsstrans_resp == WL_BSSTRANS_POLICY_PRODUCT_WBTEXT) { - dhd->wbtext_support = TRUE; - } -#ifndef WBTEXT - /* driver can turn off wbtext feature through makefile */ - if (dhd->wbtext_support) { - if (dhd_wl_ioctl_set_intiovar(dhd, "wnm_bsstrans_resp", - WL_BSSTRANS_POLICY_ROAM_ALWAYS, - WLC_SET_VAR, FALSE, 0) != BCME_OK) { - DHD_ERROR(("failed to disable WBTEXT\n")); - } - } -#endif /* !WBTEXT */ -#ifdef WNM_NEST - if (dhd_wl_ioctl_set_intiovar(dhd, "wnm_bsstrans_resp", - WL_BSSTRANS_POLICY_ROAM_ALWAYS, - WLC_SET_VAR, FALSE, 0) != BCME_OK) { - DHD_ERROR(("failed to set wnm_bsstrans_resp\n")); - } -#endif - - /* WNM capabilities */ - wnm_cap = 0 -#ifdef WL11U - | WL_WNM_BSSTRANS | WL_WNM_NOTIF -#endif -#if defined(WBTEXT) || defined(WNM_NEST) - | WL_WNM_BSSTRANS | WL_WNM_MAXIDLE -#endif /* defined(WBTEXT) || defined(WNM_NEST) */ - ; - - if (dhd_iovar(dhd, 0, "wnm", (char *)&wnm_cap, sizeof(wnm_cap), NULL, 0, TRUE) < 0) { - DHD_ERROR(("failed to set WNM capabilities\n")); - } - -#ifdef HAL_API - if (dhd_chip_alive) { - tcpka_conn_sess_info_t *sess_info; - uint32 id = TCPKA_DEFAULT_SESS_ID; - memset(iov_buf, 0, WLC_IOCTL_SMLEN); - ret2 = dhd_iovar(dhd, 0, "tcpka_conn_sess_info", (char *)&id, sizeof(id), - iov_buf, WLC_IOCTL_SMLEN, FALSE); - if (ret2 == BCME_OK) { - sess_info = (tcpka_conn_sess_info_t *)iov_buf; - DHD_INFO(("%s: tcpka sess %d : %d\n", __func__, id, - sess_info->tcpka_sess_active)); - dhd_tcpka_sess_active = sess_info->tcpka_sess_active; - } - } - ret = dhd_ndo_enable(dhd, 1); - if (ret < 0) - DHD_ERROR(("%s: failed to enable NDO\n", __func__)); - - nd_ra_filter = 1; - ret = dhd_iovar(dhd, 0, "nd_ra_filter_enable", - (char *)&nd_ra_filter, sizeof(nd_ra_filter), NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s: failed to set nd_ra_filter (%d)\n", __func__, ret)); - - slaac_enable = 1; - ret = dhd_iovar(dhd, 0, "slaac_enable", - (char *)&slaac_enable, sizeof(slaac_enable), NULL, 0, TRUE); - if (ret < 0) - DHD_ERROR(("%s: failed to set slaac_enable (%d)\n", __func__, ret)); - -#endif /* HAL_API */ - - dhd_conf_postinit_ioctls(dhd); -#ifdef RELOAD_WIFI - if (fw_reload_new_backoff >= FW_RELOAD_BACKOFF_UNIT_SEC) { - if (dhd_wl_ioctl_set_intiovar(dhd, "block_list_backoff_time", - fw_reload_new_backoff, - WLC_SET_VAR, FALSE, 0) != BCME_OK) { - DHD_ERROR(("failed to set block_list_backoff_time\n")); - } else { - DHD_ERROR(("set block_list_backoff_time to %u\n", - fw_reload_new_backoff)); - } - } -#endif /* RELOAD_WIFI */ -done: - - if (eventmask_msg) - kfree(eventmask_msg); - if (iov_buf) - kfree(iov_buf); -#if defined(DHD_8021X_DUMP) && defined(SHOW_LOGTRACE) - if (el_tag) - kfree(el_tag); -#endif /* DHD_8021X_DUMP */ - return ret; -} - - -int -dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *param_buf, uint param_len, char *res_buf, - uint res_len, int set) -{ - char *buf = NULL; - int input_len; - wl_ioctl_t ioc; - int ret; - - if (res_len > WLC_IOCTL_MAXLEN || param_len > WLC_IOCTL_MAXLEN) - return BCME_BADARG; - - input_len = strlen(name) + 1 + param_len; - if (input_len > WLC_IOCTL_MAXLEN) - return BCME_BADARG; - - buf = NULL; - if (set) { - if (res_buf || res_len != 0) { - DHD_ERROR(("%s: SET wrong arguemnet\n", __FUNCTION__)); - ret = BCME_BADARG; - goto exit; - } - buf = kzalloc(input_len, GFP_KERNEL); - if (!buf) { - DHD_ERROR(("%s: mem alloc failed\n", __FUNCTION__)); - ret = BCME_NOMEM; - goto exit; - } - ret = bcm_mkiovar(name, param_buf, param_len, buf, input_len); - if (!ret) { - ret = BCME_NOMEM; - goto exit; - } - - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = input_len; - ioc.set = set; - - ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); - } else { - if (!res_buf || !res_len) { - DHD_ERROR(("%s: GET failed. resp_buf NULL or length 0.\n", __FUNCTION__)); - ret = BCME_BADARG; - goto exit; - } - - if (res_len < input_len) { - DHD_INFO(("%s: res_len(%d) < input_len(%d)\n", __FUNCTION__, - res_len, input_len)); - buf = kzalloc(input_len, GFP_KERNEL); - if (!buf) { - DHD_ERROR(("%s: mem alloc failed\n", __FUNCTION__)); - ret = BCME_NOMEM; - goto exit; - } - ret = bcm_mkiovar(name, param_buf, param_len, buf, input_len); - if (!ret) { - ret = BCME_NOMEM; - goto exit; - } - - ioc.cmd = WLC_GET_VAR; - ioc.buf = buf; - ioc.len = input_len; - ioc.set = set; - - ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); - - if (ret == BCME_OK) { - memcpy(res_buf, buf, res_len); - } - } else { - memset(res_buf, 0, res_len); - ret = bcm_mkiovar(name, param_buf, param_len, res_buf, res_len); - if (!ret) { - ret = BCME_NOMEM; - goto exit; - } - - ioc.cmd = WLC_GET_VAR; - ioc.buf = res_buf; - ioc.len = res_len; - ioc.set = set; - - ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); - } - } -exit: - kfree(buf); - return ret; -} - -int -dhd_getiovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, - uint cmd_len, char **resptr, uint resp_len) -{ - int len = resp_len; - int ret; - char *buf = *resptr; - wl_ioctl_t ioc; - if (resp_len > WLC_IOCTL_MAXLEN) - return BCME_BADARG; - - memset(buf, 0, resp_len); - - ret = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len); - if (ret == 0) { - return BCME_BUFTOOSHORT; - } - - memset(&ioc, 0, sizeof(ioc)); - - ioc.cmd = WLC_GET_VAR; - ioc.buf = buf; - ioc.len = len; - ioc.set = 0; - - ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); - - return ret; -} - - -int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx) -{ - struct dhd_info *dhd = dhdp->info; - struct net_device *dev = NULL; - - ASSERT(dhd && dhd->iflist[ifidx]); - dev = dhd->iflist[ifidx]->net; - ASSERT(dev); - - if (netif_running(dev)) { - DHD_ERROR(("%s: Must be down to change its MTU\n", dev->name)); - return BCME_NOTDOWN; - } - -#define DHD_MIN_MTU 1500 -#define DHD_MAX_MTU 1752 - - if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) { - DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu)); - return BCME_BADARG; - } - - dev->mtu = new_mtu; - return 0; -} - -#ifdef ARP_OFFLOAD_SUPPORT -/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */ -void -aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add, int idx) -{ - u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */ - int i; - int ret; - - bzero(ipv4_buf, sizeof(ipv4_buf)); - - /* display what we've got */ - ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); - DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__)); -#ifdef AOE_DBG - dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ -#endif - /* now we saved hoste_ip table, clr it in the dongle AOE */ - dhd_aoe_hostip_clr(dhd_pub, idx); - - if (ret) { - DHD_ERROR(("%s failed\n", __FUNCTION__)); - return; - } - - for (i = 0; i < MAX_IPV4_ENTRIES; i++) { - if (add && (ipv4_buf[i] == 0)) { - ipv4_buf[i] = ipa; - add = FALSE; /* added ipa to local table */ - DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n", - __FUNCTION__, i)); - } else if (ipv4_buf[i] == ipa) { - ipv4_buf[i] = 0; - DHD_ARPOE(("%s: removed IP:%x from temp table %d\n", - __FUNCTION__, ipa, i)); - } - - if (ipv4_buf[i] != 0) { - /* add back host_ip entries from our local cache */ - dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i], idx); - DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n", - __FUNCTION__, ipv4_buf[i], i)); - } - } -#ifdef AOE_DBG - /* see the resulting hostip table */ - dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf), idx); - DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__)); - dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ -#endif -} - -/* - * Notification mechanism from kernel to our driver. This function is called by the Linux kernel - * whenever there is an event related to an IP address. - * ptr : kernel provided pointer to IP address that has changed - */ -static int dhd_inetaddr_notifier_call(struct notifier_block *this, - unsigned long event, - void *ptr) -{ - struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; - - dhd_info_t *dhd; - dhd_pub_t *dhd_pub; - int idx; - - if (!dhd_arp_enable) - return NOTIFY_DONE; - if (!ifa || !(ifa->ifa_dev->dev)) - return NOTIFY_DONE; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) - /* Filter notifications meant for non Broadcom devices */ - if ((ifa->ifa_dev->dev->netdev_ops != &dhd_ops_pri) && - (ifa->ifa_dev->dev->netdev_ops != &dhd_ops_virt)) { -#if defined(WL_ENABLE_P2P_IF) - if (!wl_cfgp2p_is_ifops(ifa->ifa_dev->dev->netdev_ops)) -#endif /* WL_ENABLE_P2P_IF */ - return NOTIFY_DONE; - } -#endif /* LINUX_VERSION_CODE */ - - dhd = DHD_DEV_INFO(ifa->ifa_dev->dev); - if (!dhd) - return NOTIFY_DONE; - - dhd_pub = &dhd->pub; - - if (dhd_pub->arp_version == 1) { - idx = 0; - } else { - for (idx = 0; idx < DHD_MAX_IFS; idx++) { - if (dhd->iflist[idx] && dhd->iflist[idx]->net == ifa->ifa_dev->dev) - break; - } - if (idx < DHD_MAX_IFS) - DHD_TRACE(("ifidx : %p %s %d\n", dhd->iflist[idx]->net, - dhd->iflist[idx]->name, dhd->iflist[idx]->idx)); - else { - DHD_ERROR(("Cannot find ifidx for(%s) set to 0\n", ifa->ifa_label)); - idx = 0; - } - } - - switch (event) { - case NETDEV_UP: - DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n", - __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); - - if (dhd->pub.busstate != DHD_BUS_DATA) { - DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__)); - if (dhd->pend_ipaddr) { - DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n", - __FUNCTION__, dhd->pend_ipaddr)); - } - dhd->pend_ipaddr = ifa->ifa_address; - break; - } - -#ifdef AOE_IP_ALIAS_SUPPORT - DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n", - __FUNCTION__)); - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE, idx); -#endif /* AOE_IP_ALIAS_SUPPORT */ - break; - - case NETDEV_DOWN: - DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n", - __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); - dhd->pend_ipaddr = 0; -#ifdef AOE_IP_ALIAS_SUPPORT - DHD_ARPOE(("%s:interface is down, AOE clr all for this if\n", - __FUNCTION__)); - if ((dhd_pub->op_mode & DHD_FLAG_HOSTAP_MODE) || - (ifa->ifa_dev->dev != dhd_linux_get_primary_netdev(dhd_pub))) { - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE, idx); - } else -#endif /* AOE_IP_ALIAS_SUPPORT */ - { - dhd_aoe_hostip_clr(&dhd->pub, idx); - dhd_aoe_arp_clr(&dhd->pub, idx); - } - break; - - default: - DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n", - __func__, ifa->ifa_label, event)); - break; - } - return NOTIFY_DONE; -} -#endif /* ARP_OFFLOAD_SUPPORT */ - -#if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT) -/* Neighbor Discovery Offload: defered handler */ -static void -dhd_inet6_work_handler(void *dhd_info, void *event_data, u8 event) -{ - struct ipv6_work_info_t *ndo_work = (struct ipv6_work_info_t *)event_data; - dhd_info_t *dhd = (dhd_info_t *)dhd_info; - dhd_pub_t *dhdp; - int ret; - - if (!dhd) { - DHD_ERROR(("%s: invalid dhd_info\n", __FUNCTION__)); - goto done; - } - dhdp = &dhd->pub; - - if (event != DHD_WQ_WORK_IPV6_NDO) { - DHD_ERROR(("%s: unexpected event\n", __FUNCTION__)); - goto done; - } - - if (!ndo_work) { - DHD_ERROR(("%s: ipv6 work info is not initialized\n", __FUNCTION__)); - return; - } - - switch (ndo_work->event) { - case NETDEV_UP: -#ifndef NDO_CONFIG_SUPPORT - DHD_TRACE(("%s: Enable NDO \n ", __FUNCTION__)); - ret = dhd_ndo_enable(dhdp, TRUE); - if (ret < 0) { - DHD_ERROR(("%s: Enabling NDO Failed %d\n", __FUNCTION__, ret)); - } -#endif /* !NDO_CONFIG_SUPPORT */ - DHD_TRACE(("%s: Add a host ip for NDO\n", __FUNCTION__)); - if (dhdp->ndo_version > 0) { - /* inet6 addr notifier called only for unicast address */ - ret = dhd_ndo_add_ip_with_type(dhdp, &ndo_work->ipv6_addr[0], - WL_ND_IPV6_ADDR_TYPE_UNICAST, ndo_work->if_idx); - } else { - ret = dhd_ndo_add_ip(dhdp, &ndo_work->ipv6_addr[0], - ndo_work->if_idx); - } - if (ret < 0) { - DHD_ERROR(("%s: Adding a host ip for NDO failed %d\n", - __FUNCTION__, ret)); - } - break; - case NETDEV_DOWN: - if (dhdp->ndo_version > 0) { - DHD_TRACE(("%s: Remove a host ip for NDO\n", __FUNCTION__)); - ret = dhd_ndo_remove_ip_by_addr(dhdp, - &ndo_work->ipv6_addr[0], ndo_work->if_idx); - } else { - DHD_TRACE(("%s: Clear host ip table for NDO \n", __FUNCTION__)); - ret = dhd_ndo_remove_ip(dhdp, ndo_work->if_idx); - } - if (ret < 0) { - DHD_ERROR(("%s: Removing host ip for NDO failed %d\n", - __FUNCTION__, ret)); - goto done; - } -#ifdef NDO_CONFIG_SUPPORT - if (dhdp->ndo_host_ip_overflow) { - ret = dhd_dev_ndo_update_inet6addr( - dhd_idx2net(dhdp, ndo_work->if_idx)); - if ((ret < 0) && (ret != BCME_NORESOURCE)) { - DHD_ERROR(("%s: Updating host ip for NDO failed %d\n", - __FUNCTION__, ret)); - goto done; - } - } -#else /* !NDO_CONFIG_SUPPORT */ -#ifndef HAL_API - DHD_TRACE(("%s: Disable NDO\n ", __FUNCTION__)); - ret = dhd_ndo_enable(dhdp, FALSE); - if (ret < 0) { - DHD_ERROR(("%s: disabling NDO Failed %d\n", __FUNCTION__, ret)); - goto done; - } -#endif /* HAL_API */ -#endif /* NDO_CONFIG_SUPPORT */ - break; - - default: - DHD_ERROR(("%s: unknown notifier event \n", __FUNCTION__)); - break; - } -done: - /* free ndo_work. alloced while scheduling the work */ - if (ndo_work) { - kfree(ndo_work); - } - - return; -} - -/* - * Neighbor Discovery Offload: Called when an interface - * is assigned with ipv6 address. - * Handles only primary interface - */ -int dhd_inet6addr_notifier_call(struct notifier_block *this, unsigned long event, void *ptr) -{ - dhd_info_t *dhd; - dhd_pub_t *dhdp; - struct inet6_ifaddr *inet6_ifa = ptr; - struct ipv6_work_info_t *ndo_info; - int idx; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) - /* Filter notifications meant for non Broadcom devices */ - if (inet6_ifa->idev->dev->netdev_ops != &dhd_ops_pri) { - return NOTIFY_DONE; - } -#endif /* LINUX_VERSION_CODE */ - - dhd = DHD_DEV_INFO(inet6_ifa->idev->dev); - if (!dhd) { - return NOTIFY_DONE; - } - dhdp = &dhd->pub; - - /* Supports only primary interface */ - idx = dhd_net2idx(dhd, inet6_ifa->idev->dev); - if (idx != 0) { - return NOTIFY_DONE; - } - - /* FW capability */ - if (!FW_SUPPORTED(dhdp, ndoe)) { - return NOTIFY_DONE; - } - - ndo_info = (struct ipv6_work_info_t *)kzalloc(sizeof(struct ipv6_work_info_t), GFP_ATOMIC); - if (!ndo_info) { - DHD_ERROR(("%s: ipv6 work alloc failed\n", __FUNCTION__)); - return NOTIFY_DONE; - } - - /* fill up ndo_info */ - ndo_info->event = event; - ndo_info->if_idx = idx; - memcpy(ndo_info->ipv6_addr, &inet6_ifa->addr, IPV6_ADDR_LEN); - - /* defer the work to thread as it may block kernel */ - dhd_deferred_schedule_work(dhd->dhd_deferred_wq, (void *)ndo_info, DHD_WQ_WORK_IPV6_NDO, - dhd_inet6_work_handler, DHD_WQ_WORK_PRIORITY_LOW); - return NOTIFY_DONE; -} -#endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ - -int -dhd_register_if(dhd_pub_t *dhdp, int ifidx, bool need_rtnl_lock) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - dhd_if_t *ifp; - struct net_device *net = NULL; - int err = 0; - uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 }; - - DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); - - if (dhd == NULL || dhd->iflist[ifidx] == NULL) { - DHD_ERROR(("%s: Invalid Interface\n", __FUNCTION__)); - return BCME_ERROR; - } - - ASSERT(dhd && dhd->iflist[ifidx]); - ifp = dhd->iflist[ifidx]; - net = ifp->net; - ASSERT(net && (ifp->idx == ifidx)); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - ASSERT(!net->open); - net->get_stats = dhd_get_stats; - net->do_ioctl = dhd_ioctl_entry; - net->hard_start_xmit = dhd_start_xmit; - net->set_mac_address = dhd_set_mac_address; - net->set_multicast_list = dhd_set_multicast_list; - net->open = net->stop = NULL; -#else - ASSERT(!net->netdev_ops); - net->netdev_ops = &dhd_ops_virt; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ - - /* Ok, link into the network layer... */ - if (ifidx == 0) { - /* - * device functions for the primary interface only - */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - net->open = dhd_open; - net->stop = dhd_stop; -#else - net->netdev_ops = &dhd_ops_pri; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ - if (!ETHER_ISNULLADDR(dhd->pub.mac.octet)) - memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); - } else { - /* - * We have to use the primary MAC for virtual interfaces - */ - memcpy(temp_addr, ifp->mac_addr, ETHER_ADDR_LEN); - /* - * Android sets the locally administered bit to indicate that this is a - * portable hotspot. This will not work in simultaneous AP/STA mode, - * nor with P2P. Need to set the Donlge's MAC address, and then use that. - */ - if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr, - ETHER_ADDR_LEN)) { - DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n", - __func__, net->name)); - temp_addr[0] |= 0x02; - } - } - - net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) - net->ethtool_ops = &dhd_ethtool_ops; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ - -#if defined(WL_WIRELESS_EXT) -#if WIRELESS_EXT < 19 - net->get_wireless_stats = dhd_get_wireless_stats; -#endif /* WIRELESS_EXT < 19 */ -#if WIRELESS_EXT > 12 - net->wireless_handlers = &wl_iw_handler_def; -#endif /* WIRELESS_EXT > 12 */ -#endif /* defined(WL_WIRELESS_EXT) */ - - dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); - -#ifdef WLMESH - if (ifidx >= 2 && dhdp->conf->fw_type == FW_TYPE_MESH) { - temp_addr[4] ^= 0x80; - temp_addr[4] += ifidx; - temp_addr[5] += ifidx; - } -#endif - memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); - - if (ifidx == 0) - DHD_INFO(("%s\n", dhd_version)); -#ifdef WL_EXT_IAPSTA - else - wl_ext_iapsta_attach_netdev(net, ifidx); -#endif -#ifdef WLMESH - if (ifidx != 0 && dhdp->conf->fw_type == FW_TYPE_MESH) { - if (_dhd_set_mac_address(dhd, ifidx, temp_addr) == 0) - DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__)); - else - DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", __FUNCTION__)); - } -#endif - - if (need_rtnl_lock) - err = register_netdev(net); - else - err = register_netdevice(net); - - if (err != 0) { - DHD_ERROR(("couldn't register the net device [%s], err %d\n", net->name, err)); - goto fail; - } -#ifdef WL_EXT_IAPSTA - if (ifidx == 0) - wl_ext_iapsta_attach_netdev(net, ifidx); - wl_ext_iapsta_attach_name(net, ifidx); -#endif - - - - DHD_INFO(("Register interface [%s] MAC: "MACDBG"\n\n", net->name, -#if defined(CUSTOMER_HW4_DEBUG) - MAC2STRDBG(dhd->pub.mac.octet))); -#else - MAC2STRDBG(net->dev_addr))); -#endif /* CUSTOMER_HW4_DEBUG */ - -#if defined(SOFTAP) && defined(WL_WIRELESS_EXT) && !defined(WL_CFG80211) -// wl_iw_iscan_set_scan_broadcast_prep(net, 1); -#endif - -#if (defined(BCMPCIE) || (defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= \ - KERNEL_VERSION(2, 6, 27))) || defined(BCMDBUS)) - if (ifidx == 0) { -#if defined(BCMLXSDMMC) && !defined(DHD_PRELOAD) - up(&dhd_registration_sem); -#endif /* BCMLXSDMMC */ - if (!dhd_download_fw_on_driverload) { -#ifdef WL_CFG80211 - wl_terminate_event_handler(net); -#endif /* WL_CFG80211 */ -#if defined(DHD_LB_RXP) - __skb_queue_purge(&dhd->rx_pend_queue); -#endif /* DHD_LB_RXP */ - -#if defined(DHD_LB_TXP) - skb_queue_purge(&dhd->tx_pend_queue); -#endif /* DHD_LB_TXP */ - -#ifdef SHOW_LOGTRACE - /* Release the skbs from queue for WLC_E_TRACE event */ - dhd_event_logtrace_flush_queue(dhdp); -#endif /* SHOW_LOGTRACE */ - -#ifdef DHDTCPACK_SUPPRESS - dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF); -#endif /* DHDTCPACK_SUPPRESS */ - dhd_net_bus_devreset(net, TRUE); -#ifdef BCMLXSDMMC - dhd_net_bus_suspend(net); -#endif /* BCMLXSDMMC */ - wifi_platform_set_power(dhdp->info->adapter, FALSE, WIFI_TURNOFF_DELAY); -#if defined(BT_OVER_SDIO) - dhd->bus_user_count--; -#endif /* BT_OVER_SDIO */ - } - } -#endif /* OEM_ANDROID && (BCMPCIE || (BCMLXSDMMC && KERNEL_VERSION >= 2.6.27)) */ - return 0; - -fail: -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) - net->open = NULL; -#else - net->netdev_ops = NULL; -#endif - return err; -} - -void -dhd_bus_detach(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (dhdp) { - dhd = (dhd_info_t *)dhdp->info; - if (dhd) { - - /* - * In case of Android cfg80211 driver, the bus is down in dhd_stop, - * calling stop again will cuase SD read/write errors. - */ - if (dhd->pub.busstate != DHD_BUS_DOWN && dhd_download_fw_on_driverload) { - /* Stop the protocol module */ - dhd_prot_stop(&dhd->pub); - - /* Stop the bus module */ -#ifdef BCMDBUS - /* Force Dongle terminated */ - if (dhd_wl_ioctl_cmd(dhdp, WLC_TERMINATED, NULL, 0, TRUE, 0) < 0) - DHD_ERROR(("%s Setting WLC_TERMINATED failed\n", - __FUNCTION__)); - dbus_stop(dhd->pub.bus); - dhd->pub.busstate = DHD_BUS_DOWN; -#else - dhd_bus_stop(dhd->pub.bus, TRUE); -#endif /* BCMDBUS */ - } - -#if defined(OOB_INTR_ONLY) || defined(BCMPCIE_OOB_HOST_WAKE) - dhd_bus_oob_intr_unregister(dhdp); -#endif - } - } -} - - -void dhd_detach(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - unsigned long flags; - int timer_valid = FALSE; - struct net_device *dev; -#ifdef WL_CFG80211 - struct bcm_cfg80211 *cfg = NULL; -#endif -#ifdef HOFFLOAD_MODULES - struct module_metadata *hmem = NULL; -#endif - if (!dhdp) - return; - - dhd = (dhd_info_t *)dhdp->info; - if (!dhd) - return; - - dev = dhd->iflist[0]->net; - - if (dev) { - rtnl_lock(); - if (dev->flags & IFF_UP) { - /* If IFF_UP is still up, it indicates that - * "ifconfig wlan0 down" hasn't been called. - * So invoke dev_close explicitly here to - * bring down the interface. - */ - DHD_TRACE(("IFF_UP flag is up. Enforcing dev_close from detach \n")); - dev_close(dev); - } - rtnl_unlock(); - } - - DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state)); - - dhd->pub.up = 0; - if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) { - /* Give sufficient time for threads to start running in case - * dhd_attach() has failed - */ - OSL_SLEEP(100); - } -#ifdef DHD_WET - dhd_free_wet_info(&dhd->pub, dhd->pub.wet_info); -#endif /* DHD_WET */ -#if defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) -#endif /* defined(BCM_DNGL_EMBEDIMAGE) || defined(BCM_REQUEST_FW) */ - -#ifdef PROP_TXSTATUS -#ifdef DHD_WLFC_THREAD - if (dhd->pub.wlfc_thread) { - kthread_stop(dhd->pub.wlfc_thread); - dhdp->wlfc_thread_go = TRUE; - wake_up_interruptible(&dhdp->wlfc_wqhead); - } - dhd->pub.wlfc_thread = NULL; -#endif /* DHD_WLFC_THREAD */ -#endif /* PROP_TXSTATUS */ - -#ifdef DHD_TIMESYNC - if (dhd->dhd_state & DHD_ATTACH_TIMESYNC_ATTACH_DONE) { - dhd_timesync_detach(dhdp); - } -#endif /* DHD_TIMESYNC */ -#ifdef WL_CFG80211 - if (dev) { - wl_cfg80211_down(dev); - } -#endif /* WL_CFG80211 */ - - if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) { - dhd_bus_detach(dhdp); -#ifdef BCMPCIE - if (is_reboot == SYS_RESTART) { - extern bcmdhd_wifi_platdata_t *dhd_wifi_platdata; - if (dhd_wifi_platdata && !dhdp->dongle_reset) { - dhdpcie_bus_clock_stop(dhdp->bus); - wifi_platform_set_power(dhd_wifi_platdata->adapters, - FALSE, WIFI_TURNOFF_DELAY); - } - } -#endif /* BCMPCIE */ -#ifndef PCIE_FULL_DONGLE - if (dhdp->prot) - dhd_prot_detach(dhdp); -#endif /* !PCIE_FULL_DONGLE */ - } - -#ifdef ARP_OFFLOAD_SUPPORT - if (dhd_inetaddr_notifier_registered) { - dhd_inetaddr_notifier_registered = FALSE; - unregister_inetaddr_notifier(&dhd_inetaddr_notifier); - } -#endif /* ARP_OFFLOAD_SUPPORT */ -#if defined(CONFIG_IPV6) && defined(IPV6_NDO_SUPPORT) - if (dhd_inet6addr_notifier_registered) { - dhd_inet6addr_notifier_registered = FALSE; - unregister_inet6addr_notifier(&dhd_inet6addr_notifier); - } -#endif /* CONFIG_IPV6 && IPV6_NDO_SUPPORT */ -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) - if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) { - if (dhd->early_suspend.suspend) - unregister_early_suspend(&dhd->early_suspend); - } -#endif /* CONFIG_HAS_EARLYSUSPEND && DHD_USE_EARLYSUSPEND */ - -#if defined(WL_WIRELESS_EXT) - if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) { - /* Detatch and unlink in the iw */ - wl_iw_detach(); - } -#ifdef WL_ESCAN - wl_escan_detach(dhdp); -#endif /* WL_ESCAN */ -#endif /* defined(WL_WIRELESS_EXT) */ - -#ifdef DHD_ULP - dhd_ulp_deinit(dhd->pub.osh, dhdp); -#endif /* DHD_ULP */ - - /* delete all interfaces, start with virtual */ - if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) { - int i = 1; - dhd_if_t *ifp; - - /* Cleanup virtual interfaces */ - dhd_net_if_lock_local(dhd); - for (i = 1; i < DHD_MAX_IFS; i++) { - if (dhd->iflist[i]) { - dhd_remove_if(&dhd->pub, i, TRUE); - } - } - dhd_net_if_unlock_local(dhd); - - /* delete primary interface 0 */ - ifp = dhd->iflist[0]; - ASSERT(ifp); - ASSERT(ifp->net); - if (ifp && ifp->net) { -#ifdef WL_CFG80211 - cfg = wl_get_cfg(ifp->net); -#endif - /* in unregister_netdev case, the interface gets freed by net->destructor - * (which is set to free_netdev) - */ - if (ifp->net->reg_state == NETREG_UNINITIALIZED) { - free_netdev(ifp->net); - } else { - argos_register_notifier_deinit(); -#ifdef SET_RPS_CPUS - custom_rps_map_clear(ifp->net->_rx); -#endif /* SET_RPS_CPUS */ - netif_tx_disable(ifp->net); - unregister_netdev(ifp->net); - } -#ifdef PCIE_FULL_DONGLE - ifp->net = DHD_NET_DEV_NULL; -#else - ifp->net = NULL; -#endif /* PCIE_FULL_DONGLE */ - -#ifdef DHD_WMF - dhd_wmf_cleanup(dhdp, 0); -#endif /* DHD_WMF */ -#ifdef DHD_L2_FILTER - bcm_l2_filter_arp_table_update(dhdp->osh, ifp->phnd_arp_table, TRUE, - NULL, FALSE, dhdp->tickcnt); - deinit_l2_filter_arp_table(dhdp->osh, ifp->phnd_arp_table); - ifp->phnd_arp_table = NULL; -#endif /* DHD_L2_FILTER */ - - - dhd_if_del_sta_list(ifp); - - MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); - dhd->iflist[0] = NULL; - } - } - - /* Clear the watchdog timer */ - DHD_GENERAL_LOCK(&dhd->pub, flags); - timer_valid = dhd->wd_timer_valid; - dhd->wd_timer_valid = FALSE; - DHD_GENERAL_UNLOCK(&dhd->pub, flags); - if (timer_valid) - del_timer_sync(&dhd->timer); - DHD_DISABLE_RUNTIME_PM(&dhd->pub); - -#ifdef BCMDBUS - tasklet_kill(&dhd->tasklet); -#else - if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) { -#ifdef DHD_PCIE_RUNTIMEPM - if (dhd->thr_rpm_ctl.thr_pid >= 0) { - PROC_STOP(&dhd->thr_rpm_ctl); - } -#endif /* DHD_PCIE_RUNTIMEPM */ - if (dhd->thr_wdt_ctl.thr_pid >= 0) { - PROC_STOP(&dhd->thr_wdt_ctl); - } - - if (dhd->rxthread_enabled && dhd->thr_rxf_ctl.thr_pid >= 0) { - PROC_STOP(&dhd->thr_rxf_ctl); - } - - if (dhd->thr_dpc_ctl.thr_pid >= 0) { - PROC_STOP(&dhd->thr_dpc_ctl); - } else - { - tasklet_kill(&dhd->tasklet); - } - } -#endif /* BCMDBUS */ -#ifdef TCPKA_REPAIR - cancel_work_sync(&dhd->tcpka_reset_work); -#endif /* TCPKA_REPAIR */ -#ifdef DHD_LB - if (dhd->dhd_state & DHD_ATTACH_STATE_LB_ATTACH_DONE) { - /* Clear the flag first to avoid calling the cpu notifier */ - dhd->dhd_state &= ~DHD_ATTACH_STATE_LB_ATTACH_DONE; - - /* Kill the Load Balancing Tasklets */ -#ifdef DHD_LB_RXP - cancel_work_sync(&dhd->rx_napi_dispatcher_work); - __skb_queue_purge(&dhd->rx_pend_queue); -#endif /* DHD_LB_RXP */ -#ifdef DHD_LB_TXP - cancel_work_sync(&dhd->tx_dispatcher_work); - tasklet_kill(&dhd->tx_tasklet); - __skb_queue_purge(&dhd->tx_pend_queue); -#endif /* DHD_LB_TXP */ -#ifdef DHD_LB_TXC - cancel_work_sync(&dhd->tx_compl_dispatcher_work); - tasklet_kill(&dhd->tx_compl_tasklet); -#endif /* DHD_LB_TXC */ -#ifdef DHD_LB_RXC - tasklet_kill(&dhd->rx_compl_tasklet); -#endif /* DHD_LB_RXC */ - - if (dhd->cpu_notifier.notifier_call != NULL) { - unregister_cpu_notifier(&dhd->cpu_notifier); - } - dhd_cpumasks_deinit(dhd); - DHD_LB_STATS_DEINIT(&dhd->pub); - } -#endif /* DHD_LB */ - - DHD_SSSR_MEMPOOL_DEINIT(&dhd->pub); - -#ifdef DHD_LOG_DUMP - dhd_log_dump_deinit(&dhd->pub); -#endif /* DHD_LOG_DUMP */ -#ifdef WL_CFG80211 - if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { - if (!cfg) { - DHD_ERROR(("cfg NULL!\n")); - ASSERT(0); - } else { - wl_cfg80211_detach(cfg); - dhd_monitor_uninit(); - } - } -#endif - -#ifdef DEBUGABILITY - if (dhdp->dbg) { -#ifdef DBG_PKT_MON - dhd_os_dbg_detach_pkt_monitor(dhdp); - dhd_os_spin_lock_deinit(dhd->pub.osh, dhd->pub.dbg->pkt_mon_lock); -#endif /* DBG_PKT_MON */ - dhd_os_dbg_detach(dhdp); - } -#endif /* DEBUGABILITY */ -#ifdef SHOW_LOGTRACE -#ifdef DHD_PKT_LOGGING - dhd_os_detach_pktlog(dhdp); -#endif /* DHD_PKT_LOGGING */ - /* Release the skbs from queue for WLC_E_TRACE event */ - dhd_event_logtrace_flush_queue(dhdp); - - if (dhd->dhd_state & DHD_ATTACH_LOGTRACE_INIT) { - if (dhd->event_data.fmts) { - MFREE(dhd->pub.osh, dhd->event_data.fmts, - dhd->event_data.fmts_size); - dhd->event_data.fmts = NULL; - } - if (dhd->event_data.raw_fmts) { - MFREE(dhd->pub.osh, dhd->event_data.raw_fmts, - dhd->event_data.raw_fmts_size); - dhd->event_data.raw_fmts = NULL; - } - if (dhd->event_data.raw_sstr) { - MFREE(dhd->pub.osh, dhd->event_data.raw_sstr, - dhd->event_data.raw_sstr_size); - dhd->event_data.raw_sstr = NULL; - } - if (dhd->event_data.rom_raw_sstr) { - MFREE(dhd->pub.osh, dhd->event_data.rom_raw_sstr, - dhd->event_data.rom_raw_sstr_size); - dhd->event_data.rom_raw_sstr = NULL; - } - dhd->dhd_state &= ~DHD_ATTACH_LOGTRACE_INIT; - } -#endif /* SHOW_LOGTRACE */ -#ifdef BCMPCIE - if (dhdp->extended_trap_data) - { - MFREE(dhdp->osh, dhdp->extended_trap_data, BCMPCIE_EXT_TRAP_DATA_MAXLEN); - dhdp->extended_trap_data = NULL; - } -#endif /* BCMPCIE */ -#ifdef PNO_SUPPORT - if (dhdp->pno_state) - dhd_pno_deinit(dhdp); -#endif -#ifdef RTT_SUPPORT - if (dhdp->rtt_state) { - dhd_rtt_deinit(dhdp); - } -#endif -#if defined(CONFIG_PM_SLEEP) - if (dhd_pm_notifier_registered) { - unregister_pm_notifier(&dhd->pm_notifier); - dhd_pm_notifier_registered = FALSE; - } -#endif /* CONFIG_PM_SLEEP */ - -#ifdef DEBUG_CPU_FREQ - if (dhd->new_freq) - free_percpu(dhd->new_freq); - dhd->new_freq = NULL; - cpufreq_unregister_notifier(&dhd->freq_trans, CPUFREQ_TRANSITION_NOTIFIER); -#endif - DHD_TRACE(("wd wakelock count:%d\n", dhd->wakelock_wd_counter)); -#ifdef CONFIG_HAS_WAKELOCK - dhd->wakelock_wd_counter = 0; - wake_lock_destroy(&dhd->wl_wdwake); - // terence 20161023: can not destroy wl_wifi when wlan down, it will happen null pointer in dhd_ioctl_entry - wake_lock_destroy(&dhd->wl_wifi); -#endif /* CONFIG_HAS_WAKELOCK */ - if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) { - DHD_OS_WAKE_LOCK_DESTROY(dhd); - } - - - -#ifdef DHDTCPACK_SUPPRESS - /* This will free all MEM allocated for TCPACK SUPPRESS */ - dhd_tcpack_suppress_set(&dhd->pub, TCPACK_SUP_OFF); -#endif /* DHDTCPACK_SUPPRESS */ - -#ifdef PCIE_FULL_DONGLE - dhd_flow_rings_deinit(dhdp); - if (dhdp->prot) - dhd_prot_detach(dhdp); -#endif - -#if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) - dhd_free_tdls_peer_list(dhdp); -#endif - -#ifdef HOFFLOAD_MODULES - hmem = &dhdp->hmem; - dhd_free_module_memory(dhdp->bus, hmem); -#endif /* HOFFLOAD_MODULES */ -#if defined(BT_OVER_SDIO) - mutex_destroy(&dhd->bus_user_lock); -#endif /* BT_OVER_SDIO */ -#ifdef DUMP_IOCTL_IOV_LIST - dhd_iov_li_delete(dhdp, &(dhdp->dump_iovlist_head)); -#endif /* DUMP_IOCTL_IOV_LIST */ -#ifdef DHD_DEBUG - /* memory waste feature list initilization */ - dhd_mw_list_delete(dhdp, &(dhdp->mw_list_head)); -#endif /* DHD_DEBUG */ -#ifdef WL_MONITOR - dhd_del_monitor_if(dhd, NULL, DHD_WQ_WORK_IF_DEL); -#endif /* WL_MONITOR */ - - /* Prefer adding de-init code above this comment unless necessary. - * The idea is to cancel work queue, sysfs and flags at the end. - */ - dhd_deferred_work_deinit(dhd->dhd_deferred_wq); - dhd->dhd_deferred_wq = NULL; - -#ifdef SHOW_LOGTRACE - /* Wait till event_log_dispatcher_work finishes */ - cancel_work_sync(&dhd->event_log_dispatcher_work); -#endif /* SHOW_LOGTRACE */ - - dhd->pub.fw_download_done = FALSE; - dhd_conf_detach(dhdp); -} - - -void -dhd_free(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (dhdp) { - int i; - for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) { - if (dhdp->reorder_bufs[i]) { - reorder_info_t *ptr; - uint32 buf_size = sizeof(struct reorder_info); - - ptr = dhdp->reorder_bufs[i]; - - buf_size += ((ptr->max_idx + 1) * sizeof(void*)); - DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n", - i, ptr->max_idx, buf_size)); - - MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size); - dhdp->reorder_bufs[i] = NULL; - } - } - - dhd_sta_pool_fini(dhdp, DHD_MAX_STA); - - dhd = (dhd_info_t *)dhdp->info; - if (dhdp->soc_ram) { -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) - DHD_OS_PREFREE(dhdp, dhdp->soc_ram, dhdp->soc_ram_length); -#else - MFREE(dhdp->osh, dhdp->soc_ram, dhdp->soc_ram_length); -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ - dhdp->soc_ram = NULL; - } -#ifdef CACHE_FW_IMAGES - if (dhdp->cached_fw) { - MFREE(dhdp->osh, dhdp->cached_fw, dhdp->bus->ramsize); - dhdp->cached_fw = NULL; - } - - if (dhdp->cached_nvram) { - MFREE(dhdp->osh, dhdp->cached_nvram, MAX_NVRAMBUF_SIZE); - dhdp->cached_nvram = NULL; - } -#endif - -#ifdef BCOL_TCPKA_SYNC -#if 0 - if (tcpka_sync.tcpka_iovbuf) { - MFREE(dhdp->osh, tcpka_sync.tcpka_iovbuf, tcpka_sync.tcpka_iovbuf_len); - tcpka_sync.tcpka_iovbuf = NULL; - } - - if (tcpka_sync.tcpka_en_info) { - MFREE(dhdp->osh, tcpka_sync.tcpka_en_info, sizeof(tcpka_conn_sess_t)); - tcpka_sync.tcpka_en_info = NULL; - } - - if (tcpka_sync.tcpka_act_buf) { - MFREE(dhdp->osh, tcpka_sync.tcpka_act_buf, - tcpka_sync.tcpka_act_buf_len); - tcpka_sync.tcpka_act_buf = NULL; - } - - if (tcpka_sync.tcpka_noti_buf) { - MFREE(dhdp->osh, tcpka_sync.tcpka_noti_buf, - tcpka_sync.tcpka_noti_buf_len); - tcpka_sync.tcpka_noti_buf = NULL; - } -#endif -#endif /* BCOL_TCPKA_SYNC */ - - if (dhd) { -#ifdef REPORT_FATAL_TIMEOUTS - deinit_dhd_timeouts(&dhd->pub); -#endif /* REPORT_FATAL_TIMEOUTS */ - - /* If pointer is allocated by dhd_os_prealloc then avoid MFREE */ - if (dhd != (dhd_info_t *)dhd_os_prealloc(dhdp, - DHD_PREALLOC_DHD_INFO, 0, FALSE)) - MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); - dhd = NULL; - } - } -} - -void -dhd_clear(dhd_pub_t *dhdp) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (dhdp) { - int i; -#ifdef DHDTCPACK_SUPPRESS - /* Clean up timer/data structure for any remaining/pending packet or timer. */ - dhd_tcpack_info_tbl_clean(dhdp); -#endif /* DHDTCPACK_SUPPRESS */ - for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) { - if (dhdp->reorder_bufs[i]) { - reorder_info_t *ptr; - uint32 buf_size = sizeof(struct reorder_info); - - ptr = dhdp->reorder_bufs[i]; - - buf_size += ((ptr->max_idx + 1) * sizeof(void*)); - DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n", - i, ptr->max_idx, buf_size)); - - MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size); - dhdp->reorder_bufs[i] = NULL; - } - } - - dhd_sta_pool_clear(dhdp, DHD_MAX_STA); - - if (dhdp->soc_ram) { -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) - DHD_OS_PREFREE(dhdp, dhdp->soc_ram, dhdp->soc_ram_length); -#else - MFREE(dhdp->osh, dhdp->soc_ram, dhdp->soc_ram_length); -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ - dhdp->soc_ram = NULL; - } - } -} - -static void -dhd_module_cleanup(void) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - dhd_bus_unregister(); - - wl_android_exit(); - - dhd_wifi_platform_unregister_drv(); - DHD_TRACE(("%s: Exit\n", __FUNCTION__)); -} - -static void -dhd_module_exit_work(void) -{ - atomic_set(&exit_in_progress, 1); - dhd_module_cleanup(); - unregister_reboot_notifier(&dhd_reboot_notifier); - dhd_destroy_to_notifier_skt(); - atomic_set(&exit_in_progress, 0); -} - -static void __exit -dhd_module_exit(void) -{ - dhd_module_exit_work(); - dhd_sysfs_exit(&dhd_sysfs_kobj); - mutex_destroy(&dhd_drv_action_lock); -} - -static int -dhd_module_init_work(void) -{ - int err; - int retry = POWERUP_MAX_RETRY; - - DHD_ERROR(("%s: in %s\n", __FUNCTION__, dhd_version)); - - DHD_PERIM_RADIO_INIT(); - - - if (firmware_path[0] != '\0') { - strncpy(fw_bak_path, firmware_path, MOD_PARAM_PATHLEN); - fw_bak_path[MOD_PARAM_PATHLEN-1] = '\0'; - } - - if (nvram_path[0] != '\0') { - strncpy(nv_bak_path, nvram_path, MOD_PARAM_PATHLEN); - nv_bak_path[MOD_PARAM_PATHLEN-1] = '\0'; - } - - do { - err = dhd_wifi_platform_register_drv(); - if (!err) { - register_reboot_notifier(&dhd_reboot_notifier); - break; - } else { - DHD_ERROR(("%s: Failed to load the driver, try cnt %d\n", - __FUNCTION__, retry)); - strncpy(firmware_path, fw_bak_path, MOD_PARAM_PATHLEN); - firmware_path[MOD_PARAM_PATHLEN-1] = '\0'; - strncpy(nvram_path, nv_bak_path, MOD_PARAM_PATHLEN); - nvram_path[MOD_PARAM_PATHLEN-1] = '\0'; - } - } while (retry--); - - dhd_create_to_notifier_skt(); - - if (err) { - DHD_ERROR(("%s: Failed to load driver max retry reached**\n", __FUNCTION__)); - } else { - if (!dhd_download_fw_on_driverload) { - dhd_driver_init_done = TRUE; - } - } - - DHD_ERROR(("%s: Exit err=%d\n", __FUNCTION__, err)); - return err; -} - -static char *get_dhd_drv_state_str(int state) -{ - switch (state) { - case DHD_DRIVER_STATE_DOWN: - return "DOWN"; - case DHD_DRIVER_STATE_WARM_PARTIAL: - return "WARM_PARTIAL"; - case DHD_DRIVER_STATE_WARM: - return "WARM"; - case DHD_DRIVER_STATE_COMPLETE: - return "COMPLETE"; - case DHD_DRIVER_STATE_ISOLATED: - return "ISOLATED"; - case DHD_DRIVER_STATE_PENDING_WAKE: - return "PENDING_WAKE"; - case DHD_DRIVER_STATE_HANGED: - return "HANGED"; - case DHD_DRIVER_STATE_BUS: - return "BUS"; - } - return "UNKNOWN"; -} - -int dhd_get_driver_state(void) -{ - return atomic_read(&dhd_drv_state); -} - -bool dhd_driver_in_hang_state(void) -{ - return ((atomic_read(&dhd_drv_state) == DHD_DRIVER_STATE_HANGED) ? 1 : 0); -} - -static void dhd_change_driver_state(int new_state) -{ - int state = dhd_get_driver_state(); - - if (state == new_state) - return; - - DHD_ERROR(("%s: %s -> %s", __func__, - get_dhd_drv_state_str(state), - get_dhd_drv_state_str(new_state))); - - atomic_set(&dhd_drv_state, new_state); - -#ifdef TCPKA_REPAIR - if (new_state == DHD_DRIVER_STATE_COMPLETE && - g_dhd_pub != NULL) { - dhd_pub_t *dhdp = g_dhd_pub; - tcpka_sync.tcpka_rp.block_tcpka_timeout = dhdp->conf->tcpka_repair_timeout; - if (tcpka_sync.tcpka_rp.block_tcpka && tcpka_sync.tcpka_rp.pkt_in_q_num > 0 && - tcpka_sync.tcpka_rp.block_tcpka_timeout > 0) { - uint32 passed_time = OSL_SYSUPTIME() - tcpka_sync.tcpka_rp.block_tcpka_start_time; - uint32 timeout_time = tcpka_sync.tcpka_rp.block_tcpka_timeout * 1000; - if (passed_time < timeout_time) { - uint32 left_time = timeout_time - passed_time; - DHD_ERROR(("[TCP RP] release packets after %d.%d(%d) sec\n", - left_time / 1000, left_time % 1000, - tcpka_sync.tcpka_rp.block_tcpka_timeout)); - mod_timer(&dhdp->info->tcpka_rp_timer, - jiffies + msecs_to_jiffies(left_time)); - } else { - dhd_tcpka_repair_pkt_sendup(dhdp); - } - } - } -#endif /* TCPKA_REPAIR */ -} - -#ifdef DHD_DEBUG -extern int dhdsdio_readconsole(void *bus); -#endif - -static bool gNeedStartBus = TRUE; - -static int __init -dhd_module_init(void) -{ -#ifdef DHD_BUILTIN - if (load_mode) { - if (!strcmp(load_mode, "cold")) { - dhd_load_mode = DHD_LOAD_MODE_COLD; - } else if (!strcmp(load_mode, "partial_warm")) { - dhd_load_mode = DHD_LOAD_MODE_PARTIAL; - } else if (!strcmp(load_mode, "warm")) { - dhd_load_mode = DHD_LOAD_MODE_WARM; - } else { - DHD_ERROR(("%s: unknown load_mode %s\n", __func__, load_mode)); - } - } else { - DHD_ERROR(("%s: load_mode not pass in\n", __func__)); - } - DHD_ERROR(("%s: dhd_load_mode %d\n", __func__, dhd_load_mode)); - - mutex_init(&dhd_drv_action_lock); - dhd_sysfs_init(&dhd_sysfs_kobj); - - memset(&g_wstats, 0, sizeof(g_wstats)); - - gNeedStartBus = TRUE; - dhd_change_driver_state(dhd_load_mode); - return 0; -#else - mutex_init(&dhd_drv_action_lock); - dhd_sysfs_init(&dhd_sysfs_kobj); - return dhd_module_init_work(); -#endif /* DHD_BUILTIN */ -} - -static int -dhd_reboot_callback(struct notifier_block *this, unsigned long code, void *unused) -{ - DHD_TRACE(("%s: code = %ld\n", __FUNCTION__, code)); - if (code == SYS_RESTART) { -#ifdef BCMPCIE - is_reboot = code; -#endif /* BCMPCIE */ - } - return NOTIFY_DONE; -} - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -#if defined(CONFIG_DEFERRED_INITCALLS) && !defined(EXYNOS_PCIE_MODULE_PATCH) -#if defined(CONFIG_MACH_UNIVERSAL7420) || defined(CONFIG_SOC_EXYNOS8890) || \ - defined(CONFIG_ARCH_MSM8996) || defined(CONFIG_SOC_EXYNOS8895) || \ - defined(CONFIG_ARCH_MSM8998) -deferred_module_init_sync(dhd_module_init); -#else -deferred_module_init(dhd_module_init); -#endif /* CONFIG_MACH_UNIVERSAL7420 || CONFIG_SOC_EXYNOS8890 || - * CONFIG_ARCH_MSM8996 || CONFIG_SOC_EXYNOS8895 || CONFIG_ARCH_MSM8998 - */ -#elif defined(USE_LATE_INITCALL_SYNC) -late_initcall_sync(dhd_module_init); -#else -late_initcall(dhd_module_init); -#endif /* USE_LATE_INITCALL_SYNC */ -#else -module_init(dhd_module_init); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ - -module_exit(dhd_module_exit); - -/* - * OS specific functions required to implement DHD driver in OS independent way - */ -int -dhd_os_proto_block(dhd_pub_t *pub) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - DHD_PERIM_UNLOCK(pub); - - down(&dhd->proto_sem); - - DHD_PERIM_LOCK(pub); - return 1; - } - - return 0; -} - -int -dhd_os_proto_unblock(dhd_pub_t *pub) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - up(&dhd->proto_sem); - return 1; - } - - return 0; -} - -void -dhd_os_dhdiovar_lock(dhd_pub_t *pub) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - mutex_lock(&dhd->dhd_iovar_mutex); - } -} - -void -dhd_os_dhdiovar_unlock(dhd_pub_t *pub) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - mutex_unlock(&dhd->dhd_iovar_mutex); - } -} - -unsigned int -dhd_os_get_ioctl_resp_timeout(void) -{ - return ((unsigned int)dhd_ioctl_timeout_msec); -} - -void -dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec) -{ - dhd_ioctl_timeout_msec = (int)timeout_msec; -} - -int -dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool resched) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - int timeout, timeout_tmp = dhd_ioctl_timeout_msec; - - if (!resched && pub->conf->ctrl_resched>0 && pub->conf->dhd_ioctl_timeout_msec>0) { - timeout_tmp = dhd_ioctl_timeout_msec; - dhd_ioctl_timeout_msec = pub->conf->dhd_ioctl_timeout_msec; - } - - /* Convert timeout in millsecond to jiffies */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); -#else - timeout = dhd_ioctl_timeout_msec * HZ / 1000; -#endif - - DHD_PERIM_UNLOCK(pub); - - timeout = wait_event_timeout(dhd->ioctl_resp_wait, (*condition), timeout); - - if (!resched && pub->conf->ctrl_resched>0 && pub->conf->dhd_ioctl_timeout_msec>0) { - dhd_ioctl_timeout_msec = timeout_tmp; - } - - DHD_PERIM_LOCK(pub); - - return timeout; -} - -int -dhd_os_ioctl_resp_wake(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - wake_up(&dhd->ioctl_resp_wait); - return 0; -} - -int -dhd_os_d3ack_wait(dhd_pub_t *pub, uint *condition) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - int timeout; - - /* Convert timeout in millsecond to jiffies */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - timeout = msecs_to_jiffies(dhd_ioctl_timeout_msec); -#else - timeout = dhd_ioctl_timeout_msec * HZ / 1000; -#endif - - DHD_PERIM_UNLOCK(pub); - - timeout = wait_event_timeout(dhd->d3ack_wait, (*condition), timeout); - - DHD_PERIM_LOCK(pub); - - return timeout; -} - -#ifdef PCIE_INB_DW -int -dhd_os_ds_exit_wait(dhd_pub_t *pub, uint *condition) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - int timeout; - - /* Convert timeout in millsecond to jiffies */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - timeout = msecs_to_jiffies(ds_exit_timeout_msec); -#else - timeout = ds_exit_timeout_msec * HZ / 1000; -#endif - - DHD_PERIM_UNLOCK(pub); - - timeout = wait_event_timeout(dhd->ds_exit_wait, (*condition), timeout); - - DHD_PERIM_LOCK(pub); - - return timeout; -} - -int -dhd_os_ds_exit_wake(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - wake_up(&dhd->ds_exit_wait); - return 0; -} - -#endif /* PCIE_INB_DW */ - -int -dhd_os_d3ack_wake(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - wake_up(&dhd->d3ack_wait); - return 0; -} - -int -dhd_os_busbusy_wait_negation(dhd_pub_t *pub, uint *condition) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - int timeout; - - /* Wait for bus usage contexts to gracefully exit within some timeout value - * Set time out to little higher than dhd_ioctl_timeout_msec, - * so that IOCTL timeout should not get affected. - */ - /* Convert timeout in millsecond to jiffies */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - timeout = msecs_to_jiffies(DHD_BUS_BUSY_TIMEOUT); -#else - timeout = DHD_BUS_BUSY_TIMEOUT * HZ / 1000; -#endif - - timeout = wait_event_timeout(dhd->dhd_bus_busy_state_wait, !(*condition), timeout); - - return timeout; -} - -/* - * Wait until the condition *var == condition is met. - * Returns 0 if the @condition evaluated to false after the timeout elapsed - * Returns 1 if the @condition evaluated to true - */ -int -dhd_os_busbusy_wait_condition(dhd_pub_t *pub, uint *var, uint condition) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - int timeout; - - /* Convert timeout in millsecond to jiffies */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - timeout = msecs_to_jiffies(DHD_BUS_BUSY_TIMEOUT); -#else - timeout = DHD_BUS_BUSY_TIMEOUT * HZ / 1000; -#endif - - timeout = wait_event_timeout(dhd->dhd_bus_busy_state_wait, (*var == condition), timeout); - - return timeout; -} - - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)) -/* Fix compilation error for FC11 */ -INLINE -#endif -int -dhd_os_busbusy_wake(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - /* Call wmb() to make sure before waking up the other event value gets updated */ - OSL_SMP_WMB(); - wake_up(&dhd->dhd_bus_busy_state_wait); - return 0; -} - -void -dhd_os_wd_timer_extend(void *bus, bool extend) -{ -#ifndef BCMDBUS - dhd_pub_t *pub = bus; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - - if (extend) - dhd_os_wd_timer(bus, WATCHDOG_EXTEND_INTERVAL); - else - dhd_os_wd_timer(bus, dhd->default_wd_interval); -#endif /* !BCMDBUS */ -} - - -void -dhd_os_wd_timer(void *bus, uint wdtick) -{ -#ifndef BCMDBUS - dhd_pub_t *pub = bus; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - unsigned long flags; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!dhd) { - DHD_ERROR(("%s: dhd NULL\n", __FUNCTION__)); - return; - } - - DHD_GENERAL_LOCK(pub, flags); - - /* don't start the wd until fw is loaded */ - if (pub->busstate == DHD_BUS_DOWN) { - DHD_GENERAL_UNLOCK(pub, flags); - return; - } - - /* Totally stop the timer */ - if (!wdtick && dhd->wd_timer_valid == TRUE) { - dhd->wd_timer_valid = FALSE; - DHD_GENERAL_UNLOCK(pub, flags); - del_timer_sync(&dhd->timer); - return; - } - - if (wdtick) { - dhd_watchdog_ms = (uint)wdtick; - /* Re arm the timer, at last watchdog period */ - mod_timer(&dhd->timer, jiffies + msecs_to_jiffies(dhd_watchdog_ms)); - dhd->wd_timer_valid = TRUE; - } - DHD_GENERAL_UNLOCK(pub, flags); -#endif /* !BCMDBUS */ -} - -#ifdef DHD_PCIE_RUNTIMEPM -void -dhd_os_runtimepm_timer(void *bus, uint tick) -{ - dhd_pub_t *pub = bus; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - unsigned long flags; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!dhd) { - DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); - return; - } - - DHD_GENERAL_LOCK(pub, flags); - - /* don't start the RPM until fw is loaded */ - if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(pub)) { - DHD_GENERAL_UNLOCK(pub, flags); - return; - } - - /* If tick is non-zero, the request is to start the timer */ - if (tick) { - /* Start the timer only if its not already running */ - if (dhd->rpm_timer_valid == FALSE) { - mod_timer(&dhd->rpm_timer, jiffies + msecs_to_jiffies(dhd_runtimepm_ms)); - dhd->rpm_timer_valid = TRUE; - } - } else { - /* tick is zero, we have to stop the timer */ - /* Stop the timer only if its running, otherwise we don't have to do anything */ - if (dhd->rpm_timer_valid == TRUE) { - dhd->rpm_timer_valid = FALSE; - DHD_GENERAL_UNLOCK(pub, flags); - del_timer_sync(&dhd->rpm_timer); - /* we have already released the lock, so just go to exit */ - goto exit; - } - } - - DHD_GENERAL_UNLOCK(pub, flags); -exit: - return; - -} - -#endif /* DHD_PCIE_RUNTIMEPM */ - -void * -dhd_os_open_image(char *filename) -{ - struct file *fp; - int size; - - fp = filp_open(filename, O_RDONLY, 0); - /* - * 2.6.11 (FC4) supports filp_open() but later revs don't? - * Alternative: - * fp = open_namei(AT_FDCWD, filename, O_RD, 0); - * ??? - */ - if (IS_ERR(fp)) { - fp = NULL; - goto err; - } - - if (!S_ISREG(file_inode(fp)->i_mode)) { - DHD_ERROR(("%s: %s is not regular file\n", __FUNCTION__, filename)); - fp = NULL; - goto err; - } - - size = i_size_read(file_inode(fp)); - if (size <= 0) { - DHD_ERROR(("%s: %s file size invalid %d\n", __FUNCTION__, filename, size)); - fp = NULL; - goto err; - } - - DHD_INFO(("%s: %s (%d bytes) open success\n", __FUNCTION__, filename, size)); - -err: - return fp; -} - -int -dhd_os_get_image_block(char *buf, int len, void *image) -{ - struct file *fp = (struct file *)image; - int rdlen; - int size; - - if (!image) { - return 0; - } - - size = i_size_read(file_inode(fp)); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) - rdlen = kernel_read(fp, buf, MIN(len, size), &fp->f_pos); -#else - rdlen = kernel_read(fp, fp->f_pos, buf, MIN(len, size)); -#endif - - if (len >= size && size != rdlen) { - return -EIO; - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) - if (rdlen > 0) { - fp->f_pos += rdlen; - } -#endif - - return rdlen; -} - -int -dhd_os_get_image_size(void *image) -{ - struct file *fp = (struct file *)image; - int size; - if (!image) { - return 0; - } - - size = i_size_read(file_inode(fp)); - - return size; -} - -#if defined(BT_OVER_SDIO) -int -dhd_os_gets_image(dhd_pub_t *pub, char *str, int len, void *image) -{ - struct file *fp = (struct file *)image; - int rd_len; - uint str_len = 0; - char *str_end = NULL; - - if (!image) - return 0; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) - rd_len = kernel_read(fp, str, len, &fp->f_pos); -#else - rd_len = kernel_read(fp, fp->f_pos, str, len); -#endif - str_end = strnchr(str, len, '\n'); - if (str_end == NULL) { - goto err; - } - str_len = (uint)(str_end - str); - - /* Advance file pointer past the string length */ - fp->f_pos += str_len + 1; - bzero(str_end, rd_len - str_len); - -err: - return str_len; -} -#endif /* defined (BT_OVER_SDIO) */ - - -void -dhd_os_close_image(void *image) -{ - if (image) - filp_close((struct file *)image, NULL); -} - -void -dhd_os_sdlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - -#ifdef BCMDBUS - spin_lock_bh(&dhd->sdlock); -#else - if (dhd_dpc_prio >= 0) - down(&dhd->sdsem); - else - spin_lock_bh(&dhd->sdlock); -#endif /* !BCMDBUS */ -} - -void -dhd_os_sdunlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - -#ifdef BCMDBUS - spin_unlock_bh(&dhd->sdlock); -#else - if (dhd_dpc_prio >= 0) - up(&dhd->sdsem); - else - spin_unlock_bh(&dhd->sdlock); -#endif /* !BCMDBUS */ -} - -void -dhd_os_sdlock_txq(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); -#ifdef BCMDBUS - spin_lock_irqsave(&dhd->txqlock, dhd->txqlock_flags); -#else - spin_lock_bh(&dhd->txqlock); -#endif /* BCMDBUS */ -} - -void -dhd_os_sdunlock_txq(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); -#ifdef BCMDBUS - spin_unlock_irqrestore(&dhd->txqlock, dhd->txqlock_flags); -#else - spin_unlock_bh(&dhd->txqlock); -#endif /* BCMDBUS */ -} - -void -dhd_os_sdlock_rxq(dhd_pub_t *pub) -{ -#if 0 - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_lock_bh(&dhd->rxqlock); -#endif -} - -void -dhd_os_sdunlock_rxq(dhd_pub_t *pub) -{ -#if 0 - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_unlock_bh(&dhd->rxqlock); -#endif -} - -static void -dhd_os_rxflock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_lock_bh(&dhd->rxf_lock); - -} - -static void -dhd_os_rxfunlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_unlock_bh(&dhd->rxf_lock); -} - -#ifdef DHDTCPACK_SUPPRESS -unsigned long -dhd_os_tcpacklock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - unsigned long flags = 0; - - dhd = (dhd_info_t *)(pub->info); - - if (dhd) { -#ifdef BCMSDIO - spin_lock_bh(&dhd->tcpack_lock); -#else - spin_lock_irqsave(&dhd->tcpack_lock, flags); -#endif /* BCMSDIO */ - } - - return flags; -} - -void -dhd_os_tcpackunlock(dhd_pub_t *pub, unsigned long flags) -{ - dhd_info_t *dhd; - -#ifdef BCMSDIO - BCM_REFERENCE(flags); -#endif /* BCMSDIO */ - - dhd = (dhd_info_t *)(pub->info); - - if (dhd) { -#ifdef BCMSDIO - spin_unlock_bh(&dhd->tcpack_lock); -#else - spin_unlock_irqrestore(&dhd->tcpack_lock, flags); -#endif /* BCMSDIO */ - } -} -#endif /* DHDTCPACK_SUPPRESS */ - -uint8* dhd_os_prealloc(dhd_pub_t *dhdpub, int section, uint size, bool kmalloc_if_fail) -{ - uint8* buf; - gfp_t flags = CAN_SLEEP() ? GFP_KERNEL: GFP_ATOMIC; - - buf = (uint8*)wifi_platform_prealloc(dhdpub->info->adapter, section, size); - if (buf == NULL && kmalloc_if_fail) - buf = kmalloc(size, flags); - - return buf; -} - -void dhd_os_prefree(dhd_pub_t *dhdpub, void *addr, uint size) -{ -} - -#if defined(WL_WIRELESS_EXT) -struct iw_statistics * -dhd_get_wireless_stats(struct net_device *dev) -{ - int res = 0; - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (!dhd->pub.up) { - return NULL; - } - - res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats); - - if (res == 0) - return &dhd->iw.wstats; - else - return NULL; -} -#endif /* defined(WL_WIRELESS_EXT) */ - -static int -dhd_wl_host_event(dhd_info_t *dhd, int ifidx, void *pktdata, uint16 pktlen, - wl_event_msg_t *event, void **data) -{ - int bcmerror = 0; -#ifdef WL_CFG80211 - unsigned long flags = 0; -#endif /* WL_CFG80211 */ - ASSERT(dhd != NULL); - -#ifdef SHOW_LOGTRACE - bcmerror = wl_process_host_event(&dhd->pub, &ifidx, pktdata, pktlen, event, data, - &dhd->event_data); -#else - bcmerror = wl_process_host_event(&dhd->pub, &ifidx, pktdata, pktlen, event, data, - NULL); -#endif /* SHOW_LOGTRACE */ - - if (bcmerror != BCME_OK) - return (bcmerror); - -#if defined(WL_EXT_IAPSTA) - wl_ext_iapsta_event(dhd->iflist[ifidx]->net, event, *data); -#endif /* defined(WL_EXT_IAPSTA) */ -#if defined(WL_WIRELESS_EXT) - if (event->bsscfgidx == 0) { - /* - * Wireless ext is on primary interface only - */ - - ASSERT(dhd->iflist[ifidx] != NULL); - ASSERT(dhd->iflist[ifidx]->net != NULL); - - if (dhd->iflist[ifidx]->net) { - wl_iw_event(dhd->iflist[ifidx]->net, event, *data); - } - } -#endif /* defined(WL_WIRELESS_EXT) */ - -#ifdef WL_CFG80211 - ASSERT(dhd->iflist[ifidx] != NULL); - ASSERT(dhd->iflist[ifidx]->net != NULL); - if (dhd->iflist[ifidx]->net) { - spin_lock_irqsave(&dhd->pub.up_lock, flags); - if (dhd->pub.up) { - wl_cfg80211_event(dhd->iflist[ifidx]->net, event, *data); - } - spin_unlock_irqrestore(&dhd->pub.up_lock, flags); - } -#endif /* defined(WL_CFG80211) */ - - return (bcmerror); -} - -/* send up locally generated event */ -void -dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) -{ - /* Just return from here */ - return; -} - -#ifdef LOG_INTO_TCPDUMP -void -dhd_sendup_log(dhd_pub_t *dhdp, void *data, int data_len) -{ - struct sk_buff *p, *skb; - uint32 pktlen; - int len; - dhd_if_t *ifp; - dhd_info_t *dhd; - uchar *skb_data; - int ifidx = 0; - struct ether_header eth; - - pktlen = sizeof(eth) + data_len; - dhd = dhdp->info; - - if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) { - ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32))); - - bcopy(&dhdp->mac, ð.ether_dhost, ETHER_ADDR_LEN); - bcopy(&dhdp->mac, ð.ether_shost, ETHER_ADDR_LEN); - ETHER_TOGGLE_LOCALADDR(ð.ether_shost); - eth.ether_type = hton16(ETHER_TYPE_BRCM); - - bcopy((void *)ð, PKTDATA(dhdp->osh, p), sizeof(eth)); - bcopy(data, PKTDATA(dhdp->osh, p) + sizeof(eth), data_len); - skb = PKTTONATIVE(dhdp->osh, p); - skb_data = skb->data; - len = skb->len; - - ifidx = dhd_ifname2idx(dhd, "wlan0"); - ifp = dhd->iflist[ifidx]; - if (ifp == NULL) - ifp = dhd->iflist[0]; - - ASSERT(ifp); - skb->dev = ifp->net; - skb->protocol = eth_type_trans(skb, skb->dev); - skb->data = skb_data; - skb->len = len; - - /* Strip header, count, deliver upward */ - skb_pull(skb, ETH_HLEN); - - bcm_object_trace_opr(skb, BCM_OBJDBG_REMOVE, - __FUNCTION__, __LINE__); - /* Send the packet */ - if (in_interrupt()) { - netif_rx(skb); - } else { - netif_rx_ni(skb); - } - } else { - /* Could not allocate a sk_buf */ - DHD_ERROR(("%s: unable to alloc sk_buf\n", __FUNCTION__)); - } -} -#endif /* LOG_INTO_TCPDUMP */ - -void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) -{ -#if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - struct dhd_info *dhdinfo = dhd->info; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - int timeout = msecs_to_jiffies(IOCTL_RESP_TIMEOUT); -#else - int timeout = (IOCTL_RESP_TIMEOUT / 1000) * HZ; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ - - dhd_os_sdunlock(dhd); - wait_event_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), timeout); - dhd_os_sdlock(dhd); -#endif /* defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) */ - return; -} - -void dhd_wait_event_wakeup(dhd_pub_t *dhd) -{ -#if defined(BCMSDIO) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - struct dhd_info *dhdinfo = dhd->info; - if (waitqueue_active(&dhdinfo->ctrl_wait)) - wake_up(&dhdinfo->ctrl_wait); -#endif - return; -} - -#if defined(BCMSDIO) || defined(BCMPCIE) || defined(BCMDBUS) -int -dhd_net_bus_devreset(struct net_device *dev, uint8 flag) -{ - int ret; - - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (flag == TRUE) { - /* Issue wl down command before resetting the chip */ - if (dhd_wl_ioctl_cmd(&dhd->pub, WLC_DOWN, NULL, 0, TRUE, 0) < 0) { - DHD_TRACE(("%s: wl down failed\n", __FUNCTION__)); - } -#ifdef PROP_TXSTATUS - if (dhd->pub.wlfc_enabled) { - dhd_wlfc_deinit(&dhd->pub); - } -#endif /* PROP_TXSTATUS */ -#ifdef PNO_SUPPORT - if (dhd->pub.pno_state) { - dhd_pno_deinit(&dhd->pub); - } -#endif -#ifdef RTT_SUPPORT - if (dhd->pub.rtt_state) { - dhd_rtt_deinit(&dhd->pub); - } -#endif /* RTT_SUPPORT */ - -#if defined(DBG_PKT_MON) && !defined(DBG_PKT_MON_INIT_DEFAULT) - dhd_os_dbg_detach_pkt_monitor(&dhd->pub); -#endif /* DBG_PKT_MON */ - } - -#ifdef BCMSDIO - if (!flag) { - dhd_update_fw_nv_path(dhd); - /* update firmware and nvram path to sdio bus */ - dhd_bus_update_fw_nv_path(dhd->pub.bus, - dhd->fw_path, dhd->nv_path, dhd->clm_path, - dhd->conf_path, dhd->reg_path); - } -#endif /* BCMSDIO */ - - ret = dhd_bus_devreset(&dhd->pub, flag); - if (ret) { - DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret)); - return ret; - } - - return ret; -} - -#ifdef BCMSDIO -int -dhd_net_bus_suspend(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - return dhd_bus_suspend(&dhd->pub); -} - -int -dhd_net_bus_resume(struct net_device *dev, uint8 stage) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - return dhd_bus_resume(&dhd->pub, stage); -} - -#endif /* BCMSDIO */ -#endif /* BCMSDIO || BCMPCIE || BCMDBUS */ - -int net_os_set_suspend_disable(struct net_device *dev, int val) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - - if (dhd) { - ret = dhd->pub.suspend_disable_flag; - dhd->pub.suspend_disable_flag = val; - } - return ret; -} - -int net_os_set_suspend(struct net_device *dev, int val, int force) -{ - int ret = 0; - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (dhd) { -#ifdef CONFIG_MACH_UNIVERSAL7420 -#endif /* CONFIG_MACH_UNIVERSAL7420 */ -#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) - ret = dhd_set_suspend(val, &dhd->pub); -#else - ret = dhd_suspend_resume_helper(dhd, val, force); -#endif -#ifdef WL_CFG80211 - wl_cfg80211_update_power_mode(dev); -#endif - } - return ret; -} - -int net_os_set_suspend_bcn_li_dtim(struct net_device *dev, int val) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (dhd) - dhd->pub.suspend_bcn_li_dtim = val; - - return 0; -} - -int net_os_set_max_dtim_enable(struct net_device *dev, int val) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (dhd) { - DHD_ERROR(("%s: use MAX bcn_li_dtim in suspend %s\n", - __FUNCTION__, (val ? "Enable" : "Disable"))); - if (val) { - dhd->pub.max_dtim_enable = TRUE; - } else { - dhd->pub.max_dtim_enable = FALSE; - } - } else { - return -1; - } - - return 0; -} - -#ifdef PKT_FILTER_SUPPORT -int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) -{ - int ret = 0; - -#ifndef GAN_LITE_NAT_KEEPALIVE_FILTER - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (!dhd_master_mode) - add_remove = !add_remove; - DHD_ERROR(("%s: add_remove = %d, num = %d\n", __FUNCTION__, add_remove, num)); - if (!dhd || (num == DHD_UNICAST_FILTER_NUM)) { - return 0; - } - - - if (num >= dhd->pub.pktfilter_count) { - return -EINVAL; - } - - ret = dhd_packet_filter_add_remove(&dhd->pub, add_remove, num); -#endif /* !GAN_LITE_NAT_KEEPALIVE_FILTER */ - - return ret; -} - -int dhd_os_enable_packet_filter(dhd_pub_t *dhdp, int val) - -{ - int ret = 0; - - /* Packet filtering is set only if we still in early-suspend and - * we need either to turn it ON or turn it OFF - * We can always turn it OFF in case of early-suspend, but we turn it - * back ON only if suspend_disable_flag was not set - */ - if (dhdp && dhdp->up) { - if (dhdp->in_suspend) { - if (!val || (val && !dhdp->suspend_disable_flag)) - dhd_enable_packet_filter(val, dhdp); - } - } - return ret; -} - -/* function to enable/disable packet for Network device */ -int net_os_enable_packet_filter(struct net_device *dev, int val) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - DHD_ERROR(("%s: val = %d\n", __FUNCTION__, val)); - return dhd_os_enable_packet_filter(&dhd->pub, val); -} -#endif /* PKT_FILTER_SUPPORT */ - -int -dhd_dev_init_ioctl(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret; - - if ((ret = dhd_sync_with_dongle(&dhd->pub)) < 0) - goto done; - -done: - return ret; -} - -#ifdef IDSUP_STATS -char *dhd_get_wpa_state_str(wifi_wpa_state_t state) { - switch (state) { - case WIFI_WPA_STATE_DISCONNECTED: - return "DISCONNECTED"; - case WIFI_WPA_STATE_INTERFACE_DISABLED: - return "INTERFACE_DISABLED"; - case WIFI_WPA_STATE_INACTIVE: - return "INACTIVE"; - case WIFI_WPA_STATE_SCANNING: - return "SCANNING"; - case WIFI_WPA_STATE_AUTHENTICATING: - return "AUTHENTICATING"; - case WIFI_WPA_STATE_ASSOCIATING: - return "ASSOCIATING"; - case WIFI_WPA_STATE_ASSOCIATED: - return "ASSOCIATED"; - case WIFI_WPA_STATE_4WAY_HANDSHAKE: - return "4WAY_HANDSHAKE"; - case WIFI_WPA_STATE_GROUP_HANDSHAKE: - return "GROUP_HANDSHAKE"; - case WIFI_WPA_STATE_COMPLETED: - return "COMPLETED"; - - default: - return "UNKNOWN"; - } -} - -wifi_wpa_state_t dhd_dev_get_wpa_state(struct net_device *dev) -{ - dhd_info_t *ptr = *(dhd_info_t **)netdev_priv(dev); - dhd_pub_t *dhd = (&ptr->pub); - uint32 wpa_state = 0; - - if (!(dev->flags & IFF_UP)) - return WIFI_WPA_STATE_INTERFACE_DISABLED; - - if (dhd_wl_ioctl_get_intiovar(dhd, "wpa_state", &wpa_state, - WLC_GET_VAR, FALSE, 0) != BCME_OK) { - DHD_ERROR(("failed to get wpa_state\n")); - } - - return wpa_state; -} - -bool dhd_dev_wpa_was_completed(struct net_device *dev) -{ - dhd_info_t *ptr = *(dhd_info_t **)netdev_priv(dev); - dhd_pub_t *dhd = (&ptr->pub); - int complete = FALSE; - - if (dhd_wl_ioctl_get_intiovar(dhd, "wpa_was_completed", &complete, - WLC_GET_VAR, FALSE, 0) != BCME_OK) { - DHD_ERROR(("failed to get wpa_was_completed\n")); - } - - return complete; -} - -#endif /* IDSUP_STATS */ - -int -dhd_dev_get_feature_set(struct net_device *dev) -{ - dhd_info_t *ptr = *(dhd_info_t **)netdev_priv(dev); - dhd_pub_t *dhd = (&ptr->pub); - int feature_set = 0; - - if (FW_SUPPORTED(dhd, sta)) - feature_set |= WIFI_FEATURE_INFRA; - if (FW_SUPPORTED(dhd, dualband)) - feature_set |= WIFI_FEATURE_INFRA_5G; - if (FW_SUPPORTED(dhd, p2p)) - feature_set |= WIFI_FEATURE_P2P; - if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) - feature_set |= WIFI_FEATURE_SOFT_AP; - if (FW_SUPPORTED(dhd, tdls)) - feature_set |= WIFI_FEATURE_TDLS; - if (FW_SUPPORTED(dhd, vsdb)) - feature_set |= WIFI_FEATURE_TDLS_OFFCHANNEL; - if (FW_SUPPORTED(dhd, nan)) { - feature_set |= WIFI_FEATURE_NAN; - /* NAN is essentail for d2d rtt */ - if (FW_SUPPORTED(dhd, rttd2d)) - feature_set |= WIFI_FEATURE_D2D_RTT; - } -#ifdef RTT_SUPPORT - if (dhd->rtt_supported) { - feature_set |= WIFI_FEATURE_D2D_RTT; - feature_set |= WIFI_FEATURE_D2AP_RTT; - } -#endif /* RTT_SUPPORT */ -#ifdef LINKSTAT_SUPPORT - feature_set |= WIFI_FEATURE_LINKSTAT; -#endif /* LINKSTAT_SUPPORT */ - -#ifdef PNO_SUPPORT - if (dhd_is_pno_supported(dhd)) { - feature_set |= WIFI_FEATURE_PNO; -#ifdef GSCAN_SUPPORT - /* terence 20171115: remove to get GTS PASS - * com.google.android.gts.wifi.WifiHostTest#testWifiScannerBatchTimestamp - */ -// feature_set |= WIFI_FEATURE_GSCAN; -// feature_set |= WIFI_FEATURE_HAL_EPNO; -#endif /* GSCAN_SUPPORT */ - } -#endif /* PNO_SUPPORT */ -#ifdef RSSI_MONITOR_SUPPORT - if (FW_SUPPORTED(dhd, rssi_mon)) { - feature_set |= WIFI_FEATURE_RSSI_MONITOR; - } -#endif /* RSSI_MONITOR_SUPPORT */ -#ifdef WL11U - feature_set |= WIFI_FEATURE_HOTSPOT; -#endif /* WL11U */ -#ifdef NDO_CONFIG_SUPPORT - feature_set |= WIFI_FEATURE_CONFIG_NDO; -#endif /* NDO_CONFIG_SUPPORT */ -#ifdef KEEP_ALIVE - feature_set |= WIFI_FEATURE_MKEEP_ALIVE; -#endif /* KEEP_ALIVE */ - - return feature_set; -} - -int -dhd_dev_get_feature_set_matrix(struct net_device *dev, int num) -{ - int feature_set_full; - int ret = 0; - - feature_set_full = dhd_dev_get_feature_set(dev); - - /* Common feature set for all interface */ - ret = (feature_set_full & WIFI_FEATURE_INFRA) | - (feature_set_full & WIFI_FEATURE_INFRA_5G) | - (feature_set_full & WIFI_FEATURE_D2D_RTT) | - (feature_set_full & WIFI_FEATURE_D2AP_RTT) | - (feature_set_full & WIFI_FEATURE_RSSI_MONITOR) | - (feature_set_full & WIFI_FEATURE_EPR); - - /* Specific feature group for each interface */ - switch (num) { - case 0: - ret |= (feature_set_full & WIFI_FEATURE_P2P) | - /* Not supported yet */ - /* (feature_set_full & WIFI_FEATURE_NAN) | */ - (feature_set_full & WIFI_FEATURE_TDLS) | - (feature_set_full & WIFI_FEATURE_PNO) | - (feature_set_full & WIFI_FEATURE_HAL_EPNO) | - (feature_set_full & WIFI_FEATURE_BATCH_SCAN) | - (feature_set_full & WIFI_FEATURE_GSCAN) | - (feature_set_full & WIFI_FEATURE_HOTSPOT) | - (feature_set_full & WIFI_FEATURE_ADDITIONAL_STA); - break; - - case 1: - ret |= (feature_set_full & WIFI_FEATURE_P2P); - /* Not yet verified NAN with P2P */ - /* (feature_set_full & WIFI_FEATURE_NAN) | */ - break; - - case 2: - ret |= (feature_set_full & WIFI_FEATURE_NAN) | - (feature_set_full & WIFI_FEATURE_TDLS) | - (feature_set_full & WIFI_FEATURE_TDLS_OFFCHANNEL); - break; - - default: - ret = WIFI_FEATURE_INVALID; - DHD_ERROR(("%s: Out of index(%d) for get feature set\n", __FUNCTION__, num)); - break; - } - - return ret; -} - -#ifdef CUSTOM_FORCE_NODFS_FLAG -int -dhd_dev_set_nodfs(struct net_device *dev, u32 nodfs) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (nodfs) - dhd->pub.dhd_cflags |= WLAN_PLAT_NODFS_FLAG; - else - dhd->pub.dhd_cflags &= ~WLAN_PLAT_NODFS_FLAG; - dhd->pub.force_country_change = TRUE; - return 0; -} -#endif /* CUSTOM_FORCE_NODFS_FLAG */ - -#ifdef NDO_CONFIG_SUPPORT -int -dhd_dev_ndo_cfg(struct net_device *dev, u8 enable) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - dhd_pub_t *dhdp = &dhd->pub; - int ret = 0; - - if (enable) { - /* enable ND offload feature (will be enabled in FW on suspend) */ - dhdp->ndo_enable = TRUE; - - /* Update changes of anycast address & DAD failed address */ - ret = dhd_dev_ndo_update_inet6addr(dev); - if ((ret < 0) && (ret != BCME_NORESOURCE)) { - DHD_ERROR(("%s: failed to update host ip addr: %d\n", __FUNCTION__, ret)); - return ret; - } - } else { - /* disable ND offload feature */ - dhdp->ndo_enable = FALSE; - - /* disable ND offload in FW */ - ret = dhd_ndo_enable(dhdp, 0); - if (ret < 0) { - DHD_ERROR(("%s: failed to disable NDO: %d\n", __FUNCTION__, ret)); - } - } - return ret; -} - -/* #pragma used as a WAR to fix build failure, -* ignore dropping of 'const' qualifier in 'list_entry' macro -* this pragma disables the warning only for the following function -*/ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" - -static int -dhd_dev_ndo_get_valid_inet6addr_count(struct inet6_dev *inet6) -{ - struct inet6_ifaddr *ifa; - struct ifacaddr6 *acaddr = NULL; - int addr_count = 0; - - /* lock */ - read_lock_bh(&inet6->lock); - - /* Count valid unicast address */ - list_for_each_entry(ifa, &inet6->addr_list, if_list) { - if ((ifa->flags & IFA_F_DADFAILED) == 0) { - addr_count++; - } - } - - /* Count anycast address */ - acaddr = inet6->ac_list; - while (acaddr) { - addr_count++; - acaddr = acaddr->aca_next; - } - - /* unlock */ - read_unlock_bh(&inet6->lock); - - return addr_count; -} - -int -dhd_dev_ndo_update_inet6addr(struct net_device *dev) -{ - dhd_info_t *dhd; - dhd_pub_t *dhdp; - struct inet6_dev *inet6; - struct inet6_ifaddr *ifa; - struct ifacaddr6 *acaddr = NULL; - struct in6_addr *ipv6_addr = NULL; - int cnt, i; - int ret = BCME_OK; - - /* - * this function evaulates host ip address in struct inet6_dev - * unicast addr in inet6_dev->addr_list - * anycast addr in inet6_dev->ac_list - * while evaluating inet6_dev, read_lock_bh() is required to prevent - * access on null(freed) pointer. - */ - - if (dev) { - inet6 = dev->ip6_ptr; - if (!inet6) { - DHD_ERROR(("%s: Invalid inet6_dev\n", __FUNCTION__)); - return BCME_ERROR; - } - - dhd = DHD_DEV_INFO(dev); - if (!dhd) { - DHD_ERROR(("%s: Invalid dhd_info\n", __FUNCTION__)); - return BCME_ERROR; - } - dhdp = &dhd->pub; - - if (dhd_net2idx(dhd, dev) != 0) { - DHD_ERROR(("%s: Not primary interface\n", __FUNCTION__)); - return BCME_ERROR; - } - } else { - DHD_ERROR(("%s: Invalid net_device\n", __FUNCTION__)); - return BCME_ERROR; - } - - /* Check host IP overflow */ - cnt = dhd_dev_ndo_get_valid_inet6addr_count(inet6); - if (cnt > dhdp->ndo_max_host_ip) { - if (!dhdp->ndo_host_ip_overflow) { - dhdp->ndo_host_ip_overflow = TRUE; - /* Disable ND offload in FW */ - DHD_INFO(("%s: Host IP overflow, disable NDO\n", __FUNCTION__)); - ret = dhd_ndo_enable(dhdp, 0); - } - - return ret; - } - - /* - * Allocate ipv6 addr buffer to store addresses to be added/removed. - * driver need to lock inet6_dev while accessing structure. but, driver - * cannot use ioctl while inet6_dev locked since it requires scheduling - * hence, copy addresses to the buffer and do ioctl after unlock. - */ - ipv6_addr = (struct in6_addr *)MALLOC(dhdp->osh, - sizeof(struct in6_addr) * dhdp->ndo_max_host_ip); - if (!ipv6_addr) { - DHD_ERROR(("%s: failed to alloc ipv6 addr buffer\n", __FUNCTION__)); - return BCME_NOMEM; - } - - /* Find DAD failed unicast address to be removed */ - cnt = 0; - read_lock_bh(&inet6->lock); - list_for_each_entry(ifa, &inet6->addr_list, if_list) { - /* DAD failed unicast address */ - if ((ifa->flags & IFA_F_DADFAILED) && - (cnt < dhdp->ndo_max_host_ip)) { - memcpy(&ipv6_addr[cnt], &ifa->addr, sizeof(struct in6_addr)); - cnt++; - } - } - read_unlock_bh(&inet6->lock); - - /* Remove DAD failed unicast address */ - for (i = 0; i < cnt; i++) { - DHD_INFO(("%s: Remove DAD failed addr\n", __FUNCTION__)); - ret = dhd_ndo_remove_ip_by_addr(dhdp, (char *)&ipv6_addr[i], 0); - if (ret < 0) { - goto done; - } - } - - /* Remove all anycast address */ - ret = dhd_ndo_remove_ip_by_type(dhdp, WL_ND_IPV6_ADDR_TYPE_ANYCAST, 0); - if (ret < 0) { - goto done; - } - - /* - * if ND offload was disabled due to host ip overflow, - * attempt to add valid unicast address. - */ - if (dhdp->ndo_host_ip_overflow) { - /* Find valid unicast address */ - cnt = 0; - read_lock_bh(&inet6->lock); - list_for_each_entry(ifa, &inet6->addr_list, if_list) { - /* valid unicast address */ - if (!(ifa->flags & IFA_F_DADFAILED) && - (cnt < dhdp->ndo_max_host_ip)) { - memcpy(&ipv6_addr[cnt], &ifa->addr, - sizeof(struct in6_addr)); - cnt++; - } - } - read_unlock_bh(&inet6->lock); - - /* Add valid unicast address */ - for (i = 0; i < cnt; i++) { - ret = dhd_ndo_add_ip_with_type(dhdp, - (char *)&ipv6_addr[i], WL_ND_IPV6_ADDR_TYPE_UNICAST, 0); - if (ret < 0) { - goto done; - } - } - } - - /* Find anycast address */ - cnt = 0; - read_lock_bh(&inet6->lock); - acaddr = inet6->ac_list; - while (acaddr) { - if (cnt < dhdp->ndo_max_host_ip) { - memcpy(&ipv6_addr[cnt], &acaddr->aca_addr, sizeof(struct in6_addr)); - cnt++; - } - acaddr = acaddr->aca_next; - } - read_unlock_bh(&inet6->lock); - - /* Add anycast address */ - for (i = 0; i < cnt; i++) { - ret = dhd_ndo_add_ip_with_type(dhdp, - (char *)&ipv6_addr[i], WL_ND_IPV6_ADDR_TYPE_ANYCAST, 0); - if (ret < 0) { - goto done; - } - } - - /* Now All host IP addr were added successfully */ - if (dhdp->ndo_host_ip_overflow) { - dhdp->ndo_host_ip_overflow = FALSE; - if (dhdp->in_suspend) { - /* drvier is in (early) suspend state, need to enable ND offload in FW */ - DHD_INFO(("%s: enable NDO\n", __FUNCTION__)); - ret = dhd_ndo_enable(dhdp, 1); - } - } - -done: - if (ipv6_addr) { - MFREE(dhdp->osh, ipv6_addr, sizeof(struct in6_addr) * dhdp->ndo_max_host_ip); - } - - return ret; -} -#pragma GCC diagnostic pop - -#endif /* NDO_CONFIG_SUPPORT */ - -#ifdef PNO_SUPPORT -/* Linux wrapper to call common dhd_pno_stop_for_ssid */ -int -dhd_dev_pno_stop_for_ssid(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - return (dhd_pno_stop_for_ssid(&dhd->pub)); -} - -/* Linux wrapper to call common dhd_pno_set_for_ssid */ -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) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - return (dhd_pno_set_for_ssid(&dhd->pub, ssids_local, nssid, scan_fr, - pno_repeat, pno_freq_expo_max, channel_list, nchan)); -} - -/* Linux wrapper to call common dhd_pno_enable */ -int -dhd_dev_pno_enable(struct net_device *dev, int enable) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - return (dhd_pno_enable(&dhd->pub, enable)); -} - -/* Linux wrapper to call common dhd_pno_set_for_hotlist */ -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) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - return (dhd_pno_set_for_hotlist(&dhd->pub, p_pfn_bssid, hotlist_params)); -} -/* Linux wrapper to call common dhd_dev_pno_stop_for_batch */ -int -dhd_dev_pno_stop_for_batch(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - return (dhd_pno_stop_for_batch(&dhd->pub)); -} - -/* Linux wrapper to call common dhd_dev_pno_set_for_batch */ -int -dhd_dev_pno_set_for_batch(struct net_device *dev, struct dhd_pno_batch_params *batch_params) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - return (dhd_pno_set_for_batch(&dhd->pub, batch_params)); -} - -/* Linux wrapper to call common dhd_dev_pno_get_for_batch */ -int -dhd_dev_pno_get_for_batch(struct net_device *dev, char *buf, int bufsize) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - return (dhd_pno_get_for_batch(&dhd->pub, buf, bufsize, PNO_STATUS_NORMAL)); -} -#endif /* PNO_SUPPORT */ - -#if defined(PNO_SUPPORT) -#ifdef GSCAN_SUPPORT -bool -dhd_dev_is_legacy_pno_enabled(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_is_legacy_pno_enabled(&dhd->pub)); -} - -int -dhd_dev_set_epno(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - if (!dhd) { - return BCME_ERROR; - } - return dhd_pno_set_epno(&dhd->pub); -} -int -dhd_dev_flush_fw_epno(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - if (!dhd) { - return BCME_ERROR; - } - return dhd_pno_flush_fw_epno(&dhd->pub); -} - -/* Linux wrapper to call common dhd_pno_set_cfg_gscan */ -int -dhd_dev_pno_set_cfg_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, - void *buf, bool flush) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_set_cfg_gscan(&dhd->pub, type, buf, flush)); -} - -/* Linux wrapper to call common dhd_wait_batch_results_complete */ -int -dhd_dev_wait_batch_results_complete(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_wait_batch_results_complete(&dhd->pub)); -} - -/* Linux wrapper to call common dhd_pno_lock_batch_results */ -int -dhd_dev_pno_lock_access_batch_results(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_lock_batch_results(&dhd->pub)); -} -/* Linux wrapper to call common dhd_pno_unlock_batch_results */ -void -dhd_dev_pno_unlock_access_batch_results(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_unlock_batch_results(&dhd->pub)); -} - -/* Linux wrapper to call common dhd_pno_initiate_gscan_request */ -int -dhd_dev_pno_run_gscan(struct net_device *dev, bool run, bool flush) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_initiate_gscan_request(&dhd->pub, run, flush)); -} - -/* Linux wrapper to call common dhd_pno_enable_full_scan_result */ -int -dhd_dev_pno_enable_full_scan_result(struct net_device *dev, bool real_time_flag) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_enable_full_scan_result(&dhd->pub, real_time_flag)); -} - -/* Linux wrapper to call common dhd_handle_hotlist_scan_evt */ -void * -dhd_dev_hotlist_scan_event(struct net_device *dev, - const void *data, int *send_evt_bytes, hotlist_type_t type) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_handle_hotlist_scan_evt(&dhd->pub, data, send_evt_bytes, type)); -} - -/* Linux wrapper to call common dhd_process_full_gscan_result */ -void * -dhd_dev_process_full_gscan_result(struct net_device *dev, -const void *data, uint32 len, int *send_evt_bytes) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_process_full_gscan_result(&dhd->pub, data, len, send_evt_bytes)); -} - -void -dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_type_t type) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - dhd_gscan_hotlist_cache_cleanup(&dhd->pub, type); - - return; -} - -int -dhd_dev_gscan_batch_cache_cleanup(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_gscan_batch_cache_cleanup(&dhd->pub)); -} - -/* Linux wrapper to call common dhd_retreive_batch_scan_results */ -int -dhd_dev_retrieve_batch_scan(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_retreive_batch_scan_results(&dhd->pub)); -} - -/* Linux wrapper to call common dhd_pno_process_epno_result */ -void * dhd_dev_process_epno_result(struct net_device *dev, - const void *data, uint32 event, int *send_evt_bytes) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_process_epno_result(&dhd->pub, data, event, send_evt_bytes)); -} - -int -dhd_dev_set_lazy_roam_cfg(struct net_device *dev, - wlc_roam_exp_params_t *roam_param) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - wl_roam_exp_cfg_t roam_exp_cfg; - int err; - - if (!roam_param) { - return BCME_BADARG; - } - - DHD_ERROR(("a_band_boost_thr %d a_band_penalty_thr %d\n", - roam_param->a_band_boost_threshold, roam_param->a_band_penalty_threshold)); - DHD_ERROR(("a_band_boost_factor %d a_band_penalty_factor %d cur_bssid_boost %d\n", - roam_param->a_band_boost_factor, roam_param->a_band_penalty_factor, - roam_param->cur_bssid_boost)); - DHD_ERROR(("alert_roam_trigger_thr %d a_band_max_boost %d\n", - roam_param->alert_roam_trigger_threshold, roam_param->a_band_max_boost)); - - memcpy(&roam_exp_cfg.params, roam_param, sizeof(*roam_param)); - roam_exp_cfg.version = ROAM_EXP_CFG_VERSION; - roam_exp_cfg.flags = ROAM_EXP_CFG_PRESENT; - if (dhd->pub.lazy_roam_enable) { - roam_exp_cfg.flags |= ROAM_EXP_ENABLE_FLAG; - } - err = dhd_iovar(&dhd->pub, 0, "roam_exp_params", - (char *)&roam_exp_cfg, sizeof(roam_exp_cfg), NULL, 0, - TRUE); - if (err < 0) { - DHD_ERROR(("%s : Failed to execute roam_exp_params %d\n", __FUNCTION__, err)); - } - return err; -} - -int -dhd_dev_lazy_roam_enable(struct net_device *dev, uint32 enable) -{ - int err; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - wl_roam_exp_cfg_t roam_exp_cfg; - - memset(&roam_exp_cfg, 0, sizeof(roam_exp_cfg)); - roam_exp_cfg.version = ROAM_EXP_CFG_VERSION; - if (enable) { - roam_exp_cfg.flags = ROAM_EXP_ENABLE_FLAG; - } - - err = dhd_iovar(&dhd->pub, 0, "roam_exp_params", - (char *)&roam_exp_cfg, sizeof(roam_exp_cfg), NULL, 0, - TRUE); - if (err < 0) { - DHD_ERROR(("%s : Failed to execute roam_exp_params %d\n", __FUNCTION__, err)); - } else { - dhd->pub.lazy_roam_enable = (enable != 0); - } - return err; -} - -int -dhd_dev_set_lazy_roam_bssid_pref(struct net_device *dev, - wl_bssid_pref_cfg_t *bssid_pref, uint32 flush) -{ - int err; - int len; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - bssid_pref->version = BSSID_PREF_LIST_VERSION; - /* By default programming bssid pref flushes out old values */ - bssid_pref->flags = (flush && !bssid_pref->count) ? ROAM_EXP_CLEAR_BSSID_PREF: 0; - len = sizeof(wl_bssid_pref_cfg_t); - len += (bssid_pref->count - 1) * sizeof(wl_bssid_pref_list_t); - err = dhd_iovar(&(dhd->pub), 0, "roam_exp_bssid_pref", (char *)bssid_pref, - len, NULL, 0, TRUE); - if (err != BCME_OK) { - DHD_ERROR(("%s : Failed to execute roam_exp_bssid_pref %d\n", __FUNCTION__, err)); - } - return err; -} - -int -dhd_dev_set_blacklist_bssid(struct net_device *dev, maclist_t *blacklist, - uint32 len, uint32 flush) -{ - int err; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int macmode; - - if (blacklist) { - err = dhd_wl_ioctl_cmd(&(dhd->pub), WLC_SET_MACLIST, (char *)blacklist, - len, TRUE, 0); - if (err != BCME_OK) { - DHD_ERROR(("%s : WLC_SET_MACLIST failed %d\n", __FUNCTION__, err)); - return err; - } - } - /* By default programming blacklist flushes out old values */ - macmode = (flush && !blacklist) ? WLC_MACMODE_DISABLED : WLC_MACMODE_DENY; - err = dhd_wl_ioctl_cmd(&(dhd->pub), WLC_SET_MACMODE, (char *)&macmode, - sizeof(macmode), TRUE, 0); - if (err != BCME_OK) { - DHD_ERROR(("%s : WLC_SET_MACMODE failed %d\n", __FUNCTION__, err)); - } - return err; -} - -int -dhd_dev_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *ssid_whitelist, - uint32 len, uint32 flush) -{ - int err; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - wl_ssid_whitelist_t whitelist_ssid_flush; - - if (!ssid_whitelist) { - if (flush) { - ssid_whitelist = &whitelist_ssid_flush; - ssid_whitelist->ssid_count = 0; - } else { - DHD_ERROR(("%s : Nothing to do here\n", __FUNCTION__)); - return BCME_BADARG; - } - } - ssid_whitelist->version = SSID_WHITELIST_VERSION; - ssid_whitelist->flags = flush ? ROAM_EXP_CLEAR_SSID_WHITELIST : 0; - err = dhd_iovar(&(dhd->pub), 0, "roam_exp_ssid_whitelist", (char *)ssid_whitelist, - len, NULL, 0, TRUE); - if (err != BCME_OK) { - DHD_ERROR(("%s : Failed to execute roam_exp_bssid_pref %d\n", __FUNCTION__, err)); - } - return err; -} -#endif /* GSCAN_SUPPORT */ - -#if defined(GSCAN_SUPPORT) || defined(DHD_GET_VALID_CHANNELS) -/* Linux wrapper to call common dhd_pno_get_gscan */ -void * -dhd_dev_pno_get_gscan(struct net_device *dev, dhd_pno_gscan_cmd_cfg_t type, - void *info, uint32 *len) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_get_gscan(&dhd->pub, type, info, len)); -} -#endif /* GSCAN_SUPPORT || DHD_GET_VALID_CHANNELS */ -#endif - -#ifdef RSSI_MONITOR_SUPPORT -int -dhd_dev_set_rssi_monitor_cfg(struct net_device *dev, int start, - int8 max_rssi, int8 min_rssi) -{ - int err; - wl_rssi_monitor_cfg_t rssi_monitor; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - rssi_monitor.version = RSSI_MONITOR_VERSION; - rssi_monitor.max_rssi = max_rssi; - rssi_monitor.min_rssi = min_rssi; - rssi_monitor.flags = start ? 0: RSSI_MONITOR_STOP; - err = dhd_iovar(&(dhd->pub), 0, "rssi_monitor", (char *)&rssi_monitor, - sizeof(rssi_monitor), NULL, 0, TRUE); - if (err < 0 && err != BCME_UNSUPPORTED) { - DHD_ERROR(("%s : Failed to execute rssi_monitor %d\n", __FUNCTION__, err)); - } - return err; -} -#endif /* RSSI_MONITOR_SUPPORT */ - -#ifdef DHDTCPACK_SUPPRESS -int dhd_dev_set_tcpack_sup_mode_cfg(struct net_device *dev, uint8 enable) -{ - int err; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - err = dhd_tcpack_suppress_set(&(dhd->pub), enable); - if (err != BCME_OK) { - DHD_ERROR(("%s : Failed to execute rssi_monitor %d\n", __FUNCTION__, err)); - } - return err; -} -#endif /* DHDTCPACK_SUPPRESS */ - -int -dhd_dev_cfg_rand_mac_oui(struct net_device *dev, uint8 *oui) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - dhd_pub_t *dhdp = &dhd->pub; - - if (!dhdp || !oui) { - DHD_ERROR(("NULL POINTER : %s\n", - __FUNCTION__)); - return BCME_ERROR; - } - if (ETHER_ISMULTI(oui)) { - DHD_ERROR(("Expected unicast OUI\n")); - return BCME_ERROR; - } else { - uint8 *rand_mac_oui = dhdp->rand_mac_oui; - memcpy(rand_mac_oui, oui, DOT11_OUI_LEN); - DHD_ERROR(("Random MAC OUI to be used - %02x:%02x:%02x\n", rand_mac_oui[0], - rand_mac_oui[1], rand_mac_oui[2])); - } - return BCME_OK; -} - -int -dhd_set_rand_mac_oui(dhd_pub_t *dhd) -{ - int err; - wl_pfn_macaddr_cfg_t wl_cfg; - uint8 *rand_mac_oui = dhd->rand_mac_oui; - - memset(&wl_cfg.macaddr, 0, ETHER_ADDR_LEN); - memcpy(&wl_cfg.macaddr, rand_mac_oui, DOT11_OUI_LEN); - wl_cfg.version = WL_PFN_MACADDR_CFG_VER; - if (ETHER_ISNULLADDR(&wl_cfg.macaddr)) { - wl_cfg.flags = 0; - } else { - wl_cfg.flags = (WL_PFN_MAC_OUI_ONLY_MASK | WL_PFN_SET_MAC_UNASSOC_MASK); - } - - DHD_ERROR(("Setting rand mac oui to FW - %02x:%02x:%02x\n", rand_mac_oui[0], - rand_mac_oui[1], rand_mac_oui[2])); - - err = dhd_iovar(dhd, 0, "pfn_macaddr", (char *)&wl_cfg, sizeof(wl_cfg), NULL, 0, TRUE); - if (err < 0) { - DHD_ERROR(("%s : failed to execute pfn_macaddr %d\n", __FUNCTION__, err)); - } - return err; -} - -#ifdef RTT_SUPPORT -#ifdef WL_CFG80211 -/* Linux wrapper to call common dhd_pno_set_cfg_gscan */ -int -dhd_dev_rtt_set_cfg(struct net_device *dev, void *buf) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_rtt_set_cfg(&dhd->pub, buf)); -} - -int -dhd_dev_rtt_cancel_cfg(struct net_device *dev, struct ether_addr *mac_list, int mac_cnt) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_rtt_stop(&dhd->pub, mac_list, mac_cnt)); -} - -int -dhd_dev_rtt_register_noti_callback(struct net_device *dev, void *ctx, dhd_rtt_compl_noti_fn noti_fn) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_rtt_register_noti_callback(&dhd->pub, ctx, noti_fn)); -} - -int -dhd_dev_rtt_unregister_noti_callback(struct net_device *dev, dhd_rtt_compl_noti_fn noti_fn) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_rtt_unregister_noti_callback(&dhd->pub, noti_fn)); -} - -int -dhd_dev_rtt_capability(struct net_device *dev, rtt_capabilities_t *capa) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_rtt_capability(&dhd->pub, capa)); -} - -int -dhd_dev_rtt_avail_channel(struct net_device *dev, wifi_channel_info *channel_info) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return (dhd_rtt_avail_channel(&dhd->pub, channel_info)); -} - -int -dhd_dev_rtt_enable_responder(struct net_device *dev, wifi_channel_info *channel_info) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return (dhd_rtt_enable_responder(&dhd->pub, channel_info)); -} - -int dhd_dev_rtt_cancel_responder(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - return (dhd_rtt_cancel_responder(&dhd->pub)); -} -#endif /* WL_CFG80211 */ -#endif /* RTT_SUPPORT */ - -#ifdef KEEP_ALIVE -#define KA_TEMP_BUF_SIZE 512 -#define KA_FRAME_SIZE 300 - -int -dhd_dev_start_mkeep_alive(dhd_pub_t *dhd_pub, uint8 mkeep_alive_id, uint8 *ip_pkt, - uint16 ip_pkt_len, uint8* src_mac, uint8* dst_mac, uint32 period_msec) -{ - const int ETHERTYPE_LEN = 2; - char *pbuf = NULL; - const char *str; - wl_mkeep_alive_pkt_t mkeep_alive_pkt; - wl_mkeep_alive_pkt_t *mkeep_alive_pktp = NULL; - int buf_len = 0; - int str_len = 0; - int res = BCME_ERROR; - int len_bytes = 0; - int i = 0; - - /* ether frame to have both max IP pkt (256 bytes) and ether header */ - char *pmac_frame = NULL; - char *pmac_frame_begin = NULL; - - /* - * The mkeep_alive packet is for STA interface only; if the bss is configured as AP, - * dongle shall reject a mkeep_alive request. - */ - if (!dhd_support_sta_mode(dhd_pub)) - return res; - - DHD_TRACE(("%s execution\n", __FUNCTION__)); - - if ((pbuf = kzalloc(KA_TEMP_BUF_SIZE, GFP_KERNEL)) == NULL) { - DHD_ERROR(("failed to allocate buf with size %d\n", KA_TEMP_BUF_SIZE)); - res = BCME_NOMEM; - return res; - } - - if ((pmac_frame = kzalloc(KA_FRAME_SIZE, GFP_KERNEL)) == NULL) { - DHD_ERROR(("failed to allocate mac_frame with size %d\n", KA_FRAME_SIZE)); - res = BCME_NOMEM; - goto exit; - } - pmac_frame_begin = pmac_frame; - - /* - * Get current mkeep-alive status. - */ - res = dhd_iovar(dhd_pub, 0, "mkeep_alive", &mkeep_alive_id, sizeof(mkeep_alive_id), pbuf, - KA_TEMP_BUF_SIZE, FALSE); - if (res < 0) { - DHD_ERROR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); - goto exit; - } else { - /* Check available ID whether it is occupied */ - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf; - if (dtoh32(mkeep_alive_pktp->period_msec != 0)) { - DHD_ERROR(("%s: Get mkeep_alive failed, ID %u is in use.\n", - __FUNCTION__, mkeep_alive_id)); - - /* Current occupied ID info */ - DHD_ERROR(("%s: mkeep_alive\n", __FUNCTION__)); - DHD_ERROR((" Id : %d\n" - " Period: %d msec\n" - " Length: %d\n" - " Packet: 0x", - mkeep_alive_pktp->keep_alive_id, - dtoh32(mkeep_alive_pktp->period_msec), - dtoh16(mkeep_alive_pktp->len_bytes))); - - for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) { - DHD_ERROR(("%02x", mkeep_alive_pktp->data[i])); - } - DHD_ERROR(("\n")); - - res = BCME_NOTFOUND; - goto exit; - } - } - - /* Request the specified ID */ - memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); - memset(pbuf, 0, KA_TEMP_BUF_SIZE); - str = "mkeep_alive"; - str_len = strlen(str); - strncpy(pbuf, str, str_len); - pbuf[str_len] = '\0'; - - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (pbuf + str_len + 1); - mkeep_alive_pkt.period_msec = htod32(period_msec); - buf_len = str_len + 1; - mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); - mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); - - /* ID assigned */ - mkeep_alive_pkt.keep_alive_id = mkeep_alive_id; - - buf_len += WL_MKEEP_ALIVE_FIXED_LEN; - - /* - * Build up Ethernet Frame - */ - - /* Mapping dest mac addr */ - memcpy(pmac_frame, dst_mac, ETHER_ADDR_LEN); - pmac_frame += ETHER_ADDR_LEN; - - /* Mapping src mac addr */ - memcpy(pmac_frame, src_mac, ETHER_ADDR_LEN); - pmac_frame += ETHER_ADDR_LEN; - - /* Mapping Ethernet type (ETHERTYPE_IP: 0x0800) */ - *(pmac_frame++) = 0x08; - *(pmac_frame++) = 0x00; - - /* Mapping IP pkt */ - memcpy(pmac_frame, ip_pkt, ip_pkt_len); - pmac_frame += ip_pkt_len; - - /* - * Length of ether frame (assume to be all hexa bytes) - * = src mac + dst mac + ether type + ip pkt len - */ - len_bytes = ETHER_ADDR_LEN*2 + ETHERTYPE_LEN + ip_pkt_len; - memcpy(mkeep_alive_pktp->data, pmac_frame_begin, len_bytes); - buf_len += len_bytes; - mkeep_alive_pkt.len_bytes = htod16(len_bytes); - - /* - * Keep-alive attributes are set in local variable (mkeep_alive_pkt), and - * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no - * guarantee that the buffer is properly aligned. - */ - memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); - - res = dhd_wl_ioctl_cmd(dhd_pub, WLC_SET_VAR, pbuf, buf_len, TRUE, 0); -exit: - kfree(pmac_frame_begin); - kfree(pbuf); - return res; -} - -int -dhd_dev_stop_mkeep_alive(dhd_pub_t *dhd_pub, uint8 mkeep_alive_id) -{ - char *pbuf; - wl_mkeep_alive_pkt_t mkeep_alive_pkt; - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; - int res = BCME_ERROR; - int i; - - /* - * The mkeep_alive packet is for STA interface only; if the bss is configured as AP, - * dongle shall reject a mkeep_alive request. - */ - if (!dhd_support_sta_mode(dhd_pub)) - return res; - - DHD_TRACE(("%s execution\n", __FUNCTION__)); - - /* - * Get current mkeep-alive status. Skip ID 0 which is being used for NULL pkt. - */ - if ((pbuf = kmalloc(KA_TEMP_BUF_SIZE, GFP_KERNEL)) == NULL) { - DHD_ERROR(("failed to allocate buf with size %d\n", KA_TEMP_BUF_SIZE)); - return res; - } - - res = dhd_iovar(dhd_pub, 0, "mkeep_alive", &mkeep_alive_id, - sizeof(mkeep_alive_id), pbuf, KA_TEMP_BUF_SIZE, FALSE); - if (res < 0) { - DHD_ERROR(("%s: Get mkeep_alive failed (error=%d)\n", __FUNCTION__, res)); - goto exit; - } else { - /* Check occupied ID */ - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) pbuf; - DHD_INFO(("%s: mkeep_alive\n", __FUNCTION__)); - DHD_INFO((" Id : %d\n" - " Period: %d msec\n" - " Length: %d\n" - " Packet: 0x", - mkeep_alive_pktp->keep_alive_id, - dtoh32(mkeep_alive_pktp->period_msec), - dtoh16(mkeep_alive_pktp->len_bytes))); - - for (i = 0; i < mkeep_alive_pktp->len_bytes; i++) { - DHD_INFO(("%02x", mkeep_alive_pktp->data[i])); - } - DHD_INFO(("\n")); - } - - /* Make it stop if available */ - if (dtoh32(mkeep_alive_pktp->period_msec != 0)) { - DHD_INFO(("stop mkeep_alive on ID %d\n", mkeep_alive_id)); - memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t)); - - mkeep_alive_pkt.period_msec = 0; - mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); - mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); - mkeep_alive_pkt.keep_alive_id = mkeep_alive_id; - - res = dhd_iovar(dhd_pub, 0, "mkeep_alive", - (char *)&mkeep_alive_pkt, - WL_MKEEP_ALIVE_FIXED_LEN, NULL, 0, TRUE); - } else { - DHD_ERROR(("%s: ID %u does not exist.\n", __FUNCTION__, mkeep_alive_id)); - res = BCME_NOTFOUND; - } -exit: - kfree(pbuf); - return res; -} -#endif /* KEEP_ALIVE */ - -#if defined(PKT_FILTER_SUPPORT) && defined(APF) -static void _dhd_apf_lock_local(dhd_info_t *dhd) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - if (dhd) { - mutex_lock(&dhd->dhd_apf_mutex); - } -#endif -} - -static void _dhd_apf_unlock_local(dhd_info_t *dhd) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - if (dhd) { - mutex_unlock(&dhd->dhd_apf_mutex); - } -#endif -} - -static int -__dhd_apf_add_filter(struct net_device *ndev, uint32 filter_id, - u8* program, uint32 program_len) -{ - dhd_info_t *dhd = DHD_DEV_INFO(ndev); - dhd_pub_t *dhdp = &dhd->pub; - wl_pkt_filter_t * pkt_filterp; - wl_apf_program_t *apf_program; - char *buf; - u32 cmd_len, buf_len; - int ifidx, ret; - gfp_t kflags; - char cmd[] = "pkt_filter_add"; - - ifidx = dhd_net2idx(dhd, ndev); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: bad ifidx\n", __FUNCTION__)); - return -ENODEV; - } - - cmd_len = sizeof(cmd); - - /* Check if the program_len is more than the expected len - * and if the program is NULL return from here. - */ - if ((program_len > WL_APF_PROGRAM_MAX_SIZE) || (program == NULL)) { - DHD_ERROR(("%s Invalid program_len: %d, program: %pK\n", - __FUNCTION__, program_len, program)); - return -EINVAL; - } - buf_len = cmd_len + WL_PKT_FILTER_FIXED_LEN + - WL_APF_PROGRAM_FIXED_LEN + program_len; - - kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - buf = kzalloc(buf_len, kflags); - if (unlikely(!buf)) { - DHD_ERROR(("%s: MALLOC failure, %d bytes\n", __FUNCTION__, buf_len)); - return -ENOMEM; - } - - memcpy(buf, cmd, cmd_len); - - pkt_filterp = (wl_pkt_filter_t *) (buf + cmd_len); - pkt_filterp->id = htod32(filter_id); - pkt_filterp->negate_match = htod32(FALSE); - pkt_filterp->type = htod32(WL_PKT_FILTER_TYPE_APF_MATCH); - - apf_program = &pkt_filterp->u.apf_program; - apf_program->version = htod16(WL_APF_INTERNAL_VERSION); - apf_program->instr_len = htod16(program_len); - memcpy(apf_program->instrs, program, program_len); - - ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, buf_len, TRUE, ifidx); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to add APF filter, id=%d, ret=%d\n", - __FUNCTION__, filter_id, ret)); - } - - if (buf) { - kfree(buf); - } - return ret; -} - -static int -__dhd_apf_config_filter(struct net_device *ndev, uint32 filter_id, - uint32 mode, uint32 enable) -{ - dhd_info_t *dhd = DHD_DEV_INFO(ndev); - dhd_pub_t *dhdp = &dhd->pub; - wl_pkt_filter_enable_t * pkt_filterp; - char *buf; - u32 cmd_len, buf_len; - int ifidx, ret; - gfp_t kflags; - char cmd[] = "pkt_filter_enable"; - - ifidx = dhd_net2idx(dhd, ndev); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: bad ifidx\n", __FUNCTION__)); - return -ENODEV; - } - - cmd_len = sizeof(cmd); - buf_len = cmd_len + sizeof(*pkt_filterp); - - kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL; - buf = kzalloc(buf_len, kflags); - if (unlikely(!buf)) { - DHD_ERROR(("%s: MALLOC failure, %d bytes\n", __FUNCTION__, buf_len)); - return -ENOMEM; - } - - memcpy(buf, cmd, cmd_len); - - pkt_filterp = (wl_pkt_filter_enable_t *) (buf + cmd_len); - pkt_filterp->id = htod32(filter_id); - pkt_filterp->enable = htod32(enable); - - ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, buf_len, TRUE, ifidx); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to enable APF filter, id=%d, ret=%d\n", - __FUNCTION__, filter_id, ret)); - goto exit; - } - - ret = dhd_wl_ioctl_set_intiovar(dhdp, "pkt_filter_mode", dhd_master_mode, - WLC_SET_VAR, TRUE, ifidx); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to set APF filter mode, id=%d, ret=%d\n", - __FUNCTION__, filter_id, ret)); - } - -exit: - if (buf) { - kfree(buf); - } - return ret; -} - -static int -__dhd_apf_delete_filter(struct net_device *ndev, uint32 filter_id) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(ndev); - dhd_pub_t *dhdp = &dhd->pub; - int ifidx, ret; - - ifidx = dhd_net2idx(dhd, ndev); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: bad ifidx\n", __FUNCTION__)); - return -ENODEV; - } - - ret = dhd_wl_ioctl_set_intiovar(dhdp, "pkt_filter_delete", - htod32(filter_id), WLC_SET_VAR, TRUE, ifidx); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to delete APF filter, id=%d, ret=%d\n", - __FUNCTION__, filter_id, ret)); - } - - return ret; -} - -void dhd_apf_lock(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - _dhd_apf_lock_local(dhd); -} - -void dhd_apf_unlock(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - _dhd_apf_unlock_local(dhd); -} - -int -dhd_dev_apf_get_version(struct net_device *ndev, uint32 *version) -{ - dhd_info_t *dhd = DHD_DEV_INFO(ndev); - dhd_pub_t *dhdp = &dhd->pub; - int ifidx, ret; - - if (!FW_SUPPORTED(dhdp, apf)) { - DHD_ERROR(("%s: firmware doesn't support APF\n", __FUNCTION__)); - - /* - * Notify Android framework that APF is not supported by setting - * version as zero. - */ - *version = 0; - return BCME_OK; - } - - ifidx = dhd_net2idx(dhd, ndev); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: bad ifidx\n", __FUNCTION__)); - return -ENODEV; - } - - ret = dhd_wl_ioctl_get_intiovar(dhdp, "apf_ver", version, - WLC_GET_VAR, FALSE, ifidx); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to get APF version, ret=%d\n", - __FUNCTION__, ret)); - } - - return ret; -} - -int -dhd_dev_apf_get_max_len(struct net_device *ndev, uint32 *max_len) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(ndev); - dhd_pub_t *dhdp = &dhd->pub; - int ifidx, ret; - - if (!FW_SUPPORTED(dhdp, apf)) { - DHD_ERROR(("%s: firmware doesn't support APF\n", __FUNCTION__)); - *max_len = 0; - return BCME_OK; - } - - ifidx = dhd_net2idx(dhd, ndev); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s bad ifidx\n", __FUNCTION__)); - return -ENODEV; - } - - ret = dhd_wl_ioctl_get_intiovar(dhdp, "apf_size_limit", max_len, - WLC_GET_VAR, FALSE, ifidx); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to get APF size limit, ret=%d\n", - __FUNCTION__, ret)); - } - - return ret; -} - -int -dhd_dev_apf_add_filter(struct net_device *ndev, u8* program, - uint32 program_len) -{ - dhd_info_t *dhd = DHD_DEV_INFO(ndev); - dhd_pub_t *dhdp = &dhd->pub; - int ret; - - DHD_APF_LOCK(ndev); - - /* delete, if filter already exists */ - if (dhdp->apf_set) { - ret = __dhd_apf_delete_filter(ndev, PKT_FILTER_APF_ID); - if (unlikely(ret)) { - goto exit; - } - dhdp->apf_set = FALSE; - } - - ret = __dhd_apf_add_filter(ndev, PKT_FILTER_APF_ID, program, program_len); - if (ret) { - goto exit; - } - dhdp->apf_set = TRUE; - - if (dhdp->in_suspend && dhdp->apf_set && !(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) { - /* Driver is still in (early) suspend state, enable APF filter back */ - ret = __dhd_apf_config_filter(ndev, PKT_FILTER_APF_ID, - PKT_FILTER_MODE_FORWARD_ON_MATCH, TRUE); - } -exit: - DHD_APF_UNLOCK(ndev); - - return ret; -} - -int -dhd_dev_apf_enable_filter(struct net_device *ndev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(ndev); - dhd_pub_t *dhdp = &dhd->pub; - int ret = 0; - - DHD_APF_LOCK(ndev); - - if (dhdp->apf_set && !(dhdp->op_mode & DHD_FLAG_HOSTAP_MODE)) { - ret = __dhd_apf_config_filter(ndev, PKT_FILTER_APF_ID, - PKT_FILTER_MODE_FORWARD_ON_MATCH, TRUE); - } - - DHD_APF_UNLOCK(ndev); - - return ret; -} - -int -dhd_dev_apf_disable_filter(struct net_device *ndev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(ndev); - dhd_pub_t *dhdp = &dhd->pub; - int ret = 0; - - DHD_APF_LOCK(ndev); - - if (dhdp->apf_set) { - ret = __dhd_apf_config_filter(ndev, PKT_FILTER_APF_ID, - PKT_FILTER_MODE_FORWARD_ON_MATCH, FALSE); - } - - DHD_APF_UNLOCK(ndev); - - return ret; -} - -int -dhd_dev_apf_delete_filter(struct net_device *ndev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(ndev); - dhd_pub_t *dhdp = &dhd->pub; - int ret = 0; - - DHD_APF_LOCK(ndev); - - if (dhdp->apf_set) { - ret = __dhd_apf_delete_filter(ndev, PKT_FILTER_APF_ID); - if (!ret) { - dhdp->apf_set = FALSE; - } - } - - DHD_APF_UNLOCK(ndev); - - return ret; -} -#endif /* PKT_FILTER_SUPPORT && APF */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -static void dhd_hang_process(void *dhd_info, void *event_info, u8 event) -{ - dhd_info_t *dhd; - struct net_device *dev; - - dhd = (dhd_info_t *)dhd_info; - dev = dhd->iflist[0]->net; - - if (dev) { - /* - * For HW2, dev_close need to be done to recover - * from upper layer after hang. For Interposer skip - * dev_close so that dhd iovars can be used to take - * socramdump after crash, also skip for HW4 as - * handling of hang event is different - */ -#if !defined(CUSTOMER_HW2_INTERPOSER) - rtnl_lock(); - dev_close(dev); - rtnl_unlock(); -#endif -#if defined(WL_WIRELESS_EXT) - wl_iw_send_priv_event(dev, "HANG"); -#endif -#if defined(WL_CFG80211) - wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); -#ifdef IDSUP_STATS - DHD_ERROR(("Driver is HANGED\n")); - atomic_set(&dhd_hang_state, DHD_STATUS_HANGED); - dhd_change_driver_state(DHD_DRIVER_STATE_HANGED); - wl_state_event_sendup(wl_get_cfg(dev), ndev_to_cfgdev(dev), - NULL, EVT_RESET, NULL); -#endif /* IDSUP_STATS */ -#endif - } -} - -#ifdef EXYNOS_PCIE_LINKDOWN_RECOVERY -extern dhd_pub_t *link_recovery; -void dhd_host_recover_link(void) -{ - DHD_ERROR(("****** %s ******\n", __FUNCTION__)); - link_recovery->hang_reason = HANG_REASON_PCIE_LINK_DOWN; - dhd_bus_set_linkdown(link_recovery, TRUE); - dhd_os_send_hang_message(link_recovery); -} -EXPORT_SYMBOL(dhd_host_recover_link); -#endif /* EXYNOS_PCIE_LINKDOWN_RECOVERY */ - -int dhd_os_send_hang_message(dhd_pub_t *dhdp) -{ - int ret = 0; - if (dhdp) { -#if defined(DHD_HANG_SEND_UP_TEST) - if (dhdp->req_hang_type) { - DHD_ERROR(("%s, Clear HANG test request 0x%x\n", - __FUNCTION__, dhdp->req_hang_type)); - dhdp->req_hang_type = 0; - } -#endif /* DHD_HANG_SEND_UP_TEST */ - - if (!dhdp->hang_was_sent) { -#if defined(CONFIG_BCM_DETECT_CONSECUTIVE_HANG) - dhdp->hang_counts++; - if (dhdp->hang_counts >= MAX_CONSECUTIVE_HANG_COUNTS) { - DHD_ERROR(("%s, Consecutive hang from Dongle :%u\n", - __func__, dhdp->hang_counts)); - BUG_ON(1); - } -#endif /* CONFIG_BCM_DETECT_CONSECUTIVE_HANG */ -#ifdef DHD_DEBUG_UART - /* If PCIe lane has broken, execute the debug uart application - * to gether a ramdump data from dongle via uart - */ - if (!dhdp->info->duart_execute) { - dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, - (void *)dhdp, DHD_WQ_WORK_DEBUG_UART_DUMP, - dhd_debug_uart_exec_rd, DHD_WQ_WORK_PRIORITY_HIGH); - } -#endif /* DHD_DEBUG_UART */ - dhdp->hang_was_sent = 1; -#ifdef BT_OVER_SDIO - dhdp->is_bt_recovery_required = TRUE; -#endif -#ifdef SDIO_TRAITS_STATS - DHD_ERROR(("%s: dhdp->hang_reason = %x\n", __func__, dhdp->hang_reason)); - if (dhdp->fw_need_reload != FW_RELOADED) { - if (dhdp->hang_reason == HANG_REASON_DONGLE_TRAP) { - dhd_bus_traits_fw_hang_inc(); - } else { - dhd_bus_traits_bus_hang_inc(); - } - } -#endif /* SDIO_TRAITS_STATS */ - dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, (void *)dhdp, - DHD_WQ_WORK_HANG_MSG, dhd_hang_process, DHD_WQ_WORK_PRIORITY_HIGH); - DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d s=%d\n", __FUNCTION__, - dhdp->rxcnt_timeout, dhdp->txcnt_timeout, dhdp->busstate)); - } - } - return ret; -} - -int net_os_send_hang_message(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - - if (dhd) { - /* Report FW problem when enabled */ - if (dhd->pub.hang_report) { -#ifdef BT_OVER_SDIO - if (netif_running(dev)) { -#endif /* BT_OVER_SDIO */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - ret = dhd_os_send_hang_message(&dhd->pub); -#else - ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); -#endif -#ifdef BT_OVER_SDIO - } - DHD_ERROR(("%s: HANG -> Reset BT\n", __FUNCTION__)); - bcmsdh_btsdio_process_dhd_hang_notification(!netif_running(dev)); -#endif /* BT_OVER_SDIO */ - } else { - DHD_ERROR(("%s: FW HANG ignored (for testing purpose) and not sent up\n", - __FUNCTION__)); - } - } - return ret; -} - -int net_os_send_hang_message_reason(struct net_device *dev, const char *string_num) -{ - dhd_info_t *dhd = NULL; - dhd_pub_t *dhdp = NULL; - int reason; - - dhd = DHD_DEV_INFO(dev); - if (dhd) { - dhdp = &dhd->pub; - } - - if (!dhd || !dhdp) { - return 0; - } - - reason = bcm_strtoul(string_num, NULL, 0); - DHD_INFO(("%s: Enter, reason=0x%x\n", __FUNCTION__, reason)); - - if ((reason <= HANG_REASON_MASK) || (reason >= HANG_REASON_MAX)) { - reason = 0; - } - - dhdp->hang_reason = reason; - - return net_os_send_hang_message(dev); -} -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) && OEM_ANDROID */ - - -int dhd_net_wifi_platform_set_power(struct net_device *dev, bool on, unsigned long delay_msec) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - return wifi_platform_set_power(dhd->adapter, on, delay_msec); -} - -bool dhd_force_country_change(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (dhd && dhd->pub.up) - return dhd->pub.force_country_change; - return FALSE; -} - -void dhd_get_customized_country_code(struct net_device *dev, char *country_iso_code, - wl_country_t *cspec) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); -#if defined(DHD_BLOB_EXISTENCE_CHECK) - if (!dhd->pub.is_blob) -#endif /* DHD_BLOB_EXISTENCE_CHECK */ - { -#if defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) - get_customized_country_code(dhd->adapter, country_iso_code, cspec, - dhd->pub.dhd_cflags); -#else - get_customized_country_code(dhd->adapter, country_iso_code, cspec); -#endif /* defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) */ - } - - BCM_REFERENCE(dhd); -} - -void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec, bool notify) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); -#ifdef WL_CFG80211 - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); -#endif - - if (dhd && dhd->pub.up) { - memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); -#ifdef WL_CFG80211 - wl_update_wiphybands(cfg, notify); -#endif - } -} - -void dhd_bus_band_set(struct net_device *dev, uint band) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); -#ifdef WL_CFG80211 - struct bcm_cfg80211 *cfg = wl_get_cfg(dev); -#endif - if (dhd && dhd->pub.up) { -#ifdef WL_CFG80211 - wl_update_wiphybands(cfg, true); -#endif - } -} - -int dhd_net_set_fw_path(struct net_device *dev, char *fw) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (!fw || fw[0] == '\0') - return -EINVAL; - - strncpy(dhd->fw_path, fw, sizeof(dhd->fw_path) - 1); - dhd->fw_path[sizeof(dhd->fw_path)-1] = '\0'; - -#if defined(SOFTAP) - if (strstr(fw, "apsta") != NULL) { - DHD_INFO(("GOT APSTA FIRMWARE\n")); - ap_fw_loaded = TRUE; - } else { - DHD_INFO(("GOT STA FIRMWARE\n")); - ap_fw_loaded = FALSE; - } -#endif - return 0; -} - -void dhd_net_if_lock(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - dhd_net_if_lock_local(dhd); -} - -void dhd_net_if_unlock(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - dhd_net_if_unlock_local(dhd); -} - -static void dhd_net_if_lock_local(dhd_info_t *dhd) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - if (dhd) - mutex_lock(&dhd->dhd_net_if_mutex); -#endif -} - -static void dhd_net_if_unlock_local(dhd_info_t *dhd) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - if (dhd) - mutex_unlock(&dhd->dhd_net_if_mutex); -#endif -} - -static void dhd_suspend_lock(dhd_pub_t *pub) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - if (dhd) - mutex_lock(&dhd->dhd_suspend_mutex); -#endif -} - -static void dhd_suspend_unlock(dhd_pub_t *pub) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - if (dhd) - mutex_unlock(&dhd->dhd_suspend_mutex); -#endif -} - -unsigned long dhd_os_general_spin_lock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags = 0; - - if (dhd) - spin_lock_irqsave(&dhd->dhd_lock, flags); - - return flags; -} - -void dhd_os_general_spin_unlock(dhd_pub_t *pub, unsigned long flags) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) - spin_unlock_irqrestore(&dhd->dhd_lock, flags); -} - -/* Linux specific multipurpose spinlock API */ -void * -dhd_os_spin_lock_init(osl_t *osh) -{ - /* Adding 4 bytes since the sizeof(spinlock_t) could be 0 */ - /* if CONFIG_SMP and CONFIG_DEBUG_SPINLOCK are not defined */ - /* and this results in kernel asserts in internal builds */ - spinlock_t * lock = MALLOC(osh, sizeof(spinlock_t) + 4); - if (lock) - spin_lock_init(lock); - return ((void *)lock); -} -void -dhd_os_spin_lock_deinit(osl_t *osh, void *lock) -{ - if (lock) - MFREE(osh, lock, sizeof(spinlock_t) + 4); -} -unsigned long -dhd_os_spin_lock(void *lock) -{ - unsigned long flags = 0; - - if (lock) - spin_lock_irqsave((spinlock_t *)lock, flags); - - return flags; -} -void -dhd_os_spin_unlock(void *lock, unsigned long flags) -{ - if (lock) - spin_unlock_irqrestore((spinlock_t *)lock, flags); -} - -static int -dhd_get_pend_8021x_cnt(dhd_info_t *dhd) -{ - return (atomic_read(&dhd->pend_8021x_cnt)); -} - -#define MAX_WAIT_FOR_8021X_TX 100 - -int -dhd_wait_pend8021x(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int timeout = msecs_to_jiffies(10); - int ntimes = MAX_WAIT_FOR_8021X_TX; - int pend = dhd_get_pend_8021x_cnt(dhd); - - while (ntimes && pend) { - if (pend) { - set_current_state(TASK_INTERRUPTIBLE); - DHD_PERIM_UNLOCK(&dhd->pub); - schedule_timeout(timeout); - DHD_PERIM_LOCK(&dhd->pub); - set_current_state(TASK_RUNNING); - ntimes--; - } - pend = dhd_get_pend_8021x_cnt(dhd); - } - if (ntimes == 0) - { - atomic_set(&dhd->pend_8021x_cnt, 0); - DHD_ERROR(("%s: TIMEOUT\n", __FUNCTION__)); - } - return pend; -} - -#if defined(DHD_DEBUG) -int write_file(const char * file_name, uint32 flags, uint8 *buf, int size) -{ - int ret = 0; - struct file *fp = NULL; - mm_segment_t old_fs; - loff_t pos = 0; - /* change to KERNEL_DS address limit */ - old_fs = get_fs(); - set_fs(KERNEL_DS); - - /* open file to write */ - fp = filp_open(file_name, flags, 0664); - if (IS_ERR(fp)) { - DHD_ERROR(("open file error, err = %ld\n", PTR_ERR(fp))); - ret = -1; - goto exit; - } - - /* Write buf to file */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) - ret = kernel_write(fp, buf, size, &pos); -#else - ret = vfs_write(fp, buf, size, &pos); -#endif - if (ret < 0) { - DHD_ERROR(("write file error, err = %d\n", ret)); - goto exit; - } - - /* Sync file from filesystem to physical media */ - ret = vfs_fsync(fp, 0); - if (ret < 0) { - DHD_ERROR(("sync file error, error = %d\n", ret)); - goto exit; - } - ret = BCME_OK; - -exit: - /* close file before return */ - if (!IS_ERR(fp)) - filp_close(fp, current->files); - - /* restore previous address limit */ - set_fs(old_fs); - - return ret; -} -#endif - -#ifdef DHD_DEBUG -static void -dhd_convert_memdump_type_to_str(uint32 type, char *buf) -{ - char *type_str = NULL; - - switch (type) { - case DUMP_TYPE_RESUMED_ON_TIMEOUT: - type_str = "resumed_on_timeout"; - break; - case DUMP_TYPE_D3_ACK_TIMEOUT: - type_str = "D3_ACK_timeout"; - break; - case DUMP_TYPE_DONGLE_TRAP: - type_str = "Dongle_Trap"; - break; - case DUMP_TYPE_MEMORY_CORRUPTION: - type_str = "Memory_Corruption"; - break; - case DUMP_TYPE_PKTID_AUDIT_FAILURE: - type_str = "PKTID_AUDIT_Fail"; - break; - case DUMP_TYPE_PKTID_INVALID: - type_str = "PKTID_INVALID"; - break; - case DUMP_TYPE_SCAN_TIMEOUT: - type_str = "SCAN_timeout"; - break; - case DUMP_TYPE_JOIN_TIMEOUT: - type_str = "JOIN_timeout"; - break; - case DUMP_TYPE_SCAN_BUSY: - type_str = "SCAN_Busy"; - break; - case DUMP_TYPE_BY_SYSDUMP: - type_str = "BY_SYSDUMP"; - break; - case DUMP_TYPE_BY_LIVELOCK: - type_str = "BY_LIVELOCK"; - break; - case DUMP_TYPE_AP_LINKUP_FAILURE: - type_str = "BY_AP_LINK_FAILURE"; - break; - case DUMP_TYPE_AP_ABNORMAL_ACCESS: - type_str = "INVALID_ACCESS"; - break; - case DUMP_TYPE_CFG_VENDOR_TRIGGERED: - type_str = "CFG_VENDOR_TRIGGERED"; - break; - case DUMP_TYPE_RESUMED_ON_TIMEOUT_RX: - type_str = "ERROR_RX_TIMED_OUT"; - break; - case DUMP_TYPE_RESUMED_ON_TIMEOUT_TX: - type_str = "ERROR_TX_TIMED_OUT"; - break; - case DUMP_TYPE_RESUMED_ON_INVALID_RING_RDWR: - type_str = "BY_INVALID_RING_RDWR"; - break; - case DUMP_TYPE_DONGLE_HOST_EVENT: - type_str = "BY_DONGLE_HOST_EVENT"; - break; - case DUMP_TYPE_TRANS_ID_MISMATCH: - type_str = "BY_TRANS_ID_MISMATCH"; - break; - case DUMP_TYPE_HANG_ON_IFACE_OP_FAIL: - type_str = "HANG_IFACE_OP_FAIL"; - break; -#ifdef SUPPORT_LINKDOWN_RECOVERY - case DUMP_TYPE_READ_SHM_FAIL: - type_str = "READ_SHM_FAIL"; - break; -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - default: - type_str = "Unknown_type"; - break; - } - - strncpy(buf, type_str, strlen(type_str)); - buf[strlen(type_str)] = 0; -} - -int -write_dump_to_file(dhd_pub_t *dhd, uint8 *buf, int size, char *fname) -{ - int ret = 0; - char memdump_path[128]; - char memdump_type[32]; - struct timeval curtime; - uint32 file_mode; - - /* Init file name */ - memset(memdump_path, 0, sizeof(memdump_path)); - memset(memdump_type, 0, sizeof(memdump_type)); - do_gettimeofday(&curtime); - dhd_convert_memdump_type_to_str(dhd->memdump_type, memdump_type); -#ifdef CUSTOMER_HW4_DEBUG - snprintf(memdump_path, sizeof(memdump_path), "%s%s_%s_%ld.%ld", - DHD_COMMON_DUMP_PATH, fname, memdump_type, - (unsigned long)curtime.tv_sec, (unsigned long)curtime.tv_usec); - file_mode = O_CREAT | O_WRONLY | O_SYNC; -#elif defined(CUSTOMER_HW2) - snprintf(memdump_path, sizeof(memdump_path), "%s%s_%s_%ld.%ld", - "/data/misc/wifi/", fname, memdump_type, - (unsigned long)curtime.tv_sec, (unsigned long)curtime.tv_usec); - file_mode = O_CREAT | O_WRONLY | O_SYNC; -#elif (defined(BOARD_PANDA) || defined(__ARM_ARCH_7A__)) - snprintf(memdump_path, sizeof(memdump_path), "%s%s_%s_%ld.%ld", - "/data/misc/wifi/", fname, memdump_type, - (unsigned long)curtime.tv_sec, (unsigned long)curtime.tv_usec); - file_mode = O_CREAT | O_WRONLY; -#else - snprintf(memdump_path, sizeof(memdump_path), "%s%s_%s_%ld.%ld", - "/installmedia/", fname, memdump_type, - (unsigned long)curtime.tv_sec, (unsigned long)curtime.tv_usec); - /* Extra flags O_DIRECT and O_SYNC are required for Brix Android, as we are - * calling BUG_ON immediately after collecting the socram dump. - * So the file write operation should directly write the contents into the - * file instead of caching it. O_TRUNC flag ensures that file will be re-written - * instead of appending. - */ - file_mode = O_CREAT | O_WRONLY | O_SYNC; - { - struct file *fp = filp_open(memdump_path, file_mode, 0664); - /* Check if it is live Brix image having /installmedia, else use /data */ - if (IS_ERR(fp)) { - DHD_ERROR(("open file %s, try /data/\n", memdump_path)); - snprintf(memdump_path, sizeof(memdump_path), "%s%s_%s_%ld.%ld", - "/data/", fname, memdump_type, - (unsigned long)curtime.tv_sec, (unsigned long)curtime.tv_usec); - } else { - filp_close(fp, NULL); - } - } -#endif /* CUSTOMER_HW4_DEBUG */ - - /* print SOCRAM dump file path */ - DHD_ERROR(("%s: file_path = %s\n", __FUNCTION__, memdump_path)); - - /* Write file */ - ret = write_file(memdump_path, file_mode, buf, size); - - return ret; -} -#endif /* DHD_DEBUG */ - -int dhd_os_wake_lock_timeout(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd && (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - ret = dhd->wakelock_rx_timeout_enable > dhd->wakelock_ctrl_timeout_enable ? - dhd->wakelock_rx_timeout_enable : dhd->wakelock_ctrl_timeout_enable; -#ifdef CONFIG_HAS_WAKELOCK - if (dhd->wakelock_rx_timeout_enable) - wake_lock_timeout(&dhd->wl_rxwake, - msecs_to_jiffies(dhd->wakelock_rx_timeout_enable)); - if (dhd->wakelock_ctrl_timeout_enable) - wake_lock_timeout(&dhd->wl_ctrlwake, - msecs_to_jiffies(dhd->wakelock_ctrl_timeout_enable)); -#endif - dhd->wakelock_rx_timeout_enable = 0; - dhd->wakelock_ctrl_timeout_enable = 0; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -int net_os_wake_lock_timeout(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_lock_timeout(&dhd->pub); - return ret; -} - -int dhd_os_wake_lock_rx_timeout_enable(dhd_pub_t *pub, int val) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - - if (dhd && (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (val > dhd->wakelock_rx_timeout_enable) - dhd->wakelock_rx_timeout_enable = val; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return 0; -} - -int dhd_os_wake_lock_ctrl_timeout_enable(dhd_pub_t *pub, int val) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - - if (dhd && (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (val > dhd->wakelock_ctrl_timeout_enable) - dhd->wakelock_ctrl_timeout_enable = val; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return 0; -} - -int dhd_os_wake_lock_ctrl_timeout_cancel(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - - if (dhd && (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - dhd->wakelock_ctrl_timeout_enable = 0; -#ifdef CONFIG_HAS_WAKELOCK - if (wake_lock_active(&dhd->wl_ctrlwake)) - wake_unlock(&dhd->wl_ctrlwake); -#endif - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return 0; -} - -int net_os_wake_lock_rx_timeout_enable(struct net_device *dev, int val) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_lock_rx_timeout_enable(&dhd->pub, val); - return ret; -} - -int net_os_wake_lock_ctrl_timeout_enable(struct net_device *dev, int val) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_lock_ctrl_timeout_enable(&dhd->pub, val); - return ret; -} - - -#if defined(DHD_TRACE_WAKE_LOCK) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) -#include <linux/hashtable.h> -#else -#include <linux/hash.h> -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ - - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) -/* Define 2^5 = 32 bucket size hash table */ -DEFINE_HASHTABLE(wklock_history, 5); -#else -/* Define 2^5 = 32 bucket size hash table */ -struct hlist_head wklock_history[32] = { [0 ... 31] = HLIST_HEAD_INIT }; -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ - -int trace_wklock_onoff = 1; -typedef enum dhd_wklock_type { - DHD_WAKE_LOCK, - DHD_WAKE_UNLOCK, - DHD_WAIVE_LOCK, - DHD_RESTORE_LOCK -} dhd_wklock_t; - -struct wk_trace_record { - unsigned long addr; /* Address of the instruction */ - dhd_wklock_t lock_type; /* lock_type */ - unsigned long long counter; /* counter information */ - struct hlist_node wklock_node; /* hash node */ -}; - -static struct wk_trace_record *find_wklock_entry(unsigned long addr) -{ - struct wk_trace_record *wklock_info; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) - hash_for_each_possible(wklock_history, wklock_info, wklock_node, addr) -#else - struct hlist_node *entry; - int index = hash_long(addr, ilog2(ARRAY_SIZE(wklock_history))); - hlist_for_each_entry(wklock_info, entry, &wklock_history[index], wklock_node) -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ - { - if (wklock_info->addr == addr) { - return wklock_info; - } - } - return NULL; -} - - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) -#define HASH_ADD(hashtable, node, key) \ - do { \ - hash_add(hashtable, node, key); \ - } while (0); -#else -#define HASH_ADD(hashtable, node, key) \ - do { \ - int index = hash_long(key, ilog2(ARRAY_SIZE(hashtable))); \ - hlist_add_head(node, &hashtable[index]); \ - } while (0); -#endif /* KERNEL_VER < KERNEL_VERSION(3, 7, 0) */ - -#define STORE_WKLOCK_RECORD(wklock_type) \ - do { \ - struct wk_trace_record *wklock_info = NULL; \ - unsigned long func_addr = (unsigned long)__builtin_return_address(0); \ - wklock_info = find_wklock_entry(func_addr); \ - if (wklock_info) { \ - if (wklock_type == DHD_WAIVE_LOCK || wklock_type == DHD_RESTORE_LOCK) { \ - wklock_info->counter = dhd->wakelock_counter; \ - } else { \ - wklock_info->counter++; \ - } \ - } else { \ - wklock_info = kzalloc(sizeof(*wklock_info), GFP_ATOMIC); \ - if (!wklock_info) {\ - printk("Can't allocate wk_trace_record \n"); \ - } else { \ - wklock_info->addr = func_addr; \ - wklock_info->lock_type = wklock_type; \ - if (wklock_type == DHD_WAIVE_LOCK || \ - wklock_type == DHD_RESTORE_LOCK) { \ - wklock_info->counter = dhd->wakelock_counter; \ - } else { \ - wklock_info->counter++; \ - } \ - HASH_ADD(wklock_history, &wklock_info->wklock_node, func_addr); \ - } \ - } \ - } while (0); - -static inline void dhd_wk_lock_rec_dump(void) -{ - int bkt; - struct wk_trace_record *wklock_info; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) - hash_for_each(wklock_history, bkt, wklock_info, wklock_node) -#else - struct hlist_node *entry = NULL; - int max_index = ARRAY_SIZE(wklock_history); - for (bkt = 0; bkt < max_index; bkt++) - hlist_for_each_entry(wklock_info, entry, &wklock_history[bkt], wklock_node) -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ - { - switch (wklock_info->lock_type) { - case DHD_WAKE_LOCK: - printk("wakelock lock : %pS lock_counter : %llu \n", - (void *)wklock_info->addr, wklock_info->counter); - break; - case DHD_WAKE_UNLOCK: - printk("wakelock unlock : %pS, unlock_counter : %llu \n", - (void *)wklock_info->addr, wklock_info->counter); - break; - case DHD_WAIVE_LOCK: - printk("wakelock waive : %pS before_waive : %llu \n", - (void *)wklock_info->addr, wklock_info->counter); - break; - case DHD_RESTORE_LOCK: - printk("wakelock restore : %pS, after_waive : %llu \n", - (void *)wklock_info->addr, wklock_info->counter); - break; - } - } -} - -static void dhd_wk_lock_trace_init(struct dhd_info *dhd) -{ - unsigned long flags; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) - int i; -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ - - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) - hash_init(wklock_history); -#else - for (i = 0; i < ARRAY_SIZE(wklock_history); i++) - INIT_HLIST_HEAD(&wklock_history[i]); -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); -} - -static void dhd_wk_lock_trace_deinit(struct dhd_info *dhd) -{ - int bkt; - struct wk_trace_record *wklock_info; - struct hlist_node *tmp; - unsigned long flags; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) - struct hlist_node *entry = NULL; - int max_index = ARRAY_SIZE(wklock_history); -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0) */ - - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) - hash_for_each_safe(wklock_history, bkt, tmp, wklock_info, wklock_node) -#else - for (bkt = 0; bkt < max_index; bkt++) - hlist_for_each_entry_safe(wklock_info, entry, tmp, - &wklock_history[bkt], wklock_node) -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0)) */ - { -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) - hash_del(&wklock_info->wklock_node); -#else - hlist_del_init(&wklock_info->wklock_node); -#endif /* KERNEL_VER >= KERNEL_VERSION(3, 7, 0)) */ - kfree(wklock_info); - } - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); -} - -void dhd_wk_lock_stats_dump(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - unsigned long flags; - - printk(KERN_ERR"DHD Printing wl_wake Lock/Unlock Record \r\n"); - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - dhd_wk_lock_rec_dump(); - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - -} -#else -#define STORE_WKLOCK_RECORD(wklock_type) -#endif /* ! DHD_TRACE_WAKE_LOCK */ - -int dhd_os_wake_lock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd && (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) { -#ifdef CONFIG_HAS_WAKELOCK - wake_lock(&dhd->wl_wifi); -#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_bus_dev_pm_stay_awake(pub); -#endif - } -#ifdef DHD_TRACE_WAKE_LOCK - if (trace_wklock_onoff) { - STORE_WKLOCK_RECORD(DHD_WAKE_LOCK); - } -#endif /* DHD_TRACE_WAKE_LOCK */ - dhd->wakelock_counter++; - ret = dhd->wakelock_counter; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - - return ret; -} - -void dhd_event_wake_lock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) { -#ifdef CONFIG_HAS_WAKELOCK - wake_lock(&dhd->wl_evtwake); -#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_bus_dev_pm_stay_awake(pub); -#endif - } -} - -void -dhd_pm_wake_lock_timeout(dhd_pub_t *pub, int val) -{ -#ifdef CONFIG_HAS_WAKELOCK - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - wake_lock_timeout(&dhd->wl_pmwake, msecs_to_jiffies(val)); - } -#endif /* CONFIG_HAS_WAKE_LOCK */ -} - -void -dhd_txfl_wake_lock_timeout(dhd_pub_t *pub, int val) -{ -#ifdef CONFIG_HAS_WAKELOCK - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - wake_lock_timeout(&dhd->wl_txflwake, msecs_to_jiffies(val)); - } -#endif /* CONFIG_HAS_WAKE_LOCK */ -} - -int net_os_wake_lock(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_lock(&dhd->pub); - return ret; -} - -int dhd_os_wake_unlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - dhd_os_wake_lock_timeout(pub); - if (dhd && (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - - if (dhd->wakelock_counter > 0) { - dhd->wakelock_counter--; -#ifdef DHD_TRACE_WAKE_LOCK - if (trace_wklock_onoff) { - STORE_WKLOCK_RECORD(DHD_WAKE_UNLOCK); - } -#endif /* DHD_TRACE_WAKE_LOCK */ - if (dhd->wakelock_counter == 0 && !dhd->waive_wakelock) { -#ifdef CONFIG_HAS_WAKELOCK - wake_unlock(&dhd->wl_wifi); -#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_bus_dev_pm_relax(pub); -#endif - } - ret = dhd->wakelock_counter; - } - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -void dhd_event_wake_unlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) { -#ifdef CONFIG_HAS_WAKELOCK - wake_unlock(&dhd->wl_evtwake); -#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_bus_dev_pm_relax(pub); -#endif - } -} - -void dhd_pm_wake_unlock(dhd_pub_t *pub) -{ -#ifdef CONFIG_HAS_WAKELOCK - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - /* if wl_pmwake is active, unlock it */ - if (wake_lock_active(&dhd->wl_pmwake)) { - wake_unlock(&dhd->wl_pmwake); - } - } -#endif /* CONFIG_HAS_WAKELOCK */ -} - -void dhd_txfl_wake_unlock(dhd_pub_t *pub) -{ -#ifdef CONFIG_HAS_WAKELOCK - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - /* if wl_txflwake is active, unlock it */ - if (wake_lock_active(&dhd->wl_txflwake)) { - wake_unlock(&dhd->wl_txflwake); - } - } -#endif /* CONFIG_HAS_WAKELOCK */ -} - -int dhd_os_check_wakelock(dhd_pub_t *pub) -{ -#if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \ - KERNEL_VERSION(2, 6, 36))) - dhd_info_t *dhd; - - if (!pub) - return 0; - dhd = (dhd_info_t *)(pub->info); -#endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */ - -#ifdef CONFIG_HAS_WAKELOCK - /* Indicate to the SD Host to avoid going to suspend if internal locks are up */ - if (dhd && (wake_lock_active(&dhd->wl_wifi) || - (wake_lock_active(&dhd->wl_wdwake)))) - return 1; -#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub)) - return 1; -#endif - return 0; -} - -int -dhd_os_check_wakelock_all(dhd_pub_t *pub) -{ -#if defined(CONFIG_HAS_WAKELOCK) || (defined(BCMSDIO) && (LINUX_VERSION_CODE > \ - KERNEL_VERSION(2, 6, 36))) -#if defined(CONFIG_HAS_WAKELOCK) - int l1, l2, l3, l4, l7, l8, l9; - int l5 = 0, l6 = 0; - int c, lock_active; -#endif /* CONFIG_HAS_WAKELOCK */ - dhd_info_t *dhd; - - if (!pub) { - return 0; - } - dhd = (dhd_info_t *)(pub->info); - if (!dhd) { - return 0; - } -#endif /* CONFIG_HAS_WAKELOCK || BCMSDIO */ - -#ifdef CONFIG_HAS_WAKELOCK - c = dhd->wakelock_counter; - l1 = wake_lock_active(&dhd->wl_wifi); - l2 = wake_lock_active(&dhd->wl_wdwake); - l3 = wake_lock_active(&dhd->wl_rxwake); - l4 = wake_lock_active(&dhd->wl_ctrlwake); - l7 = wake_lock_active(&dhd->wl_evtwake); -#ifdef BCMPCIE_OOB_HOST_WAKE - l5 = wake_lock_active(&dhd->wl_intrwake); -#endif /* BCMPCIE_OOB_HOST_WAKE */ -#ifdef DHD_USE_SCAN_WAKELOCK - l6 = wake_lock_active(&dhd->wl_scanwake); -#endif /* DHD_USE_SCAN_WAKELOCK */ - l8 = wake_lock_active(&dhd->wl_pmwake); - l9 = wake_lock_active(&dhd->wl_txflwake); - lock_active = (l1 || l2 || l3 || l4 || l5 || l6 || l7 || l8 || l9); - - /* Indicate to the Host to avoid going to suspend if internal locks are up */ - if (lock_active) { - DHD_ERROR(("%s wakelock c-%d wl-%d wd-%d rx-%d " - "ctl-%d intr-%d scan-%d evt-%d, pm-%d, txfl-%d\n", - __FUNCTION__, c, l1, l2, l3, l4, l5, l6, l7, l8, l9)); - return 1; - } -#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - if (dhd && (dhd->wakelock_counter > 0) && dhd_bus_dev_pm_enabled(pub)) { - return 1; - } -#endif /* defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */ - return 0; -} - -int net_os_wake_unlock(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_unlock(&dhd->pub); - return ret; -} - -int dhd_os_wd_wake_lock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); -#ifdef CONFIG_HAS_WAKELOCK - /* if wakelock_wd_counter was never used : lock it at once */ - if (!dhd->wakelock_wd_counter) - wake_lock(&dhd->wl_wdwake); -#endif - dhd->wakelock_wd_counter++; - ret = dhd->wakelock_wd_counter; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -int dhd_os_wd_wake_unlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (dhd->wakelock_wd_counter) { - dhd->wakelock_wd_counter = 0; -#ifdef CONFIG_HAS_WAKELOCK - wake_unlock(&dhd->wl_wdwake); -#endif - } - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -#ifdef BCMPCIE_OOB_HOST_WAKE -void -dhd_os_oob_irq_wake_lock_timeout(dhd_pub_t *pub, int val) -{ -#ifdef CONFIG_HAS_WAKELOCK - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - wake_lock_timeout(&dhd->wl_intrwake, msecs_to_jiffies(val)); - } -#endif /* CONFIG_HAS_WAKELOCK */ -} - -void -dhd_os_oob_irq_wake_unlock(dhd_pub_t *pub) -{ -#ifdef CONFIG_HAS_WAKELOCK - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - /* if wl_intrwake is active, unlock it */ - if (wake_lock_active(&dhd->wl_intrwake)) { - wake_unlock(&dhd->wl_intrwake); - } - } -#endif /* CONFIG_HAS_WAKELOCK */ -} -#endif /* BCMPCIE_OOB_HOST_WAKE */ - -#ifdef DHD_USE_SCAN_WAKELOCK -void -dhd_os_scan_wake_lock_timeout(dhd_pub_t *pub, int val) -{ -#ifdef CONFIG_HAS_WAKELOCK - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - wake_lock_timeout(&dhd->wl_scanwake, msecs_to_jiffies(val)); - } -#endif /* CONFIG_HAS_WAKELOCK */ -} - -void -dhd_os_scan_wake_unlock(dhd_pub_t *pub) -{ -#ifdef CONFIG_HAS_WAKELOCK - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - /* if wl_scanwake is active, unlock it */ - if (wake_lock_active(&dhd->wl_scanwake)) { - wake_unlock(&dhd->wl_scanwake); - } - } -#endif /* CONFIG_HAS_WAKELOCK */ -} -#endif /* DHD_USE_SCAN_WAKELOCK */ - -/* waive wakelocks for operations such as IOVARs in suspend function, must be closed - * by a paired function call to dhd_wakelock_restore. returns current wakelock counter - */ -int dhd_os_wake_lock_waive(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd && (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT)) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - - /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */ - if (dhd->waive_wakelock == FALSE) { -#ifdef DHD_TRACE_WAKE_LOCK - if (trace_wklock_onoff) { - STORE_WKLOCK_RECORD(DHD_WAIVE_LOCK); - } -#endif /* DHD_TRACE_WAKE_LOCK */ - /* record current lock status */ - dhd->wakelock_before_waive = dhd->wakelock_counter; - dhd->waive_wakelock = TRUE; - } - ret = dhd->wakelock_wd_counter; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -int dhd_os_wake_lock_restore(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (!dhd) - return 0; - if ((dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) == 0) - return 0; - - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - - /* dhd_wakelock_waive/dhd_wakelock_restore must be paired */ - if (!dhd->waive_wakelock) - goto exit; - - dhd->waive_wakelock = FALSE; - /* if somebody else acquires wakelock between dhd_wakelock_waive/dhd_wakelock_restore, - * we need to make it up by calling wake_lock or pm_stay_awake. or if somebody releases - * the lock in between, do the same by calling wake_unlock or pm_relax - */ -#ifdef DHD_TRACE_WAKE_LOCK - if (trace_wklock_onoff) { - STORE_WKLOCK_RECORD(DHD_RESTORE_LOCK); - } -#endif /* DHD_TRACE_WAKE_LOCK */ - - if (dhd->wakelock_before_waive == 0 && dhd->wakelock_counter > 0) { -#ifdef CONFIG_HAS_WAKELOCK - wake_lock(&dhd->wl_wifi); -#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_bus_dev_pm_stay_awake(&dhd->pub); -#endif - } else if (dhd->wakelock_before_waive > 0 && dhd->wakelock_counter == 0) { -#ifdef CONFIG_HAS_WAKELOCK - wake_unlock(&dhd->wl_wifi); -#elif defined(BCMSDIO) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) - dhd_bus_dev_pm_relax(&dhd->pub); -#endif - } - dhd->wakelock_before_waive = 0; -exit: - ret = dhd->wakelock_wd_counter; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - return ret; -} - -void dhd_os_wake_lock_init(struct dhd_info *dhd) -{ - DHD_TRACE(("%s: initialize wake_lock_counters\n", __FUNCTION__)); - dhd->wakelock_counter = 0; - dhd->wakelock_rx_timeout_enable = 0; - dhd->wakelock_ctrl_timeout_enable = 0; -#ifdef CONFIG_HAS_WAKELOCK - // terence 20161023: can not destroy wl_wifi when wlan down, it will happen null pointer in dhd_ioctl_entry - wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); - wake_lock_init(&dhd->wl_ctrlwake, WAKE_LOCK_SUSPEND, "wlan_ctrl_wake"); - wake_lock_init(&dhd->wl_evtwake, WAKE_LOCK_SUSPEND, "wlan_evt_wake"); - wake_lock_init(&dhd->wl_pmwake, WAKE_LOCK_SUSPEND, "wlan_pm_wake"); - wake_lock_init(&dhd->wl_txflwake, WAKE_LOCK_SUSPEND, "wlan_txfl_wake"); -#ifdef BCMPCIE_OOB_HOST_WAKE - wake_lock_init(&dhd->wl_intrwake, WAKE_LOCK_SUSPEND, "wlan_oob_irq_wake"); -#endif /* BCMPCIE_OOB_HOST_WAKE */ -#ifdef DHD_USE_SCAN_WAKELOCK - wake_lock_init(&dhd->wl_scanwake, WAKE_LOCK_SUSPEND, "wlan_scan_wake"); -#endif /* DHD_USE_SCAN_WAKELOCK */ -#endif /* CONFIG_HAS_WAKELOCK */ -#ifdef DHD_TRACE_WAKE_LOCK - dhd_wk_lock_trace_init(dhd); -#endif /* DHD_TRACE_WAKE_LOCK */ -} - -void dhd_os_wake_lock_destroy(struct dhd_info *dhd) -{ - DHD_TRACE(("%s: deinit wake_lock_counters\n", __FUNCTION__)); -#ifdef CONFIG_HAS_WAKELOCK - dhd->wakelock_counter = 0; - dhd->wakelock_rx_timeout_enable = 0; - dhd->wakelock_ctrl_timeout_enable = 0; - // terence 20161023: can not destroy wl_wifi when wlan down, it will happen null pointer in dhd_ioctl_entry - wake_lock_destroy(&dhd->wl_rxwake); - wake_lock_destroy(&dhd->wl_ctrlwake); - wake_lock_destroy(&dhd->wl_evtwake); - wake_lock_destroy(&dhd->wl_pmwake); - wake_lock_destroy(&dhd->wl_txflwake); -#ifdef BCMPCIE_OOB_HOST_WAKE - wake_lock_destroy(&dhd->wl_intrwake); -#endif /* BCMPCIE_OOB_HOST_WAKE */ -#ifdef DHD_USE_SCAN_WAKELOCK - wake_lock_destroy(&dhd->wl_scanwake); -#endif /* DHD_USE_SCAN_WAKELOCK */ -#ifdef DHD_TRACE_WAKE_LOCK - dhd_wk_lock_trace_deinit(dhd); -#endif /* DHD_TRACE_WAKE_LOCK */ -#endif /* CONFIG_HAS_WAKELOCK */ -} - -bool dhd_os_check_if_up(dhd_pub_t *pub) -{ - if (!pub) - return FALSE; - return pub->up; -} - -/* function to collect firmware, chip id and chip version info */ -void dhd_set_version_info(dhd_pub_t *dhdp, char *fw) -{ - int i; - - i = snprintf(info_string, sizeof(info_string), - "Firmware: %s CLM: %s ", fw, clm_version); - DHD_ERROR(("%s\n", info_string)); - - if (!dhdp) - return; - - i = snprintf(&info_string[i], sizeof(info_string) - i, - "\n Chip: %x Rev %x", dhd_conf_get_chip(dhdp), - dhd_conf_get_chiprev(dhdp)); -} - -int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) -{ - int ifidx; - int ret = 0; - dhd_info_t *dhd = NULL; - - if (!net || !DEV_PRIV(net)) { - DHD_ERROR(("%s invalid parameter\n", __FUNCTION__)); - return -EINVAL; - } - - dhd = DHD_DEV_INFO(net); - if (!dhd) - return -EINVAL; - - ifidx = dhd_net2idx(dhd, net); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s bad ifidx\n", __FUNCTION__)); - return -ENODEV; - } - - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_PERIM_LOCK(&dhd->pub); - - ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len); - dhd_check_hang(net, &dhd->pub, ret); - - DHD_PERIM_UNLOCK(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - return ret; -} - -bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret) -{ - struct net_device *net; - - net = dhd_idx2net(dhdp, ifidx); - if (!net) { - DHD_ERROR(("%s : Invalid index : %d\n", __FUNCTION__, ifidx)); - return -EINVAL; - } - - return dhd_check_hang(net, dhdp, ret); -} - -/* Return instance */ -int dhd_get_instance(dhd_pub_t *dhdp) -{ - return dhdp->info->unit; -} - - -#ifdef PROP_TXSTATUS - -void dhd_wlfc_plat_init(void *dhd) -{ -#ifdef USE_DYNAMIC_F2_BLKSIZE - dhdsdio_func_blocksize((dhd_pub_t *)dhd, 2, DYNAMIC_F2_BLKSIZE_FOR_NONLEGACY); -#endif /* USE_DYNAMIC_F2_BLKSIZE */ - return; -} - -void dhd_wlfc_plat_deinit(void *dhd) -{ -#ifdef USE_DYNAMIC_F2_BLKSIZE - dhdsdio_func_blocksize((dhd_pub_t *)dhd, 2, sd_f2_blocksize); -#endif /* USE_DYNAMIC_F2_BLKSIZE */ - return; -} - -bool dhd_wlfc_skip_fc(void * dhdp, uint8 idx) -{ -#ifdef SKIP_WLFC_ON_CONCURRENT - -#ifdef WL_CFG80211 - struct net_device * net = dhd_idx2net((dhd_pub_t *)dhdp, idx); - if (net) - /* enable flow control in vsdb mode */ - return !(wl_cfg80211_is_concurrent_mode(net)); -#else - return TRUE; /* skip flow control */ -#endif /* WL_CFG80211 */ - -#else - return FALSE; -#endif /* SKIP_WLFC_ON_CONCURRENT */ - return FALSE; -} -#endif /* PROP_TXSTATUS */ - -#ifdef BCMDBGFS -#include <linux/debugfs.h> - -typedef struct dhd_dbgfs { - struct dentry *debugfs_dir; - struct dentry *debugfs_mem; - dhd_pub_t *dhdp; - uint32 size; -} dhd_dbgfs_t; - -dhd_dbgfs_t g_dbgfs; - -extern uint32 dhd_readregl(void *bp, uint32 addr); -extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data); - -static int -dhd_dbg_state_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t -dhd_dbg_state_read(struct file *file, char __user *ubuf, - size_t count, loff_t *ppos) -{ - ssize_t rval; - uint32 tmp; - loff_t pos = *ppos; - size_t ret; - - if (pos < 0) - return -EINVAL; - if (pos >= g_dbgfs.size || !count) - return 0; - if (count > g_dbgfs.size - pos) - count = g_dbgfs.size - pos; - - /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */ - tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3)); - - ret = copy_to_user(ubuf, &tmp, 4); - if (ret == count) - return -EFAULT; - - count -= ret; - *ppos = pos + count; - rval = count; - - return rval; -} - - -static ssize_t -dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) -{ - loff_t pos = *ppos; - size_t ret; - uint32 buf; - - if (pos < 0) - return -EINVAL; - if (pos >= g_dbgfs.size || !count) - return 0; - if (count > g_dbgfs.size - pos) - count = g_dbgfs.size - pos; - - ret = copy_from_user(&buf, ubuf, sizeof(uint32)); - if (ret == count) - return -EFAULT; - - /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */ - dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf); - - return count; -} - - -loff_t -dhd_debugfs_lseek(struct file *file, loff_t off, int whence) -{ - loff_t pos = -1; - - switch (whence) { - case 0: - pos = off; - break; - case 1: - pos = file->f_pos + off; - break; - case 2: - pos = g_dbgfs.size - off; - } - return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos); -} - -static const struct file_operations dhd_dbg_state_ops = { - .read = dhd_dbg_state_read, - .write = dhd_debugfs_write, - .open = dhd_dbg_state_open, - .llseek = dhd_debugfs_lseek -}; - -static void dhd_dbgfs_create(void) -{ - if (g_dbgfs.debugfs_dir) { - g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir, - NULL, &dhd_dbg_state_ops); - } -} - -void dhd_dbgfs_init(dhd_pub_t *dhdp) -{ - g_dbgfs.dhdp = dhdp; - g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */ - - g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0); - if (IS_ERR(g_dbgfs.debugfs_dir)) { - g_dbgfs.debugfs_dir = NULL; - return; - } - - dhd_dbgfs_create(); - - return; -} - -void dhd_dbgfs_remove(void) -{ - debugfs_remove(g_dbgfs.debugfs_mem); - debugfs_remove(g_dbgfs.debugfs_dir); - - bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs)); -} -#endif /* BCMDBGFS */ - -#ifdef WLMEDIA_HTSF - -static -void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf) -{ - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - struct sk_buff *skb; - uint32 htsf = 0; - uint16 dport = 0, oldmagic = 0xACAC; - char *p1; - htsfts_t ts; - - /* timestamp packet */ - - p1 = (char*) PKTDATA(dhdp->osh, pktbuf); - - if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) { -/* memcpy(&proto, p1+26, 4); */ - memcpy(&dport, p1+40, 2); -/* proto = ((ntoh32(proto))>> 16) & 0xFF; */ - dport = ntoh16(dport); - } - - /* timestamp only if icmp or udb iperf with port 5555 */ -/* if (proto == 17 && dport == tsport) { */ - if (dport >= tsport && dport <= tsport + 20) { - - skb = (struct sk_buff *) pktbuf; - - htsf = dhd_get_htsf(dhd, 0); - memset(skb->data + 44, 0, 2); /* clear checksum */ - memcpy(skb->data+82, &oldmagic, 2); - memcpy(skb->data+84, &htsf, 4); - - memset(&ts, 0, sizeof(htsfts_t)); - ts.magic = HTSFMAGIC; - ts.prio = PKTPRIO(pktbuf); - ts.seqnum = htsf_seqnum++; - ts.c10 = get_cycles(); - ts.t10 = htsf; - ts.endmagic = HTSFENDMAGIC; - - memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts)); - } -} - -static void dhd_dump_htsfhisto(histo_t *his, char *s) -{ - int pktcnt = 0, curval = 0, i; - for (i = 0; i < (NUMBIN-2); i++) { - curval += 500; - DHD_PRINT(("%d ", his->bin[i])); - pktcnt += his->bin[i]; - } - DHD_PRINT((" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt, - his->bin[NUMBIN-1], s)); -} - -static -void sorttobin(int value, histo_t *histo) -{ - int i, binval = 0; - - if (value < 0) { - histo->bin[NUMBIN-1]++; - return; - } - if (value > histo->bin[NUMBIN-2]) /* store the max value */ - histo->bin[NUMBIN-2] = value; - - for (i = 0; i < (NUMBIN-2); i++) { - binval += 500; /* 500m s bins */ - if (value <= binval) { - histo->bin[i]++; - return; - } - } - histo->bin[NUMBIN-3]++; -} - -static -void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - struct sk_buff *skb; - char *p1; - uint16 old_magic; - int d1, d2, d3, end2end; - htsfts_t *htsf_ts; - uint32 htsf; - - skb = PKTTONATIVE(dhdp->osh, pktbuf); - p1 = (char*)PKTDATA(dhdp->osh, pktbuf); - - if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) { - memcpy(&old_magic, p1+78, 2); - htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4); - } else { - return; - } - - if (htsf_ts->magic == HTSFMAGIC) { - htsf_ts->tE0 = dhd_get_htsf(dhd, 0); - htsf_ts->cE0 = get_cycles(); - } - - if (old_magic == 0xACAC) { - - tspktcnt++; - htsf = dhd_get_htsf(dhd, 0); - memcpy(skb->data+92, &htsf, sizeof(uint32)); - - memcpy(&ts[tsidx].t1, skb->data+80, 16); - - d1 = ts[tsidx].t2 - ts[tsidx].t1; - d2 = ts[tsidx].t3 - ts[tsidx].t2; - d3 = ts[tsidx].t4 - ts[tsidx].t3; - end2end = ts[tsidx].t4 - ts[tsidx].t1; - - sorttobin(d1, &vi_d1); - sorttobin(d2, &vi_d2); - sorttobin(d3, &vi_d3); - sorttobin(end2end, &vi_d4); - - if (end2end > 0 && end2end > maxdelay) { - maxdelay = end2end; - maxdelaypktno = tspktcnt; - memcpy(&maxdelayts, &ts[tsidx], 16); - } - if (++tsidx >= TSMAX) - tsidx = 0; - } -} - -uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx) -{ - uint32 htsf = 0, cur_cycle, delta, delta_us; - uint32 factor, baseval, baseval2; - cycles_t t; - - t = get_cycles(); - cur_cycle = t; - - if (cur_cycle > dhd->htsf.last_cycle) - delta = cur_cycle - dhd->htsf.last_cycle; - else { - delta = cur_cycle + (0xFFFFFFFF - dhd->htsf.last_cycle); - } - - delta = delta >> 4; - - if (dhd->htsf.coef) { - /* times ten to get the first digit */ - factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1); - baseval = (delta*10)/factor; - baseval2 = (delta*10)/(factor+1); - delta_us = (baseval - (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10); - htsf = (delta_us << 4) + dhd->htsf.last_tsf + HTSF_BUS_DELAY; - } else { - DHD_ERROR(("-------dhd->htsf.coef = 0 -------\n")); - } - - return htsf; -} - -static void dhd_dump_latency(void) -{ - int i, max = 0; - int d1, d2, d3, d4, d5; - - DHD_PRINT(("T1 T2 T3 T4 d1 d2 t4-t1 i \n")); - for (i = 0; i < TSMAX; i++) { - d1 = ts[i].t2 - ts[i].t1; - d2 = ts[i].t3 - ts[i].t2; - d3 = ts[i].t4 - ts[i].t3; - d4 = ts[i].t4 - ts[i].t1; - d5 = ts[max].t4-ts[max].t1; - if (d4 > d5 && d4 > 0) { - max = i; - } - DHD_PRINT(("%08X %08X %08X %08X \t%d %d %d %d i=%d\n", - ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4, - d1, d2, d3, d4, i)); - } - - DHD_PRINT(("current idx = %d \n", tsidx)); - - DHD_PRINT(("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt)); - DHD_PRINT(("%08X %08X %08X %08X \t%d %d %d %d\n", - maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4, - maxdelayts.t2 - maxdelayts.t1, - maxdelayts.t3 - maxdelayts.t2, - maxdelayts.t4 - maxdelayts.t3, - maxdelayts.t4 - maxdelayts.t1)); -} - - -static int -dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx) -{ - char buf[32]; - int ret; - uint32 s1, s2; - - struct tsf { - uint32 low; - uint32 high; - } tsf_buf; - - memset(&tsf_buf, 0, sizeof(tsf_buf)); - - s1 = dhd_get_htsf(dhd, 0); - ret = dhd_iovar(&dhd->pub, ifidx, "tsf", NULL, 0, buf, sizeof(buf), FALSE); - if (ret < 0) { - if (ret == -EIO) { - DHD_ERROR(("%s: tsf is not supported by device\n", - dhd_ifname(&dhd->pub, ifidx))); - return -EOPNOTSUPP; - } - return ret; - } - s2 = dhd_get_htsf(dhd, 0); - - memcpy(&tsf_buf, buf, sizeof(tsf_buf)); - DHD_INFO((" TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ", - tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1, - dhd->htsf.coefdec2, s2-tsf_buf.low)); - DHD_INFO(("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle)); - return 0; -} - -void htsf_update(dhd_info_t *dhd, void *data) -{ - static ulong cur_cycle = 0, prev_cycle = 0; - uint32 htsf, tsf_delta = 0; - uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp; - ulong b, a; - cycles_t t; - - /* cycles_t in inlcude/mips/timex.h */ - - t = get_cycles(); - - prev_cycle = cur_cycle; - cur_cycle = t; - - if (cur_cycle > prev_cycle) - cyc_delta = cur_cycle - prev_cycle; - else { - b = cur_cycle; - a = prev_cycle; - cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle); - } - - if (data == NULL) - DHD_ERROR((" tsf update ata point er is null \n")); - - memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t)); - memcpy(&cur_tsf, data, sizeof(tsf_t)); - - if (cur_tsf.low == 0) { - DHD_INFO((" ---- 0 TSF, do not update, return\n")); - return; - } - - if (cur_tsf.low > prev_tsf.low) - tsf_delta = (cur_tsf.low - prev_tsf.low); - else { - DHD_INFO((" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n", - cur_tsf.low, prev_tsf.low)); - if (cur_tsf.high > prev_tsf.high) { - tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low); - DHD_INFO((" ---- Wrap around tsf coutner adjusted TSF=%08X\n", tsf_delta)); - } else { - return; /* do not update */ - } - } - - if (tsf_delta) { - hfactor = cyc_delta / tsf_delta; - tmp = (cyc_delta - (hfactor * tsf_delta))*10; - dec1 = tmp/tsf_delta; - dec2 = ((tmp - dec1*tsf_delta)*10) / tsf_delta; - tmp = (tmp - (dec1*tsf_delta))*10; - dec3 = ((tmp - dec2*tsf_delta)*10) / tsf_delta; - - if (dec3 > 4) { - if (dec2 == 9) { - dec2 = 0; - if (dec1 == 9) { - dec1 = 0; - hfactor++; - } else { - dec1++; - } - } else { - dec2++; - } - } - } - - if (hfactor) { - htsf = ((cyc_delta * 10) / (hfactor*10+dec1)) + prev_tsf.low; - dhd->htsf.coef = hfactor; - dhd->htsf.last_cycle = cur_cycle; - dhd->htsf.last_tsf = cur_tsf.low; - dhd->htsf.coefdec1 = dec1; - dhd->htsf.coefdec2 = dec2; - } else { - htsf = prev_tsf.low; - } -} - -#endif /* WLMEDIA_HTSF */ - -#ifdef CUSTOM_SET_CPUCORE -void dhd_set_cpucore(dhd_pub_t *dhd, int set) -{ - int e_dpc = 0, e_rxf = 0, retry_set = 0; - - if (!(dhd->chan_isvht80)) { - DHD_ERROR(("%s: chan_status(%d) cpucore!!!\n", __FUNCTION__, dhd->chan_isvht80)); - return; - } - - if (DPC_CPUCORE) { - do { - if (set == TRUE) { - e_dpc = set_cpus_allowed_ptr(dhd->current_dpc, - cpumask_of(DPC_CPUCORE)); - } else { - e_dpc = set_cpus_allowed_ptr(dhd->current_dpc, - cpumask_of(PRIMARY_CPUCORE)); - } - if (retry_set++ > MAX_RETRY_SET_CPUCORE) { - DHD_ERROR(("%s: dpc(%d) invalid cpu!\n", __FUNCTION__, e_dpc)); - return; - } - if (e_dpc < 0) - OSL_SLEEP(1); - } while (e_dpc < 0); - } - if (RXF_CPUCORE) { - do { - if (set == TRUE) { - e_rxf = set_cpus_allowed_ptr(dhd->current_rxf, - cpumask_of(RXF_CPUCORE)); - } else { - e_rxf = set_cpus_allowed_ptr(dhd->current_rxf, - cpumask_of(PRIMARY_CPUCORE)); - } - if (retry_set++ > MAX_RETRY_SET_CPUCORE) { - DHD_ERROR(("%s: rxf(%d) invalid cpu!\n", __FUNCTION__, e_rxf)); - return; - } - if (e_rxf < 0) - OSL_SLEEP(1); - } while (e_rxf < 0); - } -#ifdef DHD_OF_SUPPORT - interrupt_set_cpucore(set, DPC_CPUCORE, PRIMARY_CPUCORE); -#endif /* DHD_OF_SUPPORT */ - DHD_TRACE(("%s: set(%d) cpucore success!\n", __FUNCTION__, set)); - - return; -} -#endif /* CUSTOM_SET_CPUCORE */ - -#ifdef DHD_MCAST_REGEN -/* Get interface specific ap_isolate configuration */ -int dhd_get_mcast_regen_bss_enable(dhd_pub_t *dhdp, uint32 idx) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - - ASSERT(idx < DHD_MAX_IFS); - - ifp = dhd->iflist[idx]; - - return ifp->mcast_regen_bss_enable; -} - -/* Set interface specific mcast_regen configuration */ -int dhd_set_mcast_regen_bss_enable(dhd_pub_t *dhdp, uint32 idx, int val) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - - ASSERT(idx < DHD_MAX_IFS); - - ifp = dhd->iflist[idx]; - - ifp->mcast_regen_bss_enable = val; - - /* Disable rx_pkt_chain feature for interface, if mcast_regen feature - * is enabled - */ - dhd_update_rx_pkt_chainable_state(dhdp, idx); - return BCME_OK; -} -#endif /* DHD_MCAST_REGEN */ - -/* Get interface specific ap_isolate configuration */ -int dhd_get_ap_isolate(dhd_pub_t *dhdp, uint32 idx) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - - ASSERT(idx < DHD_MAX_IFS); - - ifp = dhd->iflist[idx]; - - return ifp->ap_isolate; -} - -/* Set interface specific ap_isolate configuration */ -int dhd_set_ap_isolate(dhd_pub_t *dhdp, uint32 idx, int val) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - - ASSERT(idx < DHD_MAX_IFS); - - ifp = dhd->iflist[idx]; - - if (ifp) - ifp->ap_isolate = val; - - return 0; -} - -#ifdef DHD_FW_COREDUMP -#if defined(CONFIG_X86) -#define MEMDUMPINFO_LIVE "/installmedia/.memdump.info" -#define MEMDUMPINFO_INST "/data/.memdump.info" -#endif /* CONFIG_X86 && OEM_ANDROID */ - -#ifdef CUSTOMER_HW4_DEBUG -#define MEMDUMPINFO PLATFORM_PATH".memdump.info" -#elif defined(CUSTOMER_HW2) -#define MEMDUMPINFO "/data/misc/wifi/.memdump.info" -#elif (defined(BOARD_PANDA) || defined(__ARM_ARCH_7A__)) -#define MEMDUMPINFO "/data/misc/wifi/.memdump.info" -#else -#define MEMDUMPINFO "/data/misc/wifi/.memdump.info" -#endif /* CUSTOMER_HW4_DEBUG */ - -void dhd_get_memdump_info(dhd_pub_t *dhd) -{ - struct file *fp = NULL; - uint32 mem_val = DUMP_MEMFILE_MAX; - int ret = 0; - char *filepath = MEMDUMPINFO; - - /* Read memdump info from the file */ - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { - DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); -#if defined(CONFIG_X86) - /* Check if it is Live Brix Image */ - if (strcmp(filepath, MEMDUMPINFO_LIVE) != 0) { - goto done; - } - /* Try if it is Installed Brix Image */ - filepath = MEMDUMPINFO_INST; - DHD_ERROR(("%s: Try File [%s]\n", __FUNCTION__, filepath)); - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { - DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); - goto done; - } -#else /* Non Brix Android platform */ - goto done; -#endif /* CONFIG_X86 && OEM_ANDROID */ - } - - /* Handle success case */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) - ret = kernel_read(fp, (char *)&mem_val, 4, NULL); -#else - ret = kernel_read(fp, 0, (char *)&mem_val, 4); -#endif - if (ret < 0) { - DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret)); - filp_close(fp, NULL); - goto done; - } - - mem_val = bcm_atoi((char *)&mem_val); - - filp_close(fp, NULL); - -#ifdef DHD_INIT_DEFAULT_MEMDUMP - if (mem_val == 0 || mem_val == DUMP_MEMFILE_MAX) - mem_val = DUMP_MEMFILE_BUGON; -#endif /* DHD_INIT_DEFAULT_MEMDUMP */ - -done: -#ifdef CUSTOMER_HW4_DEBUG - dhd->memdump_enabled = (mem_val < DUMP_MEMFILE_MAX) ? mem_val : DUMP_DISABLED; -#else - dhd->memdump_enabled = (mem_val < DUMP_MEMFILE_MAX) ? mem_val : DUMP_MEMFILE; -#endif /* CUSTOMER_HW4_DEBUG */ - - DHD_ERROR(("%s: MEMDUMP ENABLED = %d\n", __FUNCTION__, dhd->memdump_enabled)); -} - -void dhd_schedule_memdump(dhd_pub_t *dhdp, uint8 *buf, uint32 size) -{ - dhd_dump_t *dump = NULL; - dump = (dhd_dump_t *)MALLOC(dhdp->osh, sizeof(dhd_dump_t)); - if (dump == NULL) { - DHD_ERROR(("%s: dhd dump memory allocation failed\n", __FUNCTION__)); - return; - } - dump->buf = buf; - dump->bufsize = size; - -#if defined(CONFIG_ARM64) - DHD_ERROR(("%s: buf(va)=%llx, buf(pa)=%llx, bufsize=%d\n", __FUNCTION__, - (uint64)buf, (uint64)__virt_to_phys((ulong)buf), size)); -#elif defined(__ARM_ARCH_7A__) - DHD_ERROR(("%s: buf(va)=%x, buf(pa)=%x, bufsize=%d\n", __FUNCTION__, - (uint32)buf, (uint32)__virt_to_phys((ulong)buf), size)); -#endif /* __ARM_ARCH_7A__ */ - if (dhdp->memdump_enabled == DUMP_MEMONLY) { - BUG_ON(1); - } - -#ifdef DHD_LOG_DUMP - if (dhdp->memdump_type != DUMP_TYPE_BY_SYSDUMP) { - dhd_schedule_log_dump(dhdp); - } -#endif /* DHD_LOG_DUMP */ - dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, (void *)dump, - DHD_WQ_WORK_SOC_RAM_DUMP, dhd_mem_dump, DHD_WQ_WORK_PRIORITY_HIGH); -} - -static void -dhd_mem_dump(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - dhd_dump_t *dump = event_info; - - if (!dhd) { - DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); - return; - } - - if (!dump) { - DHD_ERROR(("%s: dump is NULL\n", __FUNCTION__)); - return; - } - - if (write_dump_to_file(&dhd->pub, dump->buf, dump->bufsize, "mem_dump")) { - DHD_ERROR(("%s: writing SoC_RAM dump to the file failed\n", __FUNCTION__)); - dhd->pub.memdump_success = FALSE; - } - - if (dhd->pub.memdump_enabled == DUMP_MEMFILE_BUGON && -#ifdef DHD_LOG_DUMP - dhd->pub.memdump_type != DUMP_TYPE_BY_SYSDUMP && -#endif /* DHD_LOG_DUMP */ -#ifdef DHD_DEBUG_UART - dhd->pub.memdump_success == TRUE && -#endif /* DHD_DEBUG_UART */ - dhd->pub.memdump_type != DUMP_TYPE_CFG_VENDOR_TRIGGERED) { - -#ifdef SHOW_LOGTRACE - /* Wait till event_log_dispatcher_work finishes */ - cancel_work_sync(&dhd->event_log_dispatcher_work); -#endif /* SHOW_LOGTRACE */ - - BUG_ON(1); - } - MFREE(dhd->pub.osh, dump, sizeof(dhd_dump_t)); -} -#endif /* DHD_FW_COREDUMP */ - -#ifdef DHD_SSSR_DUMP - -static void -dhd_sssr_dump(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - dhd_pub_t *dhdp; - int i; - char before_sr_dump[128]; - char after_sr_dump[128]; - - if (!dhd) { - DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); - return; - } - - dhdp = &dhd->pub; - - for (i = 0; i < MAX_NUM_D11CORES; i++) { - /* Init file name */ - memset(before_sr_dump, 0, sizeof(before_sr_dump)); - memset(after_sr_dump, 0, sizeof(after_sr_dump)); - - snprintf(before_sr_dump, sizeof(before_sr_dump), "%s_%d_%s", - "sssr_core", i, "before_SR"); - snprintf(after_sr_dump, sizeof(after_sr_dump), "%s_%d_%s", - "sssr_core", i, "after_SR"); - - if (dhdp->sssr_d11_before[i] && dhdp->sssr_d11_outofreset[i]) { - if (write_dump_to_file(dhdp, (uint8 *)dhdp->sssr_d11_before[i], - dhdp->sssr_reg_info.mac_regs[i].sr_size, before_sr_dump)) { - DHD_ERROR(("%s: writing SSSR MAIN dump before to the file failed\n", - __FUNCTION__)); - } - } - if (dhdp->sssr_d11_after[i] && dhdp->sssr_d11_outofreset[i]) { - if (write_dump_to_file(dhdp, (uint8 *)dhdp->sssr_d11_after[i], - dhdp->sssr_reg_info.mac_regs[i].sr_size, after_sr_dump)) { - DHD_ERROR(("%s: writing SSSR AUX dump after to the file failed\n", - __FUNCTION__)); - } - } - } - - if (dhdp->sssr_vasip_buf_before) { - if (write_dump_to_file(dhdp, (uint8 *)dhdp->sssr_vasip_buf_before, - dhdp->sssr_reg_info.vasip_regs.vasip_sr_size, "sssr_vasip_before_SR")) { - DHD_ERROR(("%s: writing SSSR VASIP dump before to the file failed\n", - __FUNCTION__)); - } - } - - if (dhdp->sssr_vasip_buf_after) { - if (write_dump_to_file(dhdp, (uint8 *)dhdp->sssr_vasip_buf_after, - dhdp->sssr_reg_info.vasip_regs.vasip_sr_size, "sssr_vasip_after_SR")) { - DHD_ERROR(("%s: writing SSSR VASIP dump after to the file failed\n", - __FUNCTION__)); - } - } - -} - -void -dhd_schedule_sssr_dump(dhd_pub_t *dhdp) -{ - dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, NULL, - DHD_WQ_WORK_SSSR_DUMP, dhd_sssr_dump, DHD_WQ_WORK_PRIORITY_HIGH); -} -#endif /* DHD_SSSR_DUMP */ - -#ifdef DHD_LOG_DUMP -static void -dhd_log_dump(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - - if (!dhd) { - DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); - return; - } - - if (do_dhd_log_dump(&dhd->pub)) { - DHD_ERROR(("%s: writing debug dump to the file failed\n", __FUNCTION__)); - return; - } -} - -void dhd_schedule_log_dump(dhd_pub_t *dhdp) -{ - dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, - (void*)NULL, DHD_WQ_WORK_DHD_LOG_DUMP, - dhd_log_dump, DHD_WQ_WORK_PRIORITY_HIGH); -} - -static int -do_dhd_log_dump(dhd_pub_t *dhdp) -{ - int ret = 0, i = 0; - struct file *fp = NULL; - mm_segment_t old_fs; - loff_t pos = 0; - unsigned int wr_size = 0; - char dump_path[128]; - struct timeval curtime; - uint32 file_mode; - unsigned long flags = 0; - struct dhd_log_dump_buf *dld_buf = &g_dld_buf[0]; - - const char *pre_strs = - "-------------------- General log ---------------------------\n"; - - const char *post_strs = - "-------------------- Specific log --------------------------\n"; - - if (!dhdp) { - return -1; - } - - DHD_ERROR(("DHD version: %s\n", dhd_version)); - DHD_ERROR(("F/W version: %s\n", fw_version)); - - /* change to KERNEL_DS address limit */ - old_fs = get_fs(); - set_fs(KERNEL_DS); - - /* Init file name */ - memset(dump_path, 0, sizeof(dump_path)); - do_gettimeofday(&curtime); - snprintf(dump_path, sizeof(dump_path), "%s_%ld.%ld", - DHD_COMMON_DUMP_PATH "debug_dump", - (unsigned long)curtime.tv_sec, (unsigned long)curtime.tv_usec); - file_mode = O_CREAT | O_WRONLY | O_SYNC; - - DHD_ERROR(("debug_dump_path = %s\n", dump_path)); - fp = filp_open(dump_path, file_mode, 0664); - if (IS_ERR(fp)) { - ret = PTR_ERR(fp); - DHD_ERROR(("open file error, err = %d\n", ret)); - goto exit; - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) - ret = kernel_write(fp, pre_strs, strlen(pre_strs), &pos); -#else - ret = vfs_write(fp, pre_strs, strlen(pre_strs), &pos); -#endif - if (ret < 0) { - DHD_ERROR(("write file error, err = %d\n", ret)); - goto exit; - } - - do { - unsigned int buf_size = (unsigned int)(dld_buf->max - - (unsigned long)dld_buf->buffer); - if (dld_buf->wraparound) { - wr_size = buf_size; - } else { - if (!dld_buf->buffer[0]) { /* print log if buf is empty. */ - DHD_ERROR_EX(("Buffer is empty. No event/log.\n")); - } - wr_size = (unsigned int)(dld_buf->present - dld_buf->front); - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) - ret = kernel_write(fp, dld_buf->buffer, wr_size, &pos); -#else - ret = vfs_write(fp, dld_buf->buffer, wr_size, &pos); -#endif - if (ret < 0) { - DHD_ERROR(("write file error, err = %d\n", ret)); - goto exit; - } - - /* re-init dhd_log_dump_buf structure */ - spin_lock_irqsave(&dld_buf->lock, flags); - dld_buf->wraparound = 0; - dld_buf->present = dld_buf->front; - dld_buf->remain = buf_size; - bzero(dld_buf->buffer, buf_size); - spin_unlock_irqrestore(&dld_buf->lock, flags); - ret = BCME_OK; - - if (++i < DLD_BUFFER_NUM) { - dld_buf = &g_dld_buf[i]; - } else { - break; - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) - ret = kernel_write(fp, post_strs, strlen(post_strs), &pos); -#else - ret = vfs_write(fp, post_strs, strlen(post_strs), &pos); -#endif - if (ret < 0) { - DHD_ERROR(("write file error, err = %d\n", ret)); - goto exit; - } - } while (1); - -exit: -#if defined(STAT_REPORT) - if (!IS_ERR(fp) && ret >= 0) { - wl_stat_report_file_save(dhdp, fp); - } -#endif /* STAT_REPORT */ - - if (!IS_ERR(fp)) { - filp_close(fp, NULL); - } - set_fs(old_fs); - - return ret; -} -#endif /* DHD_LOG_DUMP */ - - -#ifdef BCMASSERT_LOG -#ifdef CUSTOMER_HW4_DEBUG -#define ASSERTINFO PLATFORM_PATH".assert.info" -#elif defined(CUSTOMER_HW2) -#define ASSERTINFO "/data/misc/wifi/.assert.info" -#else -#define ASSERTINFO "/installmedia/.assert.info" -#endif /* CUSTOMER_HW4_DEBUG */ -void dhd_get_assert_info(dhd_pub_t *dhd) -{ - struct file *fp = NULL; - char *filepath = ASSERTINFO; - int mem_val = -1; - - /* - * Read assert info from the file - * 0: Trigger Kernel crash by panic() - * 1: Print out the logs and don't trigger Kernel panic. (default) - * 2: Trigger Kernel crash by BUG() - * File doesn't exist: Keep default value (1). - */ - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { - DHD_ERROR(("%s: File [%s] doesn't exist\n", __FUNCTION__, filepath)); - } else { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) - ssize_t ret = kernel_read(fp, (char *)&mem_val, 4, NULL); -#else - int ret = kernel_read(fp, 0, (char *)&mem_val, 4); -#endif - if (ret < 0) { - DHD_ERROR(("%s: File read error, ret=%d\n", __FUNCTION__, ret)); - } else { - mem_val = bcm_atoi((char *)&mem_val); - DHD_ERROR(("%s: ASSERT ENABLED = %d\n", __FUNCTION__, mem_val)); - } - filp_close(fp, NULL); - } -#ifdef CUSTOMER_HW4_DEBUG - /* By default. set to 1, No Kernel Panic */ - g_assert_type = (mem_val >= 0) ? mem_val : 1; -#else - /* By default. set to 0, Kernel Panic */ - g_assert_type = (mem_val >= 0) ? mem_val : 0; -#endif -} -#endif /* BCMASSERT_LOG */ - -/* - * This call is to get the memdump size so that, - * halutil can alloc that much buffer in user space. - */ -int -dhd_os_socram_dump(struct net_device *dev, uint32 *dump_size) -{ - int ret = BCME_OK; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - dhd_pub_t *dhdp = &dhd->pub; - - if (dhdp->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: bus is down\n", __FUNCTION__)); - return BCME_ERROR; - } - - if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhdp)) { - DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state, so skip\n", - __FUNCTION__, dhdp->busstate, dhdp->dhd_bus_busy_state)); - return BCME_ERROR; - } - - ret = dhd_common_socram_dump(dhdp); - if (ret == BCME_OK) { - *dump_size = dhdp->soc_ram_length; - } - return ret; -} - -/* - * This is to get the actual memdup after getting the memdump size - */ -int -dhd_os_get_socram_dump(struct net_device *dev, char **buf, uint32 *size) -{ - int ret = BCME_OK; - int orig_len = 0; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - dhd_pub_t *dhdp = &dhd->pub; - if (buf == NULL) - return BCME_ERROR; - orig_len = *size; - if (dhdp->soc_ram) { - if (orig_len >= dhdp->soc_ram_length) { - memcpy(*buf, dhdp->soc_ram, dhdp->soc_ram_length); - /* reset the storage of dump */ - memset(dhdp->soc_ram, 0, dhdp->soc_ram_length); - *size = dhdp->soc_ram_length; - } else { - ret = BCME_BUFTOOSHORT; - DHD_ERROR(("The length of the buffer is too short" - " to save the memory dump with %d\n", dhdp->soc_ram_length)); - } - } else { - DHD_ERROR(("socram_dump is not ready to get\n")); - ret = BCME_NOTREADY; - } - return ret; -} - -int -dhd_os_get_version(struct net_device *dev, bool dhd_ver, char **buf, uint32 size) -{ - char *fw_str; - - if (size == 0) - return BCME_BADARG; - - fw_str = strstr(info_string, "Firmware: "); - if (fw_str == NULL) { - return BCME_ERROR; - } - - memset(*buf, 0, size); - if (dhd_ver) { - strncpy(*buf, dhd_version, size - 1); - } else { - strncpy(*buf, fw_str, size - 1); - } - return BCME_OK; -} - -#ifdef DHD_WMF -/* Returns interface specific WMF configuration */ -dhd_wmf_t* dhd_wmf_conf(dhd_pub_t *dhdp, uint32 idx) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - - ASSERT(idx < DHD_MAX_IFS); - - ifp = dhd->iflist[idx]; - return &ifp->wmf; -} -#endif /* DHD_WMF */ - -#if defined(TRAFFIC_MGMT_DWM) -void traffic_mgmt_pkt_set_prio(dhd_pub_t *dhdp, void * pktbuf) -{ - struct ether_header *eh; - struct ethervlan_header *evh; - uint8 *pktdata, *ip_body; - uint8 dwm_filter; - uint8 tos_tc = 0; - uint8 dscp = 0; - pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); - eh = (struct ether_header *) pktdata; - ip_body = NULL; - - if (dhdp->dhd_tm_dwm_tbl.dhd_dwm_enabled) { - if (eh->ether_type == hton16(ETHER_TYPE_8021Q)) { - evh = (struct ethervlan_header *)eh; - if ((evh->ether_type == hton16(ETHER_TYPE_IP)) || - (evh->ether_type == hton16(ETHER_TYPE_IPV6))) { - ip_body = pktdata + sizeof(struct ethervlan_header); - } - } else if ((eh->ether_type == hton16(ETHER_TYPE_IP)) || - (eh->ether_type == hton16(ETHER_TYPE_IPV6))) { - ip_body = pktdata + sizeof(struct ether_header); - } - if (ip_body) { - tos_tc = IP_TOS46(ip_body); - dscp = tos_tc >> IPV4_TOS_DSCP_SHIFT; - } - - if (dscp < DHD_DWM_TBL_SIZE) { - dwm_filter = dhdp->dhd_tm_dwm_tbl.dhd_dwm_tbl[dscp]; - if (DHD_TRF_MGMT_DWM_IS_FILTER_SET(dwm_filter)) { - PKTSETPRIO(pktbuf, DHD_TRF_MGMT_DWM_PRIO(dwm_filter)); - } - } - } -} -#endif - -bool dhd_sta_associated(dhd_pub_t *dhdp, uint32 bssidx, uint8 *mac) -{ - return dhd_find_sta(dhdp, bssidx, mac) ? TRUE : FALSE; -} - -#ifdef DHD_L2_FILTER -arp_table_t* -dhd_get_ifp_arp_table_handle(dhd_pub_t *dhdp, uint32 bssidx) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - - ASSERT(bssidx < DHD_MAX_IFS); - - ifp = dhd->iflist[bssidx]; - return ifp->phnd_arp_table; -} - -int dhd_get_parp_status(dhd_pub_t *dhdp, uint32 idx) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - - ASSERT(idx < DHD_MAX_IFS); - - ifp = dhd->iflist[idx]; - - if (ifp) - return ifp->parp_enable; - else - return FALSE; -} - -/* Set interface specific proxy arp configuration */ -int dhd_set_parp_status(dhd_pub_t *dhdp, uint32 idx, int val) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - ASSERT(idx < DHD_MAX_IFS); - ifp = dhd->iflist[idx]; - - if (!ifp) - return BCME_ERROR; - - /* At present all 3 variables are being - * handled at once - */ - ifp->parp_enable = val; - ifp->parp_discard = val; - ifp->parp_allnode = val; - - /* Flush ARP entries when disabled */ - if (val == FALSE) { - bcm_l2_filter_arp_table_update(dhdp->osh, ifp->phnd_arp_table, TRUE, NULL, - FALSE, dhdp->tickcnt); - } - return BCME_OK; -} - -bool dhd_parp_discard_is_enabled(dhd_pub_t *dhdp, uint32 idx) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - - ASSERT(idx < DHD_MAX_IFS); - - ifp = dhd->iflist[idx]; - - ASSERT(ifp); - return ifp->parp_discard; -} - -bool -dhd_parp_allnode_is_enabled(dhd_pub_t *dhdp, uint32 idx) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - - ASSERT(idx < DHD_MAX_IFS); - - ifp = dhd->iflist[idx]; - - ASSERT(ifp); - - return ifp->parp_allnode; -} - -int dhd_get_dhcp_unicast_status(dhd_pub_t *dhdp, uint32 idx) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - - ASSERT(idx < DHD_MAX_IFS); - - ifp = dhd->iflist[idx]; - - ASSERT(ifp); - - return ifp->dhcp_unicast; -} - -int dhd_set_dhcp_unicast_status(dhd_pub_t *dhdp, uint32 idx, int val) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - ASSERT(idx < DHD_MAX_IFS); - ifp = dhd->iflist[idx]; - - ASSERT(ifp); - - ifp->dhcp_unicast = val; - return BCME_OK; -} - -int dhd_get_block_ping_status(dhd_pub_t *dhdp, uint32 idx) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - - ASSERT(idx < DHD_MAX_IFS); - - ifp = dhd->iflist[idx]; - - ASSERT(ifp); - - return ifp->block_ping; -} - -int dhd_set_block_ping_status(dhd_pub_t *dhdp, uint32 idx, int val) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - ASSERT(idx < DHD_MAX_IFS); - ifp = dhd->iflist[idx]; - - ASSERT(ifp); - - ifp->block_ping = val; - /* Disable rx_pkt_chain feature for interface if block_ping option is - * enabled - */ - dhd_update_rx_pkt_chainable_state(dhdp, idx); - return BCME_OK; -} - -int dhd_get_grat_arp_status(dhd_pub_t *dhdp, uint32 idx) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - - ASSERT(idx < DHD_MAX_IFS); - - ifp = dhd->iflist[idx]; - - ASSERT(ifp); - - return ifp->grat_arp; -} - -int dhd_set_grat_arp_status(dhd_pub_t *dhdp, uint32 idx, int val) -{ - dhd_info_t *dhd = dhdp->info; - dhd_if_t *ifp; - ASSERT(idx < DHD_MAX_IFS); - ifp = dhd->iflist[idx]; - - ASSERT(ifp); - - ifp->grat_arp = val; - - return BCME_OK; -} -#endif /* DHD_L2_FILTER */ - - -#if defined(SET_RPS_CPUS) -int dhd_rps_cpus_enable(struct net_device *net, int enable) -{ - dhd_info_t *dhd = DHD_DEV_INFO(net); - dhd_if_t *ifp; - int ifidx; - char * RPS_CPU_SETBUF; - - ifidx = dhd_net2idx(dhd, net); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s bad ifidx\n", __FUNCTION__)); - return -ENODEV; - } - - if (ifidx == PRIMARY_INF) { - if (dhd->pub.op_mode == DHD_FLAG_IBSS_MODE) { - DHD_INFO(("%s : set for IBSS.\n", __FUNCTION__)); - RPS_CPU_SETBUF = RPS_CPUS_MASK_IBSS; - } else { - DHD_INFO(("%s : set for BSS.\n", __FUNCTION__)); - RPS_CPU_SETBUF = RPS_CPUS_MASK; - } - } else if (ifidx == VIRTUAL_INF) { - DHD_INFO(("%s : set for P2P.\n", __FUNCTION__)); - RPS_CPU_SETBUF = RPS_CPUS_MASK_P2P; - } else { - DHD_ERROR(("%s : Invalid index : %d.\n", __FUNCTION__, ifidx)); - return -EINVAL; - } - - ifp = dhd->iflist[ifidx]; - if (ifp) { - if (enable) { - DHD_INFO(("%s : set rps_cpus as [%s]\n", __FUNCTION__, RPS_CPU_SETBUF)); - custom_rps_map_set(ifp->net->_rx, RPS_CPU_SETBUF, strlen(RPS_CPU_SETBUF)); - } else { - custom_rps_map_clear(ifp->net->_rx); - } - } else { - DHD_ERROR(("%s : ifp is NULL!!\n", __FUNCTION__)); - return -ENODEV; - } - return BCME_OK; -} - -int custom_rps_map_set(struct netdev_rx_queue *queue, char *buf, size_t len) -{ - struct rps_map *old_map, *map; - cpumask_var_t mask; - int err, cpu, i; - static DEFINE_SPINLOCK(rps_map_lock); - - DHD_INFO(("%s : Entered.\n", __FUNCTION__)); - - if (!alloc_cpumask_var(&mask, GFP_KERNEL)) { - DHD_ERROR(("%s : alloc_cpumask_var fail.\n", __FUNCTION__)); - return -ENOMEM; - } - - err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); - if (err) { - free_cpumask_var(mask); - DHD_ERROR(("%s : bitmap_parse fail.\n", __FUNCTION__)); - return err; - } - - map = kzalloc(max_t(unsigned int, - RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES), - GFP_KERNEL); - if (!map) { - free_cpumask_var(mask); - DHD_ERROR(("%s : map malloc fail.\n", __FUNCTION__)); - return -ENOMEM; - } - - i = 0; - for_each_cpu(cpu, mask) { - map->cpus[i++] = cpu; - } - - if (i) { - map->len = i; - } else { - kfree(map); - map = NULL; - free_cpumask_var(mask); - DHD_ERROR(("%s : mapping cpu fail.\n", __FUNCTION__)); - return -1; - } - - spin_lock(&rps_map_lock); - old_map = rcu_dereference_protected(queue->rps_map, - lockdep_is_held(&rps_map_lock)); - rcu_assign_pointer(queue->rps_map, map); - spin_unlock(&rps_map_lock); - - if (map) { - static_key_slow_inc(&rps_needed); - } - if (old_map) { - kfree_rcu(old_map, rcu); - static_key_slow_dec(&rps_needed); - } - free_cpumask_var(mask); - - DHD_INFO(("%s : Done. mapping cpu nummber : %d\n", __FUNCTION__, map->len)); - return map->len; -} - -void custom_rps_map_clear(struct netdev_rx_queue *queue) -{ - struct rps_map *map; - - DHD_INFO(("%s : Entered.\n", __FUNCTION__)); - - map = rcu_dereference_protected(queue->rps_map, 1); - if (map) { - RCU_INIT_POINTER(queue->rps_map, NULL); - kfree_rcu(map, rcu); - DHD_INFO(("%s : rps_cpus map clear.\n", __FUNCTION__)); - } -} -#endif - - - -#ifdef DHD_DEBUG_PAGEALLOC - -void -dhd_page_corrupt_cb(void *handle, void *addr_corrupt, size_t len) -{ - dhd_pub_t *dhdp = (dhd_pub_t *)handle; - - DHD_ERROR(("%s: Got dhd_page_corrupt_cb 0x%p %d\n", - __FUNCTION__, addr_corrupt, (uint32)len)); - - DHD_OS_WAKE_LOCK(dhdp); - prhex("Page Corruption:", addr_corrupt, len); - dhd_dump_to_kernelog(dhdp); -#if defined(BCMPCIE) && defined(DHD_FW_COREDUMP) - /* Load the dongle side dump to host memory and then BUG_ON() */ - dhdp->memdump_enabled = DUMP_MEMONLY; - dhdp->memdump_type = DUMP_TYPE_MEMORY_CORRUPTION; - dhd_bus_mem_dump(dhdp); -#endif /* BCMPCIE && DHD_FW_COREDUMP */ - DHD_OS_WAKE_UNLOCK(dhdp); -} -EXPORT_SYMBOL(dhd_page_corrupt_cb); -#endif /* DHD_DEBUG_PAGEALLOC */ - -#if defined(BCMPCIE) && defined(DHD_PKTID_AUDIT_ENABLED) -void -dhd_pktid_error_handler(dhd_pub_t *dhdp) -{ - DHD_ERROR(("%s: Got Pkt Id Audit failure \n", __FUNCTION__)); - DHD_OS_WAKE_LOCK(dhdp); - dhd_dump_to_kernelog(dhdp); -#ifdef DHD_FW_COREDUMP - /* Load the dongle side dump to host memory */ - if (dhdp->memdump_enabled == DUMP_DISABLED) { - dhdp->memdump_enabled = DUMP_MEMFILE; - } - dhdp->memdump_type = DUMP_TYPE_PKTID_AUDIT_FAILURE; - dhd_bus_mem_dump(dhdp); -#endif /* DHD_FW_COREDUMP */ - dhdp->hang_reason = HANG_REASON_PCIE_PKTID_ERROR; - dhd_os_check_hang(dhdp, 0, -EREMOTEIO); - DHD_OS_WAKE_UNLOCK(dhdp); -} -#endif /* BCMPCIE && DHD_PKTID_AUDIT_ENABLED */ - -struct net_device * -dhd_linux_get_primary_netdev(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = dhdp->info; - - if (dhd->iflist[0] && dhd->iflist[0]->net) - return dhd->iflist[0]->net; - else - return NULL; -} - -#ifdef DHD_DHCP_DUMP -static void -dhd_dhcp_dump(char *ifname, uint8 *pktdata, bool tx) -{ - struct bootp_fmt *b = (struct bootp_fmt *) &pktdata[ETHER_HDR_LEN]; - struct iphdr *h = &b->ip_header; - uint8 *ptr, *opt, *end = (uint8 *) b + ntohs(b->ip_header.tot_len); - int dhcp_type = 0, len, opt_len; - - /* check IP header */ - if (h->ihl != 5 || h->version != 4 || h->protocol != IPPROTO_UDP) { - return; - } - - /* check UDP port for bootp (67, 68) */ - if (b->udp_header.source != htons(67) && b->udp_header.source != htons(68) && - b->udp_header.dest != htons(67) && b->udp_header.dest != htons(68)) { - return; - } - - /* check header length */ - if (ntohs(h->tot_len) < ntohs(b->udp_header.len) + sizeof(struct iphdr)) { - return; - } - - len = ntohs(b->udp_header.len) - sizeof(struct udphdr); - opt_len = len - - (sizeof(*b) - sizeof(struct iphdr) - sizeof(struct udphdr) - sizeof(b->options)); - - /* parse bootp options */ - if (opt_len >= 4 && !memcmp(b->options, bootp_magic_cookie, 4)) { - ptr = &b->options[4]; - while (ptr < end && *ptr != 0xff) { - opt = ptr++; - if (*opt == 0) { - continue; - } - ptr += *ptr + 1; - if (ptr >= end) { - break; - } - /* 53 is dhcp type */ - if (*opt == 53) { - if (opt[1]) { - dhcp_type = opt[2]; - DHD_ERROR(("DHCP[%s] - %s [%s] [%s]\n", - ifname, dhcp_types[dhcp_type], - tx ? "TX" : "RX", dhcp_ops[b->op])); - break; - } - } - } - } -} -#endif /* DHD_DHCP_DUMP */ - -#ifdef DHD_ICMP_DUMP -static void -dhd_icmp_dump(char *ifname, uint8 *pktdata, bool tx) -{ - uint8 *pkt = (uint8 *)&pktdata[ETHER_HDR_LEN]; - struct iphdr *iph = (struct iphdr *)pkt; - struct icmphdr *icmph; - - /* check IP header */ - if (iph->ihl != 5 || iph->version != 4 || iph->protocol != IP_PROT_ICMP) { - return; - } - - icmph = (struct icmphdr *)((uint8 *)pkt + sizeof(struct iphdr)); - if (icmph->type == ICMP_ECHO) { - DHD_ERROR(("PING REQUEST[%s] [%s] : SEQNUM=%d\n", - ifname, tx ? "TX" : "RX", ntoh16(icmph->un.echo.sequence))); - } else if (icmph->type == ICMP_ECHOREPLY) { - DHD_ERROR(("PING REPLY[%s] [%s] : SEQNUM=%d\n", - ifname, tx ? "TX" : "RX", ntoh16(icmph->un.echo.sequence))); - } else { - DHD_ERROR(("ICMP [%s] [%s] : TYPE=%d, CODE=%d\n", - ifname, tx ? "TX" : "RX", icmph->type, icmph->code)); - } -} -#endif /* DHD_ICMP_DUMP */ - -#ifdef SHOW_LOGTRACE -void -dhd_get_read_buf_ptr(dhd_pub_t *dhd_pub, trace_buf_info_t *trace_buf_info) -{ - dhd_dbg_ring_status_t ring_status; - uint32 rlen; - - rlen = dhd_dbg_ring_pull_single(dhd_pub, FW_VERBOSE_RING_ID, trace_buf_info->buf, - TRACE_LOG_BUF_MAX_SIZE, TRUE); - trace_buf_info->size = rlen; - trace_buf_info->availability = NEXT_BUF_NOT_AVAIL; - if (rlen == 0) { - trace_buf_info->availability = BUF_NOT_AVAILABLE; - return; - } - dhd_dbg_get_ring_status(dhd_pub, FW_VERBOSE_RING_ID, &ring_status); - if (ring_status.written_bytes != ring_status.read_bytes) { - trace_buf_info->availability = NEXT_BUF_AVAIL; - } -} -#endif /* SHOW_LOGTRACE */ - -bool -dhd_fw_download_status(dhd_pub_t * dhd_pub) -{ - return dhd_pub->fw_download_done; -} - -int -dhd_create_to_notifier_skt(void) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) - /* Kernel 3.7 onwards this API accepts only 3 arguments. */ - /* Kernel version 3.6 is a special case which accepts 4 arguments */ - nl_to_event_sk = netlink_kernel_create(&init_net, BCM_NL_USER, &g_cfg); -#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) - /* Kernel version 3.5 and below use this old API format */ - nl_to_event_sk = netlink_kernel_create(&init_net, BCM_NL_USER, 0, - dhd_process_daemon_msg, NULL, THIS_MODULE); -#else - nl_to_event_sk = netlink_kernel_create(&init_net, BCM_NL_USER, THIS_MODULE, &g_cfg); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)) */ - if (!nl_to_event_sk) - { - DHD_ERROR(("Error creating socket.\n")); - return -1; - } - DHD_INFO(("nl_to socket created successfully...\n")); - return 0; -} - -void -dhd_destroy_to_notifier_skt(void) -{ - DHD_INFO(("Destroying nl_to socket\n")); - if (nl_to_event_sk) { - netlink_kernel_release(nl_to_event_sk); - } -} - -static void -dhd_recv_msg_from_daemon(struct sk_buff *skb) -{ - struct nlmsghdr *nlh; - bcm_to_info_t *cmd; - - nlh = (struct nlmsghdr *)skb->data; - cmd = (bcm_to_info_t *)nlmsg_data(nlh); - if ((cmd->magic == BCM_TO_MAGIC) && (cmd->reason == REASON_DAEMON_STARTED)) { - sender_pid = ((struct nlmsghdr *)(skb->data))->nlmsg_pid; - DHD_INFO(("DHD Daemon Started\n")); - } -} - -int -dhd_send_msg_to_daemon(struct sk_buff *skb, void *data, int size) -{ - struct nlmsghdr *nlh; - struct sk_buff *skb_out; - - if (!nl_to_event_sk) { - DHD_INFO(("No socket available\n")); - return -1; - } - - BCM_REFERENCE(skb); - if (sender_pid == 0) { - DHD_INFO(("Invalid PID 0\n")); - return -1; - } - - if ((skb_out = nlmsg_new(size, 0)) == NULL) { - DHD_ERROR(("%s: skb alloc failed\n", __FUNCTION__)); - return -1; - } - nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, size, 0); - NETLINK_CB(skb_out).dst_group = 0; /* Unicast */ - memcpy(nlmsg_data(nlh), (char *)data, size); - - if ((nlmsg_unicast(nl_to_event_sk, skb_out, sender_pid)) < 0) { - DHD_INFO(("Error sending message\n")); - } - return 0; -} - - -static void -dhd_process_daemon_msg(struct sk_buff *skb) -{ - bcm_to_info_t to_info; - - to_info.magic = BCM_TO_MAGIC; - to_info.reason = REASON_DAEMON_STARTED; - to_info.trap = NO_TRAP; - - dhd_recv_msg_from_daemon(skb); - dhd_send_msg_to_daemon(skb, &to_info, sizeof(to_info)); -} - -#ifdef REPORT_FATAL_TIMEOUTS -static void -dhd_send_trap_to_fw(dhd_pub_t * pub, int reason, int trap) -{ - bcm_to_info_t to_info; - - to_info.magic = BCM_TO_MAGIC; - to_info.reason = reason; - to_info.trap = trap; - - DHD_ERROR(("Sending Event reason:%d trap:%d\n", reason, trap)); - dhd_send_msg_to_daemon(NULL, (void *)&to_info, sizeof(bcm_to_info_t)); -} - -void -dhd_send_trap_to_fw_for_timeout(dhd_pub_t * pub, timeout_reasons_t reason) -{ - int to_reason; - int trap = NO_TRAP; - switch (reason) { - case DHD_REASON_COMMAND_TO: - to_reason = REASON_COMMAND_TO; - trap = DO_TRAP; - break; - case DHD_REASON_JOIN_TO: - to_reason = REASON_JOIN_TO; - break; - case DHD_REASON_SCAN_TO: - to_reason = REASON_SCAN_TO; - break; - case DHD_REASON_OQS_TO: - to_reason = REASON_OQS_TO; - trap = DO_TRAP; - break; - default: - to_reason = REASON_UNKOWN; - } - dhd_send_trap_to_fw(pub, to_reason, trap); -} -#endif /* REPORT_FATAL_TIMEOUTS */ - -#ifdef DHD_LOG_DUMP -void -dhd_log_dump_init(dhd_pub_t *dhd) -{ - struct dhd_log_dump_buf *dld_buf; - int i = 0; -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) - int prealloc_idx = DHD_PREALLOC_DHD_LOG_DUMP_BUF; -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ - - for (i = 0; i < DLD_BUFFER_NUM; i++) { - dld_buf = &g_dld_buf[i]; - spin_lock_init(&dld_buf->lock); -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) - dld_buf->buffer = DHD_OS_PREALLOC(dhd, prealloc_idx++, dld_buf_size[i]); -#else - dld_buf->buffer = kmalloc(dld_buf_size[i], GFP_KERNEL); -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ - - if (!dld_buf->buffer) { - dld_buf->buffer = kmalloc(dld_buf_size[i], GFP_KERNEL); - DHD_ERROR(("Try to allocate memory using kmalloc().\n")); - - if (!dld_buf->buffer) { - DHD_ERROR(("Failed to allocate memory for dld_buf[%d].\n", i)); - goto fail; - } - } - - dld_buf->wraparound = 0; - dld_buf->max = (unsigned long)dld_buf->buffer + dld_buf_size[i]; - dld_buf->present = dld_buf->front = dld_buf->buffer; - dld_buf->remain = dld_buf_size[i]; - dld_buf->enable = 1; - } - return; - -fail: - for (i = 0; i < DLD_BUFFER_NUM; i++) { - if (dld_buf[i].buffer) { - kfree(dld_buf[i].buffer); - } - } -} - -void -dhd_log_dump_deinit(dhd_pub_t *dhd) -{ - struct dhd_log_dump_buf *dld_buf; - int i = 0; - - for (i = 0; i < DLD_BUFFER_NUM; i++) { - dld_buf = &g_dld_buf[i]; - dld_buf->enable = 0; -#if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP) - DHD_OS_PREFREE(dhd, dld_buf->buffer, dld_buf_size[i]); -#else - kfree(dld_buf->buffer); -#endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */ - } -} - -void -dhd_log_dump_write(int type, const char *fmt, ...) -{ - int len = 0; - char tmp_buf[DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE] = {0, }; - va_list args; - unsigned long flags = 0; - struct dhd_log_dump_buf *dld_buf = NULL; - - switch (type) - { - case DLD_BUF_TYPE_GENERAL: - dld_buf = &g_dld_buf[type]; - break; - case DLD_BUF_TYPE_SPECIAL: - dld_buf = &g_dld_buf[type]; - break; - default: - DHD_ERROR(("%s: Unknown DHD_LOG_DUMP_BUF_TYPE(%d).\n", - __FUNCTION__, type)); - return; - } - - if (dld_buf->enable != 1) { - return; - } - - va_start(args, fmt); - - len = vsnprintf(tmp_buf, DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE, fmt, args); - /* Non ANSI C99 compliant returns -1, - * ANSI compliant return len >= DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE - */ - if (len < 0) { - return; - } - - if (len >= DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE) { - len = DHD_LOG_DUMP_MAX_TEMP_BUFFER_SIZE - 1; - tmp_buf[len] = '\0'; - } - - /* make a critical section to eliminate race conditions */ - spin_lock_irqsave(&dld_buf->lock, flags); - if (dld_buf->remain < len) { - dld_buf->wraparound = 1; - dld_buf->present = dld_buf->front; - dld_buf->remain = dld_buf_size[type]; - } - - strncpy(dld_buf->present, tmp_buf, len); - dld_buf->remain -= len; - dld_buf->present += len; - spin_unlock_irqrestore(&dld_buf->lock, flags); - - /* double check invalid memory operation */ - ASSERT((unsigned long)dld_buf->present <= dld_buf->max); - va_end(args); -} - -char* -dhd_log_dump_get_timestamp(void) -{ - static char buf[16]; - u64 ts_nsec; - unsigned long rem_nsec; - - ts_nsec = local_clock(); - rem_nsec = do_div(ts_nsec, 1000000000); - snprintf(buf, sizeof(buf), "%5lu.%06lu", - (unsigned long)ts_nsec, rem_nsec / 1000); - - return buf; -} -#endif /* DHD_LOG_DUMP */ - -int -dhd_write_file(const char *filepath, char *buf, int buf_len) -{ - struct file *fp = NULL; - mm_segment_t old_fs; - int ret = 0; - - /* change to KERNEL_DS address limit */ - old_fs = get_fs(); - set_fs(KERNEL_DS); - - /* File is always created. */ - fp = filp_open(filepath, O_RDWR | O_CREAT, 0664); - if (IS_ERR(fp)) { - DHD_ERROR(("%s: Couldn't open file '%s' err %ld\n", - __FUNCTION__, filepath, PTR_ERR(fp))); - ret = BCME_ERROR; - } else { - if (fp->f_mode & FMODE_WRITE) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) - ret = kernel_write(fp, buf, buf_len, &fp->f_pos); -#else - ret = vfs_write(fp, buf, buf_len, &fp->f_pos); -#endif - if (ret < 0) { - DHD_ERROR(("%s: Couldn't write file '%s'\n", - __FUNCTION__, filepath)); - ret = BCME_ERROR; - } else { - ret = BCME_OK; - } - } - filp_close(fp, NULL); - } - - /* restore previous address limit */ - set_fs(old_fs); - - return ret; -} - -int -dhd_read_file(const char *filepath, char *buf, int buf_len) -{ - struct file *fp = NULL; - mm_segment_t old_fs; - int ret; - - /* change to KERNEL_DS address limit */ - old_fs = get_fs(); - set_fs(KERNEL_DS); - - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { - set_fs(old_fs); - DHD_ERROR(("%s: File %s doesn't exist\n", __FUNCTION__, filepath)); - return BCME_ERROR; - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) - ret = kernel_read(fp, buf, buf_len, NULL); -#else - ret = kernel_read(fp, 0, buf, buf_len); -#endif - filp_close(fp, NULL); - - /* restore previous address limit */ - set_fs(old_fs); - - /* Return the number of bytes read */ - if (ret > 0) { - /* Success to read */ - ret = 0; - } else { - DHD_ERROR(("%s: Couldn't read the file %s, ret=%d\n", - __FUNCTION__, filepath, ret)); - ret = BCME_ERROR; - } - - return ret; -} - -int -dhd_write_file_and_check(const char *filepath, char *buf, int buf_len) -{ - int ret; - - ret = dhd_write_file(filepath, buf, buf_len); - if (ret < 0) { - return ret; - } - - /* Read the file again and check if the file size is not zero */ - memset(buf, 0, buf_len); - ret = dhd_read_file(filepath, buf, buf_len); - - return ret; -} - -#ifdef DHD_LB_TXP -#define DHD_LB_TXBOUND 64 -/* - * Function that performs the TX processing on a given CPU - */ -bool -dhd_lb_tx_process(dhd_info_t *dhd) -{ - struct sk_buff *skb; - int cnt = 0; - struct net_device *net; - int ifidx; - bool resched = FALSE; - - DHD_TRACE(("%s(): TX Processing \r\n", __FUNCTION__)); - if (dhd == NULL) { - DHD_ERROR((" Null pointer DHD \r\n")); - return resched; - } - - DHD_LB_STATS_PERCPU_ARR_INCR(dhd->txp_percpu_run_cnt); - - /* Base Loop to perform the actual Tx */ - do { - skb = skb_dequeue(&dhd->tx_pend_queue); - if (skb == NULL) { - DHD_TRACE(("Dequeued a Null Packet \r\n")); - break; - } - cnt++; - - net = DHD_LB_TX_PKTTAG_NETDEV((dhd_tx_lb_pkttag_fr_t *)PKTTAG(skb)); - ifidx = DHD_LB_TX_PKTTAG_IFIDX((dhd_tx_lb_pkttag_fr_t *)PKTTAG(skb)); - - BCM_REFERENCE(net); - DHD_TRACE(("Processing skb %p for net %p index %d \r\n", skb, - net, ifidx)); - - __dhd_sendpkt(&dhd->pub, ifidx, skb); - - if (cnt >= DHD_LB_TXBOUND) { - resched = TRUE; - break; - } - - } while (1); - - DHD_INFO(("%s(): Processed %d packets \r\n", __FUNCTION__, cnt)); - - return resched; -} - -void -dhd_lb_tx_handler(unsigned long data) -{ - dhd_info_t *dhd = (dhd_info_t *)data; - - if (dhd_lb_tx_process(dhd)) { - dhd_tasklet_schedule(&dhd->tx_tasklet); - } -} - -#endif /* DHD_LB_TXP */ - -/* ---------------------------------------------------------------------------- - * Infrastructure code for sysfs interface support for DHD - * - * What is sysfs interface? - * https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt - * - * Why sysfs interface? - * This is the Linux standard way of changing/configuring Run Time parameters - * for a driver. We can use this interface to control "linux" specific driver - * parameters. - * - * ----------------------------------------------------------------------------- - */ - -#include <linux/sysfs.h> -#include <linux/kobject.h> - -static ssize_t -show_driver_state(struct dhd_info *dev, char *buf) -{ - ssize_t ret = 0; - - mutex_lock(&dhd_drv_action_lock); - - ret = scnprintf(buf, PAGE_SIZE - 1, "%d\n", - dhd_get_driver_state()); - - mutex_unlock(&dhd_drv_action_lock); - - return ret; -} - -static ssize_t -set_driver_state(struct dhd_info *dhd, const char *buf, size_t count) -{ - unsigned long target_state, current_state; - int ret = 0, val = 0; - dhd_pub_t *dhdp = g_dhd_pub; - if (count == 1 && buf[0] == '\n') { - goto out; - } - current_state = dhd_get_driver_state(); - mutex_lock(&dhd_drv_action_lock); - target_state = bcm_strtoul(buf, NULL, 10); - DHD_ERROR(("%s: changing from %s -> %s\n", __func__, - get_dhd_drv_state_str(current_state), - get_dhd_drv_state_str(target_state))); - - if (gNeedStartBus && (target_state == DHD_DRIVER_STATE_BUS || - target_state == DHD_DRIVER_STATE_COMPLETE)) { - /* need start bus first */ - DHD_ERROR(("%s: start bus\n", __func__)); - -#ifdef CONFIG_AMLOGIC_CHIP_ALIVE - dhd_chip_alive = 1; -#else - dhd_chip_alive = 0; -#endif - sdio_set_chip_alive(dhd_chip_alive); - ret = dhd_module_init_work(); - if (ret == BCME_OK) { - dhdp = g_dhd_pub; - if (dhd_load_mode == DHD_LOAD_MODE_COLD) { - /* read skip_sched_cold iovar */ - val = 0; - ret = dhd_wl_ioctl_get_intiovar(dhdp, "skip_sched_cold", &val, - WLC_GET_VAR, FALSE, 0); - - if (val) { - DHD_ERROR(("%s: targeting down state, skip_sched_cold make it warm!!!", __func__)); - - dhd_change_driver_state(DHD_DRIVER_STATE_WARM); - current_state = DHD_DRIVER_STATE_WARM; - } else { - DHD_ERROR(("%s: targeting down state, read wifi stats and console only!!!", __func__)); - -#ifdef WIFI_STATS - dhd_dump_wifi_stats(dhdp, NULL); -#endif /* WIFI_STATS */ -#ifdef DHD_DEBUG - if (dhdp && dhdp->bus) - dhdsdio_readconsole(dhdp->bus); - else - DHD_ERROR(("%s: dhdp %p, dhdp->bus %p!!!", __func__, dhdp, dhdp ? dhdp->bus : NULL)); -#endif - dhd_module_exit_work(); - DHD_ERROR(("%s: module_exit done!!!", __func__)); - } - } - } else { -#ifdef SDIO_TRAITS_STATS - if (dhd_load_mode != DHD_LOAD_MODE_COLD) - dhd_bus_traits_attach_fail_inc(); -#endif /* SDIO_TRAITS_STATS */ - dhd_chip_alive = 0; - sdio_set_chip_alive(dhd_chip_alive); - dhd_change_driver_state(DHD_DRIVER_STATE_DOWN); - current_state = DHD_DRIVER_STATE_DOWN; - } - gNeedStartBus = FALSE; - } - - switch (target_state) { - case DHD_DRIVER_STATE_ISOLATED: - switch (current_state) { - case DHD_DRIVER_STATE_PENDING_WAKE: -#ifdef SCHED_WAKE - dhd_sched_wake_setup(dhdp, SCHEDWAKE_RSN_PENDING_WAKE); -#endif /* SCHED_WAKE */ - case DHD_DRIVER_STATE_WARM_PARTIAL: - val = 1; - ret = dhd_wl_ioctl_set_intiovar(dhdp, "host_off", val, - WLC_SET_VAR, TRUE, 0); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to set host_off, ret=%d\n", - __FUNCTION__, ret)); - } - dhdsdio_padsiso_enable(dhdp, true); - dhd_change_driver_state(target_state); - break; - } - break; - case DHD_DRIVER_STATE_DOWN: - switch (current_state) { - case DHD_DRIVER_STATE_ISOLATED: - dhdsdio_padsiso_enable(dhdp, false); - case DHD_DRIVER_STATE_WARM_PARTIAL: - case DHD_DRIVER_STATE_WARM: - case DHD_DRIVER_STATE_COMPLETE: - dhd_module_exit_work(); - dhd_change_driver_state(target_state); - break; - } - break; - case DHD_DRIVER_STATE_COMPLETE: - switch (current_state) { - case DHD_DRIVER_STATE_HANGED: - dhd_module_exit_work(); - case DHD_DRIVER_STATE_DOWN: - dhd_chip_alive = 0; - sdio_set_chip_alive(dhd_chip_alive); - ret = dhd_module_init_work(); - if (ret == BCME_OK) { - dhdp = g_dhd_pub; - dhd_change_driver_state(target_state); - } - break; - - case DHD_DRIVER_STATE_PENDING_WAKE: - case DHD_DRIVER_STATE_WARM_PARTIAL: - dhd_conf_read_config(dhdp, dhdp->conf_path); - dhd_conf_read_regulatory(dhdp, dhdp->reg_path); - val = 0; - ret = dhd_wl_ioctl_set_intiovar(dhdp, "host_off", val, - WLC_SET_VAR, TRUE, 0); - if (unlikely(ret)) { - DHD_ERROR(("%s: failed to set host_off, ret=%d\n", - __FUNCTION__, ret)); - } else { - dhd_change_driver_state(target_state); - } - break; - - case DHD_DRIVER_STATE_WARM: - dhd_conf_read_config(dhdp, dhdp->conf_path); - dhd_conf_read_regulatory(dhdp, dhdp->reg_path); - dhd_change_driver_state(target_state); - break; - } - break; - } - mutex_unlock(&dhd_drv_action_lock); -out: - return count; -} - - -#if defined(DHD_TRACE_WAKE_LOCK) - -/* Function to show the history buffer */ -static ssize_t -show_wklock_trace(struct dhd_info *dev, char *buf) -{ - ssize_t ret = 0; - dhd_info_t *dhd = (dhd_info_t *)dev; - - buf[ret] = '\n'; - buf[ret+1] = 0; - - dhd_wk_lock_stats_dump(&dhd->pub); - return ret+1; -} - -/* Function to enable/disable wakelock trace */ -static ssize_t -wklock_trace_onoff(struct dhd_info *dev, const char *buf, size_t count) -{ - unsigned long onoff; - unsigned long flags; - dhd_info_t *dhd = (dhd_info_t *)dev; - - onoff = bcm_strtoul(buf, NULL, 10); - if (onoff != 0 && onoff != 1) { - return -EINVAL; - } - - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - trace_wklock_onoff = onoff; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - if (trace_wklock_onoff) { - printk("ENABLE WAKLOCK TRACE\n"); - } else { - printk("DISABLE WAKELOCK TRACE\n"); - } - - return (ssize_t)(onoff+1); -} -#endif /* DHD_TRACE_WAKE_LOCK */ - -#if defined(DHD_LB_TXP) -static ssize_t -show_lbtxp(struct dhd_info *dev, char *buf) -{ - ssize_t ret = 0; - unsigned long onoff; - dhd_info_t *dhd = (dhd_info_t *)dev; - - onoff = atomic_read(&dhd->lb_txp_active); - ret = scnprintf(buf, PAGE_SIZE - 1, "%lu \n", - onoff); - return ret; -} - -static ssize_t -lbtxp_onoff(struct dhd_info *dev, const char *buf, size_t count) -{ - unsigned long onoff; - dhd_info_t *dhd = (dhd_info_t *)dev; - int i; - - onoff = bcm_strtoul(buf, NULL, 10); - - sscanf(buf, "%lu", &onoff); - if (onoff != 0 && onoff != 1) { - return -EINVAL; - } - atomic_set(&dhd->lb_txp_active, onoff); - - /* Since the scheme is changed clear the counters */ - for (i = 0; i < NR_CPUS; i++) { - DHD_LB_STATS_CLR(dhd->txp_percpu_run_cnt[i]); - DHD_LB_STATS_CLR(dhd->tx_start_percpu_run_cnt[i]); - } - - return count; -} - -#endif /* DHD_LB_TXP */ -/* - * Generic Attribute Structure for DHD. - * If we have to add a new sysfs entry under /sys/bcm-dhd/, we have - * to instantiate an object of type dhd_attr, populate it with - * the required show/store functions (ex:- dhd_attr_cpumask_primary) - * and add the object to default_attrs[] array, that gets registered - * to the kobject of dhd (named bcm-dhd). - */ - -struct dhd_attr { - struct attribute attr; - ssize_t(*show)(struct dhd_info *, char *); - ssize_t(*store)(struct dhd_info *, const char *, size_t count); -}; - -static struct dhd_attr dhd_driver_state = - __ATTR(driver_state, 0660, show_driver_state, set_driver_state); - -#if defined(DHD_TRACE_WAKE_LOCK) -static struct dhd_attr dhd_attr_wklock = - __ATTR(wklock_trace, 0660, show_wklock_trace, wklock_trace_onoff); -#endif /* defined(DHD_TRACE_WAKE_LOCK */ - -#if defined(DHD_LB_TXP) -static struct dhd_attr dhd_attr_lbtxp = - __ATTR(lbtxp, 0660, show_lbtxp, lbtxp_onoff); -#endif /* DHD_LB_TXP */ - -/* Attribute object that gets registered with "bcm-dhd" kobject tree */ -static struct attribute *default_attrs[] = { - &dhd_driver_state.attr, -#if defined(DHD_TRACE_WAKE_LOCK) - &dhd_attr_wklock.attr, -#endif /* DHD_TRACE_WAKE_LOCK */ -#if defined(DHD_LB_TXP) - &dhd_attr_lbtxp.attr, -#endif /* DHD_LB_TXP */ - NULL -}; - -#define to_dhd(k) container_of(k, struct dhd_info, dhd_kobj) -#define to_attr(a) container_of(a, struct dhd_attr, attr) - -/* - * bcm-dhd kobject show function, the "attr" attribute specifices to which - * node under "bcm-dhd" the show function is called. - */ -static ssize_t dhd_show(struct kobject *kobj, struct attribute *attr, char *buf) -{ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - dhd_info_t *dhd = to_dhd(kobj); - struct dhd_attr *d_attr = to_attr(attr); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - int ret; - - if (d_attr->show) - ret = d_attr->show(dhd, buf); - else - ret = -EIO; - - return ret; -} - -/* - * bcm-dhd kobject show function, the "attr" attribute specifices to which - * node under "bcm-dhd" the store function is called. - */ -static ssize_t dhd_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t count) -{ -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - dhd_info_t *dhd = to_dhd(kobj); - struct dhd_attr *d_attr = to_attr(attr); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - int ret; - - if (d_attr->store) - ret = d_attr->store(dhd, buf, count); - else - ret = -EIO; - - return ret; - -} - -static struct sysfs_ops dhd_sysfs_ops = { - .show = dhd_show, - .store = dhd_store, -}; - -static struct kobj_type dhd_ktype = { - .sysfs_ops = &dhd_sysfs_ops, - .default_attrs = default_attrs, -}; - -/* Create a kobject and attach to sysfs interface */ -static int dhd_sysfs_init(struct kobject *kobj) -{ - int ret = -1; - - if (kobj == NULL) { - DHD_ERROR(("%s(): kobj is NULL \r\n", __FUNCTION__)); - return ret; - } - - /* Initialize the kobject */ - ret = kobject_init_and_add(kobj, &dhd_ktype, NULL, "bcm-dhd"); - if (ret) { - kobject_put(kobj); - DHD_ERROR(("%s(): Unable to allocate kobject \r\n", __FUNCTION__)); - return ret; - } - - /* - * We are always responsible for sending the uevent that the kobject - * was added to the system. - */ - kobject_uevent(kobj, KOBJ_ADD); - - return ret; -} - -/* Done with the kobject and detach the sysfs interface */ -static void dhd_sysfs_exit(struct kobject *kobj) -{ - if (kobj == NULL) { - DHD_ERROR(("%s(): dhd is NULL \r\n", __FUNCTION__)); - return; - } - - /* Releae the kobject */ - if (kobj->state_initialized) - kobject_put(kobj); -} - -#ifdef DHD_DEBUG_UART -bool -dhd_debug_uart_is_running(struct net_device *dev) -{ - dhd_info_t *dhd = DHD_DEV_INFO(dev); - - if (dhd->duart_execute) { - return TRUE; - } - - return FALSE; -} - -static void -dhd_debug_uart_exec_rd(void *handle, void *event_info, u8 event) -{ - dhd_pub_t *dhdp = handle; - dhd_debug_uart_exec(dhdp, "rd"); -} - -static void -dhd_debug_uart_exec(dhd_pub_t *dhdp, char *cmd) -{ - int ret; - - char *argv[] = {DHD_DEBUG_UART_EXEC_PATH, cmd, NULL}; - char *envp[] = {"HOME=/", "TERM=linux", "PATH=/sbin:/system/bin", NULL}; - -#ifdef DHD_FW_COREDUMP - if (dhdp->memdump_enabled == DUMP_MEMFILE_BUGON) -#endif - { - if (dhdp->hang_reason == HANG_REASON_PCIE_LINK_DOWN || -#ifdef DHD_FW_COREDUMP - dhdp->memdump_success == FALSE || -#endif - FALSE) { - dhdp->info->duart_execute = TRUE; - DHD_ERROR(("DHD: %s - execute %s %s\n", - __FUNCTION__, DHD_DEBUG_UART_EXEC_PATH, cmd)); - ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC); - DHD_ERROR(("DHD: %s - %s %s ret = %d\n", - __FUNCTION__, DHD_DEBUG_UART_EXEC_PATH, cmd, ret)); - dhdp->info->duart_execute = FALSE; - -#ifdef DHD_LOG_DUMP - if (dhdp->memdump_type != DUMP_TYPE_BY_SYSDUMP) -#endif - { - BUG_ON(1); - } - } - } -} -#endif /* DHD_DEBUG_UART */ - -#if defined(DHD_BLOB_EXISTENCE_CHECK) -void -dhd_set_blob_support(dhd_pub_t *dhdp, char *fw_path) -{ - struct file *fp; - char *filepath = CONFIG_BCMDHD_CLM_PATH; - - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { - DHD_ERROR(("%s: ----- blob file dosen't exist -----\n", __FUNCTION__)); - dhdp->is_blob = FALSE; - } else { - DHD_ERROR(("%s: ----- blob file exist -----\n", __FUNCTION__)); - dhdp->is_blob = TRUE; -#if defined(CONCATE_BLOB) - strncat(fw_path, "_blob", strlen("_blob")); -#else - BCM_REFERENCE(fw_path); -#endif /* SKIP_CONCATE_BLOB */ - filp_close(fp, NULL); - } -} -#endif /* DHD_BLOB_EXISTENCE_CHECK */ - -#if defined(PCIE_FULL_DONGLE) -/** test / loopback */ -void -dmaxfer_free_dmaaddr_handler(void *handle, void *event_info, u8 event) -{ - dmaxref_mem_map_t *dmmap = (dmaxref_mem_map_t *)event_info; - dhd_info_t *dhd_info = (dhd_info_t *)handle; - dhd_pub_t *dhdp = &dhd_info->pub; - - if (event != DHD_WQ_WORK_DMA_LB_MEM_REL) { - DHD_ERROR(("%s: unexpected event \n", __FUNCTION__)); - return; - } - - if ((dhd_info == NULL) || (dhdp == NULL)) { - DHD_ERROR(("%s: invalid dhd_info\n", __FUNCTION__)); - return; - } - - if (dmmap == NULL) { - DHD_ERROR(("%s: dmmap is null\n", __FUNCTION__)); - return; - } - dmaxfer_free_prev_dmaaddr(dhdp, dmmap); -} - - -void -dhd_schedule_dmaxfer_free(dhd_pub_t *dhdp, dmaxref_mem_map_t *dmmap) -{ - dhd_info_t *dhd_info = dhdp->info; - - dhd_deferred_schedule_work(dhd_info->dhd_deferred_wq, (void *)dmmap, - DHD_WQ_WORK_DMA_LB_MEM_REL, dmaxfer_free_dmaaddr_handler, DHD_WQ_WORK_PRIORITY_LOW); -} -#endif /* PCIE_FULL_DONGLE */ -/* ---------------------------- End of sysfs implementation ------------------------------------- */ -#ifdef HOFFLOAD_MODULES -void -dhd_linux_get_modfw_address(dhd_pub_t *dhd) -{ - const char* module_name = NULL; - const struct firmware *module_fw; - struct module_metadata *hmem = &dhd->hmem; - - if (dhd_hmem_module_string[0] != '\0') { - module_name = dhd_hmem_module_string; - } else { - DHD_ERROR(("%s No module image name specified\n", __FUNCTION__)); - return; - } - if (request_firmware(&module_fw, module_name, dhd_bus_to_dev(dhd->bus))) { - DHD_ERROR(("modules.img not available\n")); - return; - } - if (!dhd_alloc_module_memory(dhd->bus, module_fw->size, hmem)) { - release_firmware(module_fw); - return; - } - memcpy(hmem->data, module_fw->data, module_fw->size); - release_firmware(module_fw); -} -#endif /* HOFFLOAD_MODULES */ - -#ifdef SET_PCIE_IRQ_CPU_CORE -void -dhd_set_irq_cpucore(dhd_pub_t *dhdp, int set) -{ - unsigned int irq; - if (!dhdp) { - DHD_ERROR(("%s : dhd is NULL\n", __FUNCTION__)); - return; - } - - if (!dhdp->bus) { - DHD_ERROR(("%s : dhd->bus is NULL\n", __FUNCTION__)); - return; - } - - if (dhdpcie_get_pcieirq(dhdp->bus, &irq)) { - return; - } - - set_irq_cpucore(irq, set); -} -#endif /* SET_PCIE_IRQ_CPU_CORE */ - -#if defined(DHD_HANG_SEND_UP_TEST) -void -dhd_make_hang_with_reason(struct net_device *dev, const char *string_num) -{ - dhd_info_t *dhd = NULL; - dhd_pub_t *dhdp = NULL; - uint reason = HANG_REASON_MAX; - char buf[WLC_IOCTL_SMLEN] = {0, }; - uint32 fw_test_code = 0; - dhd = DHD_DEV_INFO(dev); - - if (dhd) { - dhdp = &dhd->pub; - } - - if (!dhd || !dhdp) { - return; - } - - reason = (uint) bcm_strtoul(string_num, NULL, 0); - DHD_ERROR(("Enter %s, reason=0x%x\n", __FUNCTION__, reason)); - - if (reason == 0) { - if (dhdp->req_hang_type) { - DHD_ERROR(("%s, Clear HANG test request 0x%x\n", - __FUNCTION__, dhdp->req_hang_type)); - dhdp->req_hang_type = 0; - return; - } else { - DHD_ERROR(("%s, No requested HANG test\n", __FUNCTION__)); - return; - } - } else if ((reason <= HANG_REASON_MASK) || (reason >= HANG_REASON_MAX)) { - DHD_ERROR(("Invalid HANG request, reason 0x%x\n", reason)); - return; - } - - if (dhdp->req_hang_type != 0) { - DHD_ERROR(("Already HANG requested for test\n")); - return; - } - - switch (reason) { - case HANG_REASON_IOCTL_RESP_TIMEOUT: - DHD_ERROR(("Make HANG!!!: IOCTL response timeout(0x%x)\n", reason)); - dhdp->req_hang_type = reason; - fw_test_code = 102; /* resumed on timeour */ - bcm_mkiovar("bus:disconnect", (void *)&fw_test_code, 4, buf, sizeof(buf)); - dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); - break; - case HANG_REASON_DONGLE_TRAP: - DHD_ERROR(("Make HANG!!!: Dongle trap (0x%x)\n", reason)); - dhdp->req_hang_type = reason; - fw_test_code = 99; /* dongle trap */ - bcm_mkiovar("bus:disconnect", (void *)&fw_test_code, 4, buf, sizeof(buf)); - dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); - break; - case HANG_REASON_D3_ACK_TIMEOUT: - DHD_ERROR(("Make HANG!!!: D3 ACK timeout (0x%x)\n", reason)); - dhdp->req_hang_type = reason; - break; - case HANG_REASON_BUS_DOWN: - DHD_ERROR(("Make HANG!!!: BUS down(0x%x)\n", reason)); - dhdp->req_hang_type = reason; - break; - case HANG_REASON_PCIE_LINK_DOWN: - case HANG_REASON_MSGBUF_LIVELOCK: - dhdp->req_hang_type = 0; - DHD_ERROR(("Does not support requested HANG(0x%x)\n", reason)); - break; - case HANG_REASON_IFACE_OP_FAILURE: - DHD_ERROR(("Make HANG!!!: P2P inrerface delete failure(0x%x)\n", reason)); - dhdp->req_hang_type = reason; - break; - case HANG_REASON_HT_AVAIL_ERROR: - dhdp->req_hang_type = 0; - DHD_ERROR(("PCIe does not support requested HANG(0x%x)\n", reason)); - break; - case HANG_REASON_PCIE_RC_LINK_UP_FAIL: - DHD_ERROR(("Make HANG!!!:Link Up(0x%x)\n", reason)); - dhdp->req_hang_type = reason; - break; - default: - dhdp->req_hang_type = 0; - DHD_ERROR(("Unknown HANG request (0x%x)\n", reason)); - break; - } -} -#endif /* DHD_HANG_SEND_UP_TEST */ -#ifdef DHD_WAKE_STATUS -wake_counts_t* -dhd_get_wakecount(dhd_pub_t *dhdp) -{ -#ifdef BCMDBUS - return NULL; -#else - return dhd_bus_get_wakecount(dhdp); -#endif /* BCMDBUS */ -} -#endif /* DHD_WAKE_STATUS */ - -#ifdef BCM_ASLR_HEAP -uint32 -dhd_get_random_number(void) -{ - uint32 rand = 0; - get_random_bytes_arch(&rand, sizeof(rand)); - return rand; -} -#endif /* BCM_ASLR_HEAP */ - -#ifdef DHD_PKT_LOGGING -void -dhd_pktlog_dump(void *handle, void *event_info, u8 event) -{ - dhd_info_t *dhd = handle; - - if (!dhd) { - DHD_ERROR(("%s: dhd is NULL\n", __FUNCTION__)); - return; - } - - if (dhd_pktlog_write_file(&dhd->pub)) { - DHD_ERROR(("%s: writing pktlog dump to the file failed\n", __FUNCTION__)); - return; - } -} - -void -dhd_schedule_pktlog_dump(dhd_pub_t *dhdp) -{ - dhd_deferred_schedule_work(dhdp->info->dhd_deferred_wq, - (void*)NULL, DHD_WQ_WORK_PKTLOG_DUMP, - dhd_pktlog_dump, DHD_WQ_WORK_PRIORITY_HIGH); -} -#endif /* DHD_PKT_LOGGING */ - -void *dhd_get_pub(struct net_device *dev) -{ - dhd_info_t *dhdinfo = *(dhd_info_t **)netdev_priv(dev); - if (dhdinfo) - return (void *)&dhdinfo->pub; - else { - DHD_ERROR(("%s: null dhdinfo\n", __FUNCTION__)); - return NULL; - } -} - -void *dhd_get_conf(struct net_device *dev) -{ - dhd_info_t *dhdinfo = *(dhd_info_t **)netdev_priv(dev); - if (dhdinfo) - return (void *)dhdinfo->pub.conf; - else { - DHD_ERROR(("%s: null dhdinfo\n", __FUNCTION__)); - return NULL; - } -} - -bool dhd_os_wd_timer_enabled(void *bus) -{ - dhd_pub_t *pub = bus; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - if (!dhd) { - DHD_ERROR(("%s: dhd NULL\n", __FUNCTION__)); - return FALSE; - } - return dhd->wd_timer_valid; -}
diff --git a/bcmdhd.1.579.77.41.x/dhd_linux.h b/bcmdhd.1.579.77.41.x/dhd_linux.h deleted file mode 100644 index bef2cb6..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_linux.h +++ /dev/null
@@ -1,188 +0,0 @@ -/* - * DHD Linux header file (dhd_linux exports for cfg80211 and other components) - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_linux.h 699532 2017-05-15 11:00:39Z $ - */ - -/* 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> -#ifdef DHD_WMF -#include <dhd_wmf_linux.h> -#endif -/* 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) */ - -/* 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; - const char *reg_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 -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); - int (*get_mac_addr)(unsigned char *buf); -#if defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) - void *(*get_country_code)(char *ccode, u32 flags); -#else - void *(*get_country_code)(char *ccode); -#endif /* defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) */ -}; - -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 */ -#ifdef DHD_WMF - struct dhd_sta *psta_prim; /* primary index of psta interface */ -#endif /* DHD_WMF */ -} dhd_sta_t; -typedef dhd_sta_t dhd_sta_pool_t; - -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); -#if defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) -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 /* defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) */ -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); - -#ifdef DHD_WMF -dhd_wmf_t* dhd_wmf_conf(dhd_pub_t *dhdp, uint32 idx); -int dhd_get_wmf_psta_disable(dhd_pub_t *dhdp, uint32 idx); -int dhd_set_wmf_psta_disable(dhd_pub_t *dhdp, uint32 idx, int val); -void dhd_update_psta_interface_for_sta(dhd_pub_t *dhdp, char* ifname, - void* mac_addr, void* event_data); -#endif /* DHD_WMF */ -#if defined(BT_OVER_SDIO) -int dhd_net_bus_get(struct net_device *dev); -int dhd_net_bus_put(struct net_device *dev); -#endif /* BT_OVER_SDIO */ -#ifdef HOFFLOAD_MODULES -extern void dhd_free_module_memory(struct dhd_bus *bus, struct module_metadata *hmem); -extern void* dhd_alloc_module_memory(struct dhd_bus *bus, uint32_t size, - struct module_metadata *hmem); -#endif /* HOFFLOAD_MODULES */ -#if defined(WLADPS) || defined(WLADPS_PRIVATE_CMD) -#define ADPS_ENABLE 1 -#define ADPS_DISABLE 0 -typedef struct bcm_iov_buf { - uint16 version; - uint16 len; - uint16 id; - uint16 data[1]; -} bcm_iov_buf_t; - -int dhd_enable_adps(dhd_pub_t *dhd, uint8 on); -#endif /* WLADPS || WLADPS_PRIVATE_CMD */ -#endif /* __DHD_LINUX_H__ */
diff --git a/bcmdhd.1.579.77.41.x/dhd_linux_platdev.c b/bcmdhd.1.579.77.41.x/dhd_linux_platdev.c deleted file mode 100644 index 38c03d1..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_linux_platdev.c +++ /dev/null
@@ -1,1000 +0,0 @@ -/* - * Linux platform device for DHD WLAN adapter - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_linux_platdev.c 662397 2016-09-29 10:15:08Z $ - */ -#include <typedefs.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <bcmutils.h> -#include <linux_osl.h> -#include <dhd_dbg.h> -#include <dngl_stats.h> -#include <dhd.h> -#include <dhd_bus.h> -#include <dhd_linux.h> -#include <wl_android.h> -#if defined(CONFIG_WIFI_CONTROL_FUNC) -#include <linux/wlan_plat.h> -#endif -#ifdef CONFIG_DTS -#include<linux/regulator/consumer.h> -#include<linux/of_gpio.h> -#endif /* CONFIG_DTS */ - -#if defined(CUSTOMER_HW) -extern int dhd_wlan_init_plat_data(void); -extern void dhd_wlan_deinit_plat_data(wifi_adapter_info_t *adapter); -#endif /* CUSTOMER_HW */ - -#define WIFI_PLAT_NAME "bcmdhd_wlan" -#define WIFI_PLAT_NAME2 "bcm4329_wlan" -#define WIFI_PLAT_EXT "bcmdhd_wifi_platform" - -#ifdef CONFIG_DTS -struct regulator *wifi_regulator = NULL; -extern struct wifi_platform_data dhd_wlan_control; -#endif /* CONFIG_DTS */ - -bool cfg_multichip = FALSE; -bcmdhd_wifi_platdata_t *dhd_wifi_platdata = NULL; -static int wifi_plat_dev_probe_ret = 0; -static bool is_power_on = FALSE; -#if !defined(CONFIG_DTS) -#if defined(DHD_OF_SUPPORT) -static bool dts_enabled = TRUE; -extern struct resource dhd_wlan_resources; -extern struct wifi_platform_data dhd_wlan_control; -#else -static bool dts_enabled = FALSE; -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#endif -struct resource dhd_wlan_resources = {0}; -struct wifi_platform_data dhd_wlan_control = {0}; -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif -#endif /* CONFIG_OF && !defined(CONFIG_ARCH_MSM) */ -#endif /* !defind(CONFIG_DTS) */ - -static int dhd_wifi_platform_load(void); - -extern void* wl_cfg80211_get_dhdp(struct net_device *dev); - -#ifdef ENABLE_4335BT_WAR -extern int bcm_bt_lock(int cookie); -extern void bcm_bt_unlock(int cookie); -static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */ -#endif /* ENABLE_4335BT_WAR */ - -wifi_adapter_info_t* dhd_wifi_platform_attach_adapter(uint32 bus_type, - uint32 bus_num, uint32 slot_num, unsigned long status) -{ - int i; - - if (dhd_wifi_platdata == NULL) - return NULL; - - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - wifi_adapter_info_t *adapter = &dhd_wifi_platdata->adapters[i]; - if ((adapter->bus_type == -1 || adapter->bus_type == bus_type) && - (adapter->bus_num == -1 || adapter->bus_num == bus_num) && - (adapter->slot_num == -1 || adapter->slot_num == slot_num) -#if defined(ENABLE_INSMOD_NO_FW_LOAD) - && (wifi_chk_adapter_status(adapter, status)) -#endif - ) { - DHD_ERROR(("attach adapter info '%s'\n", adapter->name)); - return adapter; - } - } - return NULL; -} - -wifi_adapter_info_t* dhd_wifi_platform_get_adapter(uint32 bus_type, uint32 bus_num, uint32 slot_num) -{ - int i; - - if (dhd_wifi_platdata == NULL) - return NULL; - - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - wifi_adapter_info_t *adapter = &dhd_wifi_platdata->adapters[i]; - if ((adapter->bus_type == -1 || adapter->bus_type == bus_type) && - (adapter->bus_num == -1 || adapter->bus_num == bus_num) && - (adapter->slot_num == -1 || adapter->slot_num == slot_num)) { - DHD_TRACE(("found adapter info '%s'\n", adapter->name)); - return adapter; - } - } - return NULL; -} - -void* wifi_platform_prealloc(wifi_adapter_info_t *adapter, int section, unsigned long size) -{ - void *alloc_ptr = NULL; - struct wifi_platform_data *plat_data; - - if (!adapter || !adapter->wifi_plat_data) - return NULL; - plat_data = adapter->wifi_plat_data; - if (plat_data->mem_prealloc) { - alloc_ptr = plat_data->mem_prealloc(section, size); - if (alloc_ptr) { - DHD_INFO(("success alloc section %d\n", section)); - if (size != 0L) - bzero(alloc_ptr, size); - return alloc_ptr; - } - } else - return NULL; - - DHD_ERROR(("%s: failed to alloc static mem section %d\n", __FUNCTION__, section)); - return NULL; -} - -void* wifi_platform_get_prealloc_func_ptr(wifi_adapter_info_t *adapter) -{ - struct wifi_platform_data *plat_data; - - if (!adapter || !adapter->wifi_plat_data) - return NULL; - plat_data = adapter->wifi_plat_data; - return plat_data->mem_prealloc; -} - -int wifi_platform_get_irq_number(wifi_adapter_info_t *adapter, unsigned long *irq_flags_ptr) -{ - if (adapter == NULL) - return -1; - if (irq_flags_ptr) - *irq_flags_ptr = adapter->intr_flags; - return adapter->irq_num; -} - -int wifi_platform_set_power(wifi_adapter_info_t *adapter, bool on, unsigned long msec) -{ - int err = 0; -#ifndef CONFIG_DTS - struct wifi_platform_data *plat_data; -#endif -#ifdef EXT_POWER_SET - return 0; -#endif -#ifdef BT_OVER_SDIO - if (is_power_on == on) { - return -EINVAL; - } -#endif /* BT_OVER_SDIO */ - if (on) { - wifi_set_adapter_status(adapter, WIFI_STATUS_POWER_ON); - } else { - wifi_clr_adapter_status(adapter, WIFI_STATUS_POWER_ON); - } -#ifdef CONFIG_DTS - if (on) { - DHD_INFO(("======== PULL WL_REG_ON HIGH! ========\n")); - err = regulator_enable(wifi_regulator); - is_power_on = TRUE; - } - else { - DHD_INFO(("======== PULL WL_REG_ON LOW! ========\n")); - err = regulator_disable(wifi_regulator); - is_power_on = FALSE; - } - if (err < 0) { - DHD_ERROR(("%s: regulator enable/disable failed", __FUNCTION__)); - goto fail; - } -#else - if (!adapter || !adapter->wifi_plat_data) { - err = -EINVAL; - goto fail; - } - plat_data = adapter->wifi_plat_data; - - DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); - if (plat_data->set_power) { -#ifdef ENABLE_4335BT_WAR - if (on) { - printk("WiFi: trying to acquire BT lock\n"); - if (bcm_bt_lock(lock_cookie_wifi) != 0) - printk("** WiFi: timeout in acquiring bt lock**\n"); - printk("%s: btlock acquired\n", __FUNCTION__); - } - else { - /* For a exceptional case, release btlock */ - bcm_bt_unlock(lock_cookie_wifi); - } -#endif /* ENABLE_4335BT_WAR */ - -#ifdef BUS_POWER_RESTORE - err = plat_data->set_power(on, adapter); -#else - err = plat_data->set_power(on); -#endif - } - - if (msec && !err) - OSL_SLEEP(msec); - - if (on && !err) - is_power_on = TRUE; - else - is_power_on = FALSE; - -#endif /* CONFIG_DTS */ - - return err; -fail: - if (on) { - wifi_clr_adapter_status(adapter, WIFI_STATUS_POWER_ON); - } else { - wifi_set_adapter_status(adapter, WIFI_STATUS_POWER_ON); - } - return err; -} - -int wifi_platform_bus_enumerate(wifi_adapter_info_t *adapter, bool device_present) -{ - int err = 0; - struct wifi_platform_data *plat_data; - - if (!adapter || !adapter->wifi_plat_data) - return -EINVAL; - plat_data = adapter->wifi_plat_data; - - DHD_TRACE(("%s device present %d\n", __FUNCTION__, device_present)); - if (plat_data->set_carddetect) { - err = plat_data->set_carddetect(device_present); - if (err != 0) - DHD_ERROR(("%s err %d\n", __FUNCTION__,err)); - } - return err; - -} - -int wifi_platform_get_mac_addr(wifi_adapter_info_t *adapter, unsigned char *buf) -{ - struct wifi_platform_data *plat_data; - - DHD_ERROR(("%s\n", __FUNCTION__)); - if (!buf || !adapter || !adapter->wifi_plat_data) - return -EINVAL; - plat_data = adapter->wifi_plat_data; - if (plat_data->get_mac_addr) { - return plat_data->get_mac_addr(buf); - } - return -EOPNOTSUPP; -} - -void * -#if defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) -wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode, u32 flags) -#else -wifi_platform_get_country_code(wifi_adapter_info_t *adapter, char *ccode) -#endif /* defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) */ -{ - /* get_country_code was added after 2.6.39 */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) - struct wifi_platform_data *plat_data; - - if (!ccode || !adapter || !adapter->wifi_plat_data) - return NULL; - plat_data = adapter->wifi_plat_data; - - DHD_TRACE(("%s\n", __FUNCTION__)); - if (plat_data->get_country_code) { -#if defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) - return plat_data->get_country_code(ccode, flags); -#else - return plat_data->get_country_code(ccode); -#endif /* defined(CUSTOM_COUNTRY_CODE) || defined(CUSTOM_FORCE_NODFS_FLAG) */ - } -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ - - return NULL; -} - -#ifndef CUSTOMER_HW -static int wifi_plat_dev_drv_probe(struct platform_device *pdev) -{ - struct resource *resource; - wifi_adapter_info_t *adapter; -#if defined(CONFIG_DTS) && defined(CUSTOMER_OOB) - int irq, gpio; -#endif /* CONFIG_DTS */ - - /* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan") - * is kept for backward compatibility and supports only 1 adapter - */ - ASSERT(dhd_wifi_platdata != NULL); - ASSERT(dhd_wifi_platdata->num_adapters == 1); - adapter = &dhd_wifi_platdata->adapters[0]; - adapter->wifi_plat_data = (void *)&dhd_wlan_control; -// adapter->wifi_plat_data = (struct wifi_platform_data *)(pdev->dev.platform_data); - - resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq"); - if (resource == NULL) - resource = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq"); - if (resource) { - adapter->irq_num = resource->start; - adapter->intr_flags = resource->flags & IRQF_TRIGGER_MASK; -#ifdef DHD_ISR_NO_SUSPEND - adapter->intr_flags |= IRQF_NO_SUSPEND; -#endif - } - -#ifdef CONFIG_DTS - wifi_regulator = regulator_get(&pdev->dev, "wlreg_on"); - if (wifi_regulator == NULL) { - DHD_ERROR(("%s regulator is null\n", __FUNCTION__)); - return -1; - } - -#if defined(CUSTOMER_OOB) - /* This is to get the irq for the OOB */ - gpio = of_get_gpio(pdev->dev.of_node, 0); - - if (gpio < 0) { - DHD_ERROR(("%s gpio information is incorrect\n", __FUNCTION__)); - return -1; - } - irq = gpio_to_irq(gpio); - if (irq < 0) { - DHD_ERROR(("%s irq information is incorrect\n", __FUNCTION__)); - return -1; - } - adapter->irq_num = irq; - - /* need to change the flags according to our requirement */ - adapter->intr_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | - IORESOURCE_IRQ_SHAREABLE; -#endif -#endif /* CONFIG_DTS */ - - wifi_plat_dev_probe_ret = dhd_wifi_platform_load(); - return wifi_plat_dev_probe_ret; -} - -static int wifi_plat_dev_drv_remove(struct platform_device *pdev) -{ - wifi_adapter_info_t *adapter; - - /* Android style wifi platform data device ("bcmdhd_wlan" or "bcm4329_wlan") - * is kept for backward compatibility and supports only 1 adapter - */ - ASSERT(dhd_wifi_platdata != NULL); - ASSERT(dhd_wifi_platdata->num_adapters == 1); - adapter = &dhd_wifi_platdata->adapters[0]; - if (is_power_on) { -#ifdef BCMPCIE - wifi_platform_bus_enumerate(adapter, FALSE); - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); -#else - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - wifi_platform_bus_enumerate(adapter, FALSE); -#endif /* BCMPCIE */ - } - -#ifdef CONFIG_DTS - regulator_put(wifi_regulator); -#endif /* CONFIG_DTS */ - return 0; -} - -static int wifi_plat_dev_drv_suspend(struct platform_device *pdev, pm_message_t state) -{ - DHD_TRACE(("##> %s\n", __FUNCTION__)); -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && \ - defined(BCMSDIO) - bcmsdh_oob_intr_set(0); -#endif /* (OOB_INTR_ONLY) */ - return 0; -} - -static int wifi_plat_dev_drv_resume(struct platform_device *pdev) -{ - DHD_TRACE(("##> %s\n", __FUNCTION__)); -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && \ - defined(BCMSDIO) - if (dhd_os_check_if_up(wl_cfg80211_get_dhdp())) - bcmsdh_oob_intr_set(1); -#endif /* (OOB_INTR_ONLY) */ - return 0; -} - -#ifdef CONFIG_DTS -static const struct of_device_id wifi_device_dt_match[] = { - { .compatible = "android,bcmdhd_wlan", }, - {}, -}; -#endif /* CONFIG_DTS */ - -static struct platform_driver wifi_platform_dev_driver = { - .probe = wifi_plat_dev_drv_probe, - .remove = wifi_plat_dev_drv_remove, - .suspend = wifi_plat_dev_drv_suspend, - .resume = wifi_plat_dev_drv_resume, - .driver = { - .name = WIFI_PLAT_NAME, -#ifdef CONFIG_DTS - .of_match_table = wifi_device_dt_match, -#endif /* CONFIG_DTS */ - } -}; - -static struct platform_driver wifi_platform_dev_driver_legacy = { - .probe = wifi_plat_dev_drv_probe, - .remove = wifi_plat_dev_drv_remove, - .suspend = wifi_plat_dev_drv_suspend, - .resume = wifi_plat_dev_drv_resume, - .driver = { - .name = WIFI_PLAT_NAME2, - } -}; - -static int wifi_platdev_match(struct device *dev, void *data) -{ - char *name = (char*)data; -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - const struct platform_device *pdev = to_platform_device(dev); -#if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - - if (strcmp(pdev->name, name) == 0) { - DHD_ERROR(("found wifi platform device %s\n", name)); - return TRUE; - } - - return FALSE; -} -#endif - -static int wifi_ctrlfunc_register_drv(void) -{ - wifi_adapter_info_t *adapter; - -#ifndef CUSTOMER_HW - int err = 0; - struct device *dev1, *dev2; - dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match); - dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match); -#endif - -#if !defined(CONFIG_DTS) && !defined(CUSTOMER_HW) - if (!dts_enabled) { - if (dev1 == NULL && dev2 == NULL) { - DHD_ERROR(("no wifi platform data, skip\n")); - return -ENXIO; - } - } -#endif /* !defined(CONFIG_DTS) */ - - /* multi-chip support not enabled, build one adapter information for - * DHD (either SDIO, USB or PCIe) - */ - adapter = kzalloc(sizeof(wifi_adapter_info_t), GFP_KERNEL); - if (adapter == NULL) { - DHD_ERROR(("%s:adapter alloc failed", __FUNCTION__)); - return -ENOMEM; - } - adapter->name = "DHD generic adapter"; - adapter->bus_type = -1; - adapter->bus_num = -1; - adapter->slot_num = -1; - adapter->irq_num = -1; - is_power_on = FALSE; - wifi_plat_dev_probe_ret = 0; - dhd_wifi_platdata = kzalloc(sizeof(bcmdhd_wifi_platdata_t), GFP_KERNEL); - dhd_wifi_platdata->num_adapters = 1; - dhd_wifi_platdata->adapters = adapter; - init_waitqueue_head(&adapter->status_event); - -#ifndef CUSTOMER_HW - if (dev1) { - err = platform_driver_register(&wifi_platform_dev_driver); - if (err) { - DHD_ERROR(("%s: failed to register wifi ctrl func driver\n", - __FUNCTION__)); - return err; - } - } - if (dev2) { - err = platform_driver_register(&wifi_platform_dev_driver_legacy); - if (err) { - DHD_ERROR(("%s: failed to register wifi ctrl func legacy driver\n", - __FUNCTION__)); - return err; - } - } -#endif - -#if !defined(CONFIG_DTS) - if (dts_enabled) { - struct resource *resource; - adapter->wifi_plat_data = (void *)&dhd_wlan_control; - resource = &dhd_wlan_resources; -#ifdef CUSTOMER_HW - wifi_plat_dev_probe_ret = dhd_wlan_init_plat_data(); - if (wifi_plat_dev_probe_ret) - return wifi_plat_dev_probe_ret; -#endif - adapter->irq_num = resource->start; - adapter->intr_flags = resource->flags & IRQF_TRIGGER_MASK; -#ifdef DHD_ISR_NO_SUSPEND - adapter->intr_flags |= IRQF_NO_SUSPEND; -#endif - wifi_plat_dev_probe_ret = dhd_wifi_platform_load(); - } -#endif /* !defined(CONFIG_DTS) */ - - -#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW) - wifi_plat_dev_probe_ret = platform_driver_register(&wifi_platform_dev_driver); -#endif /* CONFIG_DTS */ - - /* return probe function's return value if registeration succeeded */ - return wifi_plat_dev_probe_ret; -} - -void wifi_ctrlfunc_unregister_drv(void) -{ -#ifndef CONFIG_DTS - wifi_adapter_info_t *adapter = NULL; -#endif - -#if defined(CONFIG_DTS) && !defined(CUSTOMER_HW) - DHD_ERROR(("unregister wifi platform drivers\n")); - platform_driver_unregister(&wifi_platform_dev_driver); -#else -#ifndef CUSTOMER_HW - struct device *dev1, *dev2; - dev1 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME, wifi_platdev_match); - dev2 = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_NAME2, wifi_platdev_match); - if (!dts_enabled) - if (dev1 == NULL && dev2 == NULL) - return; -#endif - DHD_ERROR(("unregister wifi platform drivers\n")); -#ifndef CUSTOMER_HW - if (dev1) - platform_driver_unregister(&wifi_platform_dev_driver); - if (dev2) - platform_driver_unregister(&wifi_platform_dev_driver_legacy); -#endif - if (dts_enabled) { - adapter = &dhd_wifi_platdata->adapters[0]; - if (is_power_on) { - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - } - wifi_platform_bus_enumerate(adapter, FALSE); - } -#endif /* !defined(CONFIG_DTS) */ - -#if defined(CUSTOMER_HW) - dhd_wlan_deinit_plat_data(adapter); -#endif - - kfree(dhd_wifi_platdata->adapters); - dhd_wifi_platdata->adapters = NULL; - dhd_wifi_platdata->num_adapters = 0; - kfree(dhd_wifi_platdata); - dhd_wifi_platdata = NULL; -} - -#ifndef CUSTOMER_HW -static int bcmdhd_wifi_plat_dev_drv_probe(struct platform_device *pdev) -{ - dhd_wifi_platdata = (bcmdhd_wifi_platdata_t *)(pdev->dev.platform_data); - - return dhd_wifi_platform_load(); -} - -static int bcmdhd_wifi_plat_dev_drv_remove(struct platform_device *pdev) -{ - int i; - wifi_adapter_info_t *adapter; - ASSERT(dhd_wifi_platdata != NULL); - - /* power down all adapters */ - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - adapter = &dhd_wifi_platdata->adapters[i]; - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - wifi_platform_bus_enumerate(adapter, FALSE); - } - return 0; -} - -static struct platform_driver dhd_wifi_platform_dev_driver = { - .probe = bcmdhd_wifi_plat_dev_drv_probe, - .remove = bcmdhd_wifi_plat_dev_drv_remove, - .driver = { - .name = WIFI_PLAT_EXT, - } -}; -#endif - -int dhd_wifi_platform_register_drv(void) -{ - int err = 0; -#ifndef CUSTOMER_HW - struct device *dev; - - /* register Broadcom wifi platform data driver if multi-chip is enabled, - * otherwise use Android style wifi platform data (aka wifi control function) - * if it exists - * - * to support multi-chip DHD, Broadcom wifi platform data device must - * be added in kernel early boot (e.g. board config file). - */ - if (cfg_multichip) { - dev = bus_find_device(&platform_bus_type, NULL, WIFI_PLAT_EXT, wifi_platdev_match); - if (dev == NULL) { - DHD_ERROR(("bcmdhd wifi platform data device not found!!\n")); - return -ENXIO; - } - err = platform_driver_register(&dhd_wifi_platform_dev_driver); - } else -#endif - { - err = wifi_ctrlfunc_register_drv(); - - /* no wifi ctrl func either, load bus directly and ignore this error */ - if (err) { - if (err == -ENXIO) { - /* wifi ctrl function does not exist */ - err = dhd_wifi_platform_load(); - } else { - /* unregister driver due to initialization failure */ - wifi_ctrlfunc_unregister_drv(); - } - } - } - - return err; -} - -#ifdef BCMPCIE -static int dhd_wifi_platform_load_pcie(void) -{ - int err = 0; - int i; - wifi_adapter_info_t *adapter; - - BCM_REFERENCE(i); - BCM_REFERENCE(adapter); - - if (dhd_wifi_platdata == NULL) { - err = dhd_bus_register(); - } else { - if (dhd_download_fw_on_driverload) { - /* power up all adapters */ - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - int retry = POWERUP_MAX_RETRY; - adapter = &dhd_wifi_platdata->adapters[i]; - - DHD_INFO(("Power-up adapter '%s'\n", adapter->name)); - DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n", - adapter->irq_num, adapter->intr_flags, adapter->fw_path, - adapter->nv_path)); - DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n", - adapter->bus_type, adapter->bus_num, adapter->slot_num)); - - do { - err = wifi_platform_set_power(adapter, - TRUE, WIFI_TURNON_DELAY); - if (err) { - DHD_ERROR(("failed to power up %s," - " %d retry left\n", - adapter->name, retry)); - /* WL_REG_ON state unknown, Power off forcely */ - wifi_platform_set_power(adapter, - FALSE, WIFI_TURNOFF_DELAY); - continue; - } else { - err = wifi_platform_bus_enumerate(adapter, TRUE); - if (err) { - DHD_ERROR(("failed to enumerate bus %s, " - "%d retry left\n", - adapter->name, retry)); - wifi_platform_set_power(adapter, FALSE, - WIFI_TURNOFF_DELAY); - } else { - break; - } - } - } while (retry--); - - if (retry < 0) { - DHD_ERROR(("failed to power up %s, max retry reached**\n", - adapter->name)); - return -ENODEV; - } - } - } - - err = dhd_bus_register(); - - if (err) { - DHD_ERROR(("%s: pcie_register_driver failed\n", __FUNCTION__)); - if (dhd_download_fw_on_driverload) { - /* power down all adapters */ - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - adapter = &dhd_wifi_platdata->adapters[i]; - wifi_platform_bus_enumerate(adapter, FALSE); - wifi_platform_set_power(adapter, - FALSE, WIFI_TURNOFF_DELAY); - } - } - } - } - - return err; -} -#else -static int dhd_wifi_platform_load_pcie(void) -{ - return 0; -} -#endif /* BCMPCIE */ - - -void dhd_wifi_platform_unregister_drv(void) -{ -#ifndef CUSTOMER_HW - if (cfg_multichip) - platform_driver_unregister(&dhd_wifi_platform_dev_driver); - else -#endif - wifi_ctrlfunc_unregister_drv(); -} - -extern int dhd_watchdog_prio; -extern int dhd_dpc_prio; -extern uint dhd_deferred_tx; -#if defined(BCMLXSDMMC) || defined(BCMDBUS) -extern struct semaphore dhd_registration_sem; -#endif - -#ifdef BCMSDIO -static int dhd_wifi_platform_load_sdio(void) -{ - int i; - int err = 0; - wifi_adapter_info_t *adapter; - - BCM_REFERENCE(i); - BCM_REFERENCE(adapter); - /* Sanity check on the module parameters - * - Both watchdog and DPC as tasklets are ok - * - If both watchdog and DPC are threads, TX must be deferred - */ - if (!(dhd_watchdog_prio < 0 && dhd_dpc_prio < 0) && - !(dhd_watchdog_prio >= 0 && dhd_dpc_prio >= 0 && dhd_deferred_tx)) - return -EINVAL; - -#if defined(BCMLXSDMMC) && !defined(DHD_PRELOAD) - sema_init(&dhd_registration_sem, 0); -#endif - - if (dhd_wifi_platdata == NULL) { - DHD_ERROR(("DHD wifi platform data is required for Android build\n")); - DHD_ERROR(("DHD registeing bus directly\n")); - /* x86 bring-up PC needs no power-up operations */ - err = dhd_bus_register(); - return err; - } - -#if defined(BCMLXSDMMC) && !defined(DHD_PRELOAD) - /* power up all adapters */ - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - bool chip_up = FALSE; - int retry = POWERUP_MAX_RETRY; - struct semaphore dhd_chipup_sem; - - adapter = &dhd_wifi_platdata->adapters[i]; - - DHD_INFO(("Power-up adapter '%s'\n", adapter->name)); - DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n", - adapter->irq_num, adapter->intr_flags, adapter->fw_path, adapter->nv_path)); - DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n", - adapter->bus_type, adapter->bus_num, adapter->slot_num)); - - do { - sema_init(&dhd_chipup_sem, 0); - - err = dhd_bus_reg_sdio_notify(&dhd_chipup_sem); - if (err) { - DHD_ERROR(("%s dhd_bus_reg_sdio_notify fail(%d)\n\n", - __FUNCTION__, err)); - return err; - } - - err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY); - if (err) { - dhd_bus_unreg_sdio_notify(); - /* WL_REG_ON state unknown, Power off forcely */ - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - DHD_ERROR(("%s wifi_platform_set_power fail(%d)\n", - __FUNCTION__, err)); - continue; - } else { - wifi_platform_bus_enumerate(adapter, TRUE); - } - - if (down_timeout(&dhd_chipup_sem, msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) { - dhd_bus_unreg_sdio_notify(); - chip_up = TRUE; - break; - } - - DHD_ERROR(("failed to power up %s, %d retry left\n", adapter->name, retry)); - dhd_bus_unreg_sdio_notify(); - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - wifi_platform_bus_enumerate(adapter, FALSE); - } while (retry--); - - if (!chip_up) { - DHD_ERROR(("failed to power up %s, max retry reached**\n", adapter->name)); - return -ENODEV; - } - - } - - err = dhd_bus_register(); - - if (err) { - DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__)); - goto fail; - } - - /* - * Wait till MMC sdio_register_driver callback called and made driver attach. - * It's needed to make sync up exit from dhd insmod and - * Kernel MMC sdio device callback registration - */ - err = down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)); - if (err) { - DHD_ERROR(("%s: sdio_register_driver timeout or error \n", __FUNCTION__)); - dhd_bus_unregister(); - goto fail; - } - - return err; - -fail: - /* power down all adapters */ - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - adapter = &dhd_wifi_platdata->adapters[i]; - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - wifi_platform_bus_enumerate(adapter, FALSE); - } -#endif - - return err; -} -#else /* BCMSDIO */ -static int dhd_wifi_platform_load_sdio(void) -{ - return 0; -} -#endif /* BCMSDIO */ - -#ifdef BCMDBUS -static int dhd_wifi_platform_load_usb(void) -{ - wifi_adapter_info_t *adapter; - s32 timeout = -1; - int i; - int err = 0; - enum wifi_adapter_status wait_status; - - err = dhd_bus_register(); - if (err) { - DHD_ERROR(("%s: usb_register failed\n", __FUNCTION__)); - goto exit; - } - - /* power up all adapters */ - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - adapter = &dhd_wifi_platdata->adapters[i]; - DHD_ERROR(("Power-up adapter '%s'\n", adapter->name)); - DHD_INFO((" - irq %d [flags %d], firmware: %s, nvram: %s\n", - adapter->irq_num, adapter->intr_flags, adapter->fw_path, adapter->nv_path)); - DHD_INFO((" - bus type %d, bus num %d, slot num %d\n\n", - adapter->bus_type, adapter->bus_num, adapter->slot_num)); - err = wifi_platform_set_power(adapter, TRUE, WIFI_TURNON_DELAY); - if (err) { - DHD_ERROR(("failed to wifi_platform_set_power on %s\n", adapter->name)); - goto fail; - } - if (dhd_download_fw_on_driverload) - wait_status = WIFI_STATUS_ATTACH; - else - wait_status = WIFI_STATUS_DETTACH; - timeout = wait_event_interruptible_timeout(adapter->status_event, - wifi_get_adapter_status(adapter, wait_status), - msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)); - if (timeout <= 0) { - err = -1; - DHD_ERROR(("%s: usb_register_driver timeout\n", __FUNCTION__)); - goto fail; - } - } - -exit: - return err; - -fail: - dhd_bus_unregister(); - /* power down all adapters */ - for (i = 0; i < dhd_wifi_platdata->num_adapters; i++) { - adapter = &dhd_wifi_platdata->adapters[i]; - wifi_platform_set_power(adapter, FALSE, WIFI_TURNOFF_DELAY); - } - - return err; -} -#else /* BCMDBUS */ -static int dhd_wifi_platform_load_usb(void) -{ - return 0; -} -#endif /* BCMDBUS */ - -static int dhd_wifi_platform_load(void) -{ - int err = 0; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - wl_android_init(); - - if ((err = dhd_wifi_platform_load_usb())) - goto end; - else if ((err = dhd_wifi_platform_load_sdio())) - goto end; - else - err = dhd_wifi_platform_load_pcie(); - -end: - if (err) - wl_android_exit(); -#if !defined(MULTIPLE_SUPPLICANT) - else - wl_android_post_init(); -#endif - - return err; -}
diff --git a/bcmdhd.1.579.77.41.x/dhd_linux_sched.c b/bcmdhd.1.579.77.41.x/dhd_linux_sched.c deleted file mode 100644 index 88c0cce..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_linux_sched.c +++ /dev/null
@@ -1,51 +0,0 @@ -/* - * Expose some of the kernel scheduler routines - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_linux_sched.c 514727 2014-11-12 03:02:48Z $ - */ -#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; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - rc = sched_setscheduler(p, policy, param); -#endif /* LinuxVer */ - return rc; -} - -int get_scheduler_policy(struct task_struct *p) -{ - int rc = SCHED_NORMAL; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - rc = p->policy; -#endif /* LinuxVer */ - return rc; -}
diff --git a/bcmdhd.1.579.77.41.x/dhd_linux_wq.c b/bcmdhd.1.579.77.41.x/dhd_linux_wq.c deleted file mode 100644 index b791fd2..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_linux_wq.c +++ /dev/null
@@ -1,379 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), Generic work queue framework - * Generic interface to handle dhd deferred work events - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_linux_wq.c 641330 2016-06-02 06:55:00Z $ - */ - -#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 */ -}; - -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; - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) - fifo = kfifo_init(buf, size, flags, lock); -#else - fifo = (struct kfifo *)kzalloc(sizeof(struct kfifo), flags); - if (!fifo) { - return NULL; - } - kfifo_init(fifo, buf, size); -#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)) */ - return fifo; -} - -static inline void -dhd_kfifo_free(struct kfifo *fifo) -{ - kfifo_free(fifo); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31)) - /* FC11 releases the fifo memory */ - kfree(fifo); -#endif -} - -/* deferred work functions */ -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; - DHD_INFO(("%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; - } - - /* - * 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; -}
diff --git a/bcmdhd.1.579.77.41.x/dhd_linux_wq.h b/bcmdhd.1.579.77.41.x/dhd_linux_wq.h deleted file mode 100644 index b06755c..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_linux_wq.h +++ /dev/null
@@ -1,87 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), Generic work queue framework - * Generic interface to handle dhd deferred work events - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_linux_wq.h 704361 2017-06-13 08:50:38Z $ - */ -#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_SOC_RAM_DUMP, - DHD_WQ_WORK_DHD_LOG_DUMP, - DHD_WQ_WORK_INFORM_DHD_MON, - DHD_WQ_WORK_EVENT_LOGTRACE, - DHD_WQ_WORK_DMA_LB_MEM_REL, - DHD_WQ_WORK_DEBUG_UART_DUMP, - DHD_WQ_WORK_SSSR_DUMP, - DHD_WQ_WORK_PKTLOG_DUMP, -#ifdef DHD_UPDATE_INTF_MAC - DHD_WQ_WORK_IF_UPDATE, -#endif /* DHD_UPDATE_INTF_MAC */ -#ifdef BCOL_TCPKA_SYNC - DHD_WQ_WORK_SYNC_BCOL_TCPKA_CONN, -#endif /* DHD_BCOL_TCPKA */ -#ifdef RELOAD_WIFI - DHD_WQ_RELOAD_FW, -#endif /* RELOAD_WIFI */ - 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 - -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); -#endif /* _dhd_linux_wq_h_ */
diff --git a/bcmdhd.1.579.77.41.x/dhd_mschdbg.c b/bcmdhd.1.579.77.41.x/dhd_mschdbg.c deleted file mode 100644 index c1032f2..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_mschdbg.c +++ /dev/null
@@ -1,747 +0,0 @@ -/* - * DHD debugability support - * - * <<Broadcom-WL-IPTag/Open:>> - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $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 - -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 > 0) { - msch_event_log_profiler_event_data_t *p = - (msch_event_log_profiler_event_data_t *)data; - int size = WL_MSCH_EVENT_LOG_HEAD_SIZE + p->hdr.count * sizeof(uint32); - data += size; - len -= size; - dhd_mschdbg_us_to_sec(p->time_hi, p->time_lo, &s, &ss); - MSCH_EVENT_HEAD(0); - MSCH_EVENT(("%06d.%06d [wl%d]: ", s, ss, p->hdr.tag)); - p->hdr.tag = EVENT_LOG_TAG_MSCHPROFILE; - p->hdr.fmt_num = ntoh16(p->hdr.fmt_num); - dhd_dbg_verboselog_printf(dhdp, &p->hdr, raw_event_ptr, p->data); - } - 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, int tag, uint32 *log_ptr) -{ - head_log = "CONSOLE"; - if (tag == EVENT_LOG_TAG_MSCHPROFILE) { - msch_event_log_profiler_event_data_t *p = - (msch_event_log_profiler_event_data_t *)log_ptr; - uint32 s, ss; - dhd_mschdbg_us_to_sec(p->time_hi, p->time_lo, &s, &ss); - MSCH_EVENT_HEAD(0); - MSCH_EVENT(("%06d.%06d [wl%d]: ", s, ss, p->hdr.tag)); - p->hdr.tag = EVENT_LOG_TAG_MSCHPROFILE; - p->hdr.fmt_num = ntoh16(p->hdr.fmt_num); - dhd_dbg_verboselog_printf(dhdp, &p->hdr, raw_event_ptr, p->data); - } else { - msch_collect_tlv_t *p = (msch_collect_tlv_t *)log_ptr; - int type = ntoh16(p->type); - int len = ntoh16(p->size); - dhd_mschdbg_dump_data(dhdp, raw_event_ptr, type, p->value, len); - } -} -#endif /* SHOW_LOGTRACE */
diff --git a/bcmdhd.1.579.77.41.x/dhd_mschdbg.h b/bcmdhd.1.579.77.41.x/dhd_mschdbg.h deleted file mode 100644 index 749e111..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_mschdbg.h +++ /dev/null
@@ -1,39 +0,0 @@ -/* - * DHD debugability header file - * - * <<Broadcom-WL-IPTag/Open:>> - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $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, int tag, - uint32 *log_ptr); -#endif /* SHOW_LOGTRACE */ - -#endif /* _dhd_mschdbg_h_ */
diff --git a/bcmdhd.1.579.77.41.x/dhd_msgbuf.c b/bcmdhd.1.579.77.41.x/dhd_msgbuf.c deleted file mode 100644 index 455f125..0000000 --- a/bcmdhd.1.579.77.41.x/dhd_msgbuf.c +++ /dev/null
@@ -1,8950 +0,0 @@ -/** - * @file definition of host message ring functionality - * Provides type definitions and function prototypes used to link the - * DHD OS, bus, and protocol modules. - * - * Copyright (C) 1999-2017, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * - * <<Broadcom-WL-IPTag/Open:>> - * - * $Id: dhd_msgbuf.c 704361 2017-06-13 08:50:38Z $ - */ - - -#include <typedefs.h> -#include <osl.h> - -#include <bcmutils.h> -#include <bcmmsgbuf.h> -#include <bcmendian.h> - -#include <dngl_stats.h> -#include <dhd.h> -#include <dhd_proto.h> - -#include <dhd_bus.h> - -#include <dhd_dbg.h> -#include <siutils.h> -#include <dhd_debug.h> - -#include <dhd_flowring.h> - -#include <pcie_core.h> -#include <bcmpcie.h> -#include <dhd_pcie.h> -#include <dhd_config.h> -#ifdef DHD_TIMESYNC -#include <dhd_timesync.h> -#endif /* DHD_TIMESYNC */ - -#if defined(DHD_LB) -#include <linux/cpu.h> -#include <bcm_ring.h> -#define DHD_LB_WORKQ_SZ (8192) -#define DHD_LB_WORKQ_SYNC (16) -#define DHD_LB_WORK_SCHED (DHD_LB_WORKQ_SYNC * 2) -#endif /* DHD_LB */ - -#include <hnd_debug.h> -#include <hnd_armtrap.h> - -#ifdef DHD_PKT_LOGGING -#include <dhd_pktlog.h> -#endif /* DHD_PKT_LOGGING */ - -extern char dhd_version[]; -extern char fw_version[]; - -/** - * Host configures a soft doorbell for d2h rings, by specifying a 32bit host - * address where a value must be written. Host may also interrupt coalescing - * on this soft doorbell. - * Use Case: Hosts with network processors, may register with the dongle the - * network processor's thread wakeup register and a value corresponding to the - * core/thread context. Dongle will issue a write transaction <address,value> - * to the PCIE RC which will need to be routed to the mapped register space, by - * the host. - */ -/* #define DHD_D2H_SOFT_DOORBELL_SUPPORT */ - -/* Dependency Check */ -#if defined(IOCTLRESP_USE_CONSTMEM) && defined(DHD_USE_STATIC_CTRLBUF) -#error "DHD_USE_STATIC_CTRLBUF is NOT working with DHD_USE_OSLPKT_FOR_RESPBUF" -#endif /* IOCTLRESP_USE_CONSTMEM && DHD_USE_STATIC_CTRLBUF */ - -#define RETRIES 2 /* # of retries to retrieve matching ioctl response */ - -#define DEFAULT_RX_BUFFERS_TO_POST 256 -#define RXBUFPOST_THRESHOLD 32 -#define RX_BUF_BURST 32 /* Rx buffers for MSDU Data */ - -#define DHD_STOP_QUEUE_THRESHOLD 200 -#define DHD_START_QUEUE_THRESHOLD 100 - -#define RX_DMA_OFFSET 8 /* Mem2mem DMA inserts an extra 8 */ -#define IOCT_RETBUF_SIZE (RX_DMA_OFFSET + WLC_IOCTL_MAXLEN) - -/* flags for ioctl pending status */ -#define MSGBUF_IOCTL_ACK_PENDING (1<<0) -#define MSGBUF_IOCTL_RESP_PENDING (1<<1) - -#define DMA_ALIGN_LEN 4 - -#define DMA_D2H_SCRATCH_BUF_LEN 8 -#define DMA_XFER_LEN_LIMIT 0x400000 - -#ifdef BCM_HOST_BUF -#ifndef DMA_HOST_BUFFER_LEN -#define DMA_HOST_BUFFER_LEN 0x200000 -#endif -#endif /* BCM_HOST_BUF */ - -#define DHD_FLOWRING_IOCTL_BUFPOST_PKTSZ 8192 - -#define DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D 1 -#define DHD_FLOWRING_MAX_EVENTBUF_POST 32 -#define DHD_FLOWRING_MAX_IOCTLRESPBUF_POST 8 -#define DHD_H2D_INFORING_MAX_BUF_POST 32 -#define DHD_MAX_TSBUF_POST 8 - -#define DHD_PROT_FUNCS 41 - -/* Length of buffer in host for bus throughput measurement */ -#define DHD_BUS_TPUT_BUF_LEN 2048 - -#define TXP_FLUSH_NITEMS - -/* optimization to write "n" tx items at a time to ring */ -#define TXP_FLUSH_MAX_ITEMS_FLUSH_CNT 48 - -#define RING_NAME_MAX_LENGTH 24 -#define CTRLSUB_HOSTTS_MEESAGE_SIZE 1024 -/* Giving room before ioctl_trans_id rollsover. */ -#define BUFFER_BEFORE_ROLLOVER 300 - -struct msgbuf_ring; /* ring context for common and flow rings */ - -/** - * PCIE D2H DMA Complete Sync Modes - * - * Firmware may interrupt the host, prior to the D2H Mem2Mem DMA completes into - * Host system memory. A WAR using one of 3 approaches is needed: - * 1. Dongle places a modulo-253 seqnum in last word of each D2H message - * 2. XOR Checksum, with epoch# in each work item. Dongle builds an XOR checksum - * writes in the last word of each work item. Each work item has a seqnum - * number = sequence num % 253. - * - * 3. Read Barrier: Dongle does a host memory read access prior to posting an - * interrupt, ensuring that D2H data transfer indeed completed. - * 4. Dongle DMA's all indices after producing items in the D2H ring, flushing - * ring contents before the indices. - * - * Host does not sync for DMA to complete with option #3 or #4, and a noop sync - * callback (see dhd_prot_d2h_sync_none) may be bound. - * - * Dongle advertizes host side sync mechanism requirements. - */ - -#define PCIE_D2H_SYNC_WAIT_TRIES (512UL) -#define PCIE_D2H_SYNC_NUM_OF_STEPS (5UL) -#define PCIE_D2H_SYNC_DELAY (100UL) /* in terms of usecs */ - -/** - * Custom callback attached based upon D2H DMA Sync mode advertized by dongle. - * - * On success: return cmn_msg_hdr_t::msg_type - * On failure: return 0 (invalid msg_type) - */ -typedef uint8 (* d2h_sync_cb_t)(dhd_pub_t *dhd, struct msgbuf_ring *ring, - volatile cmn_msg_hdr_t *msg, int msglen); - -/* - * +---------------------------------------------------------------------------- - * - * RingIds and FlowId are not equivalent as ringids include D2H rings whereas - * flowids do not. - * - * Dongle advertizes the max H2D rings, as max_sub_queues = 'N' which includes - * the H2D common rings as well as the (N-BCMPCIE_H2D_COMMON_MSGRINGS) flowrings - * - * Here is a sample mapping for (based on PCIE Full Dongle Rev5) where, - * BCMPCIE_H2D_COMMON_MSGRINGS = 2, i.e. 2 H2D common rings, - * BCMPCIE_COMMON_MSGRINGS = 5, i.e. include 3 D2H common rings. - * - * H2D Control Submit RingId = 0 FlowId = 0 reserved never allocated - * H2D RxPost Submit RingId = 1 FlowId = 1 reserved never allocated - * - * D2H Control Complete RingId = 2 - * D2H Transmit Complete RingId = 3 - * D2H Receive Complete RingId = 4 - * - * H2D TxPost FLOWRING RingId = 5 FlowId = 2 (1st flowring) - * H2D TxPost FLOWRING RingId = 6 FlowId = 3 (2nd flowring) - * H2D TxPost FLOWRING RingId = 5 + (N-1) FlowId = (N-1) (Nth flowring) - * - * When TxPost FlowId(s) are allocated, the FlowIds [0..FLOWID_RESERVED) are - * unused, where FLOWID_RESERVED is BCMPCIE_H2D_COMMON_MSGRINGS. - * - * Example: when a system supports 4 bc/mc and 128 uc flowrings, with - * BCMPCIE_H2D_COMMON_MSGRINGS = 2, and BCMPCIE_H2D_COMMON_MSGRINGS = 5, and the - * FlowId values would be in the range [2..133] and the corresponding - * RingId values would be in the range [5..136]. - * - * The flowId allocator, may chose to, allocate Flowids: - * bc/mc (per virtual interface) in one consecutive range [2..(2+VIFS)) - * X# of uc flowids in consecutive ranges (per station Id), where X is the - * packet's access category (e.g. 4 uc flowids per station). - * - * CAUTION: - * When DMA indices array feature is used, RingId=5, corresponding to the 0th - * FLOWRING, will actually use the FlowId as index into the H2D DMA index, - * since the FlowId truly represents the index in the H2D DMA indices array. - * - * Likewise, in the D2H direction, the RingId - BCMPCIE_H2D_COMMON_MSGRINGS, - * will represent the index in the D2H DMA indices array. - * - * +---------------------------------------------------------------------------- - */ - -/* First TxPost Flowring Id */ -#define DHD_FLOWRING_START_FLOWID BCMPCIE_H2D_COMMON_MSGRINGS - -/* Determine whether a ringid belongs to a TxPost flowring */ -#define DHD_IS_FLOWRING(ringid, max_flow_rings) \ - ((ringid) >= BCMPCIE_COMMON_MSGRINGS && \ - (ringid) < ((max_flow_rings) + BCMPCIE_COMMON_MSGRINGS)) - -/* Convert a H2D TxPost FlowId to a MsgBuf RingId */ -#define DHD_FLOWID_TO_RINGID(flowid) \ - (BCMPCIE_COMMON_MSGRINGS + ((flowid) - BCMPCIE_H2D_COMMON_MSGRINGS)) - -/* Convert a MsgBuf RingId to a H2D TxPost FlowId */ -#define DHD_RINGID_TO_FLOWID(ringid) \ - (BCMPCIE_H2D_COMMON_MSGRINGS + ((ringid) - BCMPCIE_COMMON_MSGRINGS)) - -/* Convert a H2D MsgBuf RingId to an offset index into the H2D DMA indices array - * This may be used for the H2D DMA WR index array or H2D DMA RD index array or - * any array of H2D rings. - */ -#define DHD_H2D_RING_OFFSET(ringid) \ - (((ringid) >= BCMPCIE_COMMON_MSGRINGS) ? DHD_RINGID_TO_FLOWID(ringid) : (ringid)) - -/* Convert a H2D MsgBuf Flowring Id to an offset index into the H2D DMA indices array - * This may be used for IFRM. - */ -#define DHD_H2D_FRM_FLOW_RING_OFFSET(ringid) \ - ((ringid) - BCMPCIE_COMMON_MSGRINGS) - -/* Convert a D2H MsgBuf RingId to an offset index into the D2H DMA indices array - * This may be used for the D2H DMA WR index array or D2H DMA RD index array or - * any array of D2H rings. - * d2h debug ring is located at the end, i.e. after all the tx flow rings and h2d debug ring - * max_h2d_rings: total number of h2d rings - */ -#define DHD_D2H_RING_OFFSET(ringid, max_h2d_rings) \ - ((ringid) > (max_h2d_rings) ? \ - ((ringid) - max_h2d_rings) : \ - ((ringid) - BCMPCIE_H2D_COMMON_MSGRINGS)) - -/* Convert a D2H DMA Indices Offset to a RingId */ -#define DHD_D2H_RINGID(offset) \ - ((offset) + BCMPCIE_H2D_COMMON_MSGRINGS) - - -#define DHD_DMAH_NULL ((void*)NULL) - -/* - * Pad a DMA-able buffer by an additional cachline. If the end of the DMA-able - * buffer does not occupy the entire cacheline, and another object is placed - * following the DMA-able buffer, data corruption may occur if the DMA-able - * buffer is used to DMAing into (e.g. D2H direction), when HW cache coherency - * is not available. - */ -#if defined(L1_CACHE_BYTES) -#define DHD_DMA_PAD (L1_CACHE_BYTES) -#else -#define DHD_DMA_PAD (128) -#endif - -/* Used in loopback tests */ -typedef struct dhd_dmaxfer { - dhd_dma_buf_t srcmem; - dhd_dma_buf_t dstmem; - uint32 srcdelay; - uint32 destdelay; - uint32 len; - bool in_progress; - uint64 start_usec; - uint32 d11_lpbk; -} dhd_dmaxfer_t; - -/** - * msgbuf_ring : This object manages the host side ring that includes a DMA-able - * buffer, the WR and RD indices, ring parameters such as max number of items - * an length of each items, and other miscellaneous runtime state. - * A msgbuf_ring may be used to represent a H2D or D2H common ring or a - * H2D TxPost ring as specified in the PCIE FullDongle Spec. - * Ring parameters are conveyed to the dongle, which maintains its own peer end - * ring state. Depending on whether the DMA Indices feature is supported, the - * host will update the WR/RD index in the DMA indices array in host memory or - * directly in dongle memory. - */ -typedef struct msgbuf_ring { - bool inited; - uint16 idx; /* ring id */ - uint16 rd; /* read index */ - uint16 curr_rd; /* read index for debug */ - uint16 wr; /* write index */ - uint16 max_items; /* maximum number of items in ring */ - uint16 item_len; /* length of each item in the ring */ - sh_addr_t base_addr; /* LITTLE ENDIAN formatted: base address */ - dhd_dma_buf_t dma_buf; /* DMA-able buffer: pa, va, len, dmah, secdma */ - uint32 seqnum; /* next expected item's sequence number */ -#ifdef TXP_FLUSH_NITEMS - void *start_addr; - /* # of messages on ring not yet announced to dongle */ - uint16 pend_items_count; -#endif /* TXP_FLUSH_NITEMS */ - - uint8 ring_type; - uint8 n_completion_ids; - bool create_pending; - uint16 create_req_id; - uint8 current_phase; - uint16 compeltion_ring_ids[MAX_COMPLETION_RING_IDS_ASSOCIATED]; - uchar name[RING_NAME_MAX_LENGTH]; - uint32 ring_mem_allocated; -} msgbuf_ring_t; - -#define DHD_RING_BGN_VA(ring) ((ring)->dma_buf.va) -#define DHD_RING_END_VA(ring) \ - ((uint8 *)(DHD_RING_BGN_VA((ring))) + \ - (((ring)->max_items - 1) * (ring)->item_len)) - - - -/* This can be overwritten by module parameter defined in dhd_linux.c - * or by dhd iovar h2d_max_txpost. - */ -int h2d_max_txpost = H2DRING_TXPOST_MAX_ITEM; - -/** DHD protocol handle. Is an opaque type to other DHD software layers. */ -typedef struct dhd_prot { - osl_t *osh; /* OSL handle */ - uint16 rxbufpost; - uint16 max_rxbufpost; - uint16 max_eventbufpost; - uint16 max_ioctlrespbufpost; - uint16 max_tsbufpost; - uint16 max_infobufpost; - uint16 infobufpost; - uint16 cur_event_bufs_posted; - uint16 cur_ioctlresp_bufs_posted; - uint16 cur_ts_bufs_posted; - - /* Flow control mechanism based on active transmits pending */ - uint16 active_tx_count; /* increments on every packet tx, and decrements on tx_status */ - uint16 h2d_max_txpost; - uint16 txp_threshold; /* optimization to write "n" tx items at a time to ring */ - - /* MsgBuf Ring info: has a dhd_dma_buf that is dynamically allocated */ - msgbuf_ring_t h2dring_ctrl_subn; /* H2D ctrl message submission ring */ - msgbuf_ring_t h2dring_rxp_subn; /* H2D RxBuf post ring */ - msgbuf_ring_t d2hring_ctrl_cpln; /* D2H ctrl completion ring */ - msgbuf_ring_t d2hring_tx_cpln; /* D2H Tx complete message ring */ - msgbuf_ring_t d2hring_rx_cpln; /* D2H Rx complete message ring */ - msgbuf_ring_t *h2dring_info_subn; /* H2D info submission ring */ - msgbuf_ring_t *d2hring_info_cpln; /* D2H info completion ring */ - - msgbuf_ring_t *h2d_flowrings_pool; /* Pool of preallocated flowings */ - dhd_dma_buf_t flowrings_dma_buf; /* Contiguous DMA buffer for flowrings */ - uint16 h2d_rings_total; /* total H2D (common rings + flowrings) */ - - uint32 rx_dataoffset; - - dhd_mb_ring_t mb_ring_fn; /* called when dongle needs to be notified of new msg */ - dhd_mb_ring_2_t mb_2_ring_fn; /* called when dongle needs to be notified of new msg */ - - /* ioctl related resources */ - uint8 ioctl_state; - int16 ioctl_status; /* status returned from dongle */ - uint16 ioctl_resplen; - dhd_ioctl_recieved_status_t ioctl_received; - uint curr_ioctl_cmd; - dhd_dma_buf_t retbuf; /* For holding ioctl response */ - dhd_dma_buf_t ioctbuf; /* For holding ioctl request */ - - dhd_dma_buf_t d2h_dma_scratch_buf; /* For holding d2h scratch */ - - /* DMA-able arrays for holding WR and RD indices */ - uint32 rw_index_sz; /* Size of a RD or WR index in dongle */ - dhd_dma_buf_t h2d_dma_indx_wr_buf; /* Array of H2D WR indices */ - dhd_dma_buf_t h2d_dma_indx_rd_buf; /* Array of H2D RD indices */ - dhd_dma_buf_t d2h_dma_indx_wr_buf; /* Array of D2H WR indices */ - dhd_dma_buf_t d2h_dma_indx_rd_buf; /* Array of D2H RD indices */ - dhd_dma_buf_t h2d_ifrm_indx_wr_buf; /* Array of H2D WR indices for ifrm */ - - dhd_dma_buf_t host_bus_throughput_buf; /* bus throughput measure buffer */ - - dhd_dma_buf_t *flowring_buf; /* pool of flow ring buf */ - uint32 flowring_num; - - d2h_sync_cb_t d2h_sync_cb; /* Sync on D2H DMA done: SEQNUM or XORCSUM */ - ulong d2h_sync_wait_max; /* max number of wait loops to receive one msg */ - ulong d2h_sync_wait_tot; /* total wait loops */ - - dhd_dmaxfer_t dmaxfer; /* for test/DMA loopback */ - - uint16 ioctl_seq_no; - uint16 data_seq_no; - uint16 ioctl_trans_id; - void *pktid_ctrl_map; /* a pktid maps to a packet and its metadata */ - void *pktid_rx_map; /* pktid map for rx path */ - void *pktid_tx_map; /* pktid map for tx path */ - void *rx_lock; /* rx pktid map and rings access protection */ - bool metadata_dbg; - void *pktid_map_handle_ioctl; - - /* Applications/utilities can read tx and rx metadata using IOVARs */ - uint16 rx_metadata_offset; - uint16 tx_metadata_offset; - - -#if defined(DHD_D2H_SOFT_DOORBELL_SUPPORT) - /* Host's soft doorbell configuration */ - bcmpcie_soft_doorbell_t soft_doorbell[BCMPCIE_D2H_COMMON_MSGRINGS]; -#endif /* DHD_D2H_SOFT_DOORBELL_SUPPORT */ - - /* Work Queues to be used by the producer and the consumer, and threshold - * when the WRITE index must be synced to consumer's workq - */ -#if defined(DHD_LB_TXC) - uint32 tx_compl_prod_sync ____cacheline_aligned; - bcm_workq_t tx_compl_prod, tx_compl_cons; -#endif /* DHD_LB_TXC */ -#if defined(DHD_LB_RXC) - uint32 rx_compl_prod_sync ____cacheline_aligned; - bcm_workq_t rx_compl_prod, rx_compl_cons; -#endif /* DHD_LB_RXC */ - - dhd_dma_buf_t fw_trap_buf; /* firmware trap buffer */ - - uint32 host_ipc_version; /* Host sypported IPC rev */ - uint32 device_ipc_version; /* FW supported IPC rev */ - uint32 active_ipc_version; /* Host advertised IPC rev */ - dhd_dma_buf_t hostts_req_buf; /* For holding host timestamp request buf */ - bool hostts_req_buf_inuse; - bool rx_ts_log_enabled; - bool tx_ts_log_enabled; -} dhd_prot_t; - -extern void dhd_schedule_dmaxfer_free(dhd_pub_t* dhdp, dmaxref_mem_map_t *dmmap); - -static atomic_t dhd_msgbuf_rxbuf_post_event_bufs_running = ATOMIC_INIT(0); - -/* Convert a dmaaddr_t to a base_addr with htol operations */ -static INLINE void dhd_base_addr_htolpa(sh_addr_t *base_addr, dmaaddr_t pa); - -/* APIs for managing a DMA-able buffer */ -static int dhd_dma_buf_audit(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf); -static int dhd_dma_buf_alloc(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf, uint32 buf_len); -static void dhd_dma_buf_reset(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf); -static void dhd_dma_buf_free(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf); - -/* msgbuf ring management */ -static int dhd_prot_ring_attach(dhd_pub_t *dhd, msgbuf_ring_t *ring, - const char *name, uint16 max_items, uint16 len_item, uint16 ringid); -static void dhd_prot_ring_init(dhd_pub_t *dhd, msgbuf_ring_t *ring); -static void dhd_prot_ring_reset(dhd_pub_t *dhd, msgbuf_ring_t *ring); -static void dhd_prot_ring_detach(dhd_pub_t *dhd, msgbuf_ring_t *ring); -static void dhd_prot_process_fw_timestamp(dhd_pub_t *dhd, void* buf); - -/* Pool of pre-allocated msgbuf_ring_t with DMA-able buffers for Flowrings */ -static int dhd_prot_flowrings_pool_attach(dhd_pub_t *dhd); -static void dhd_prot_flowrings_pool_reset(dhd_pub_t *dhd); -static void dhd_prot_flowrings_pool_detach(dhd_pub_t *dhd); - -/* Fetch and Release a flowring msgbuf_ring from flowring pool */ -static msgbuf_ring_t *dhd_prot_flowrings_pool_fetch(dhd_pub_t *dhd, - uint16 flowid); -/* see also dhd_prot_flowrings_pool_release() in dhd_prot.h */ - -/* Producer: Allocate space in a msgbuf ring */ -static void* dhd_prot_alloc_ring_space(dhd_pub_t *dhd, msgbuf_ring_t *ring, - uint16 nitems, uint16 *alloced, bool exactly_nitems); -static void* dhd_prot_get_ring_space(msgbuf_ring_t *ring, uint16 nitems, - uint16 *alloced, bool exactly_nitems); - -/* Consumer: Determine the location where the next message may be consumed */ -static uint8* dhd_prot_get_read_addr(dhd_pub_t *dhd, msgbuf_ring_t *ring, - uint32 *available_len); - -/* Producer (WR index update) or Consumer (RD index update) indication */ -static void dhd_prot_ring_write_complete(dhd_pub_t *dhd, msgbuf_ring_t *ring, - void *p, uint16 len); -static void dhd_prot_upd_read_idx(dhd_pub_t *dhd, msgbuf_ring_t *ring); - -static INLINE int dhd_prot_dma_indx_alloc(dhd_pub_t *dhd, uint8 type, - dhd_dma_buf_t *dma_buf, uint32 bufsz); - -/* Set/Get a RD or WR index in the array of indices */ -/* See also: dhd_prot_dma_indx_init() */ -void dhd_prot_dma_indx_set(dhd_pub_t *dhd, uint16 new_index, uint8 type, - uint16 ringid); -static uint16 dhd_prot_dma_indx_get(dhd_pub_t *dhd, uint8 type, uint16 ringid); - -/* Locate a packet given a pktid */ -static INLINE void *dhd_prot_packet_get(dhd_pub_t *dhd, uint32 pktid, uint8 pkttype, - bool free_pktid); -/* Locate a packet given a PktId and free it. */ -static INLINE void dhd_prot_packet_free(dhd_pub_t *dhd, void *pkt, uint8 pkttype, bool send); - -static int dhd_msgbuf_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, - void *buf, uint len, uint8 action); -static int dhd_msgbuf_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, - void *buf, uint len, uint8 action); -static int dhd_msgbuf_wait_ioctl_cmplt(dhd_pub_t *dhd, uint32 len, void *buf); -static int dhd_fillup_ioct_reqst(dhd_pub_t *dhd, uint16 len, uint cmd, - void *buf, int ifidx); - -/* Post buffers for Rx, control ioctl response and events */ -static uint16 dhd_msgbuf_rxbuf_post_ctrlpath(dhd_pub_t *dhd, uint8 msgid, uint32 max_to_post); -static void dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd_pub_t *pub); -static void dhd_msgbuf_rxbuf_post_event_bufs(dhd_pub_t *pub); -static void dhd_msgbuf_rxbuf_post(dhd_pub_t *dhd, bool use_rsv_pktid); -static int dhd_prot_rxbuf_post(dhd_pub_t *dhd, uint16 count, bool use_rsv_pktid); -static int dhd_msgbuf_rxbuf_post_ts_bufs(dhd_pub_t *pub); - -static void dhd_prot_return_rxbuf(dhd_pub_t *dhd, uint32 pktid, uint32 rxcnt); - - -/* D2H Message handling */ -static int dhd_prot_process_msgtype(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8 *buf, uint32 len); - -/* D2H Message handlers */ -static void dhd_prot_noop(dhd_pub_t *dhd, void *msg); -static void dhd_prot_txstatus_process(dhd_pub_t *dhd, void *msg); -static void dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void *msg); -static void dhd_prot_ioctack_process(dhd_pub_t *dhd, void *msg); -static void dhd_prot_ringstatus_process(dhd_pub_t *dhd, void *msg); -static void dhd_prot_genstatus_process(dhd_pub_t *dhd, void *msg); -static void dhd_prot_event_process(dhd_pub_t *dhd, void *msg); - -/* Loopback test with dongle */ -static void dmaxfer_free_dmaaddr(dhd_pub_t *dhd, dhd_dmaxfer_t *dma); -static int dmaxfer_prepare_dmaaddr(dhd_pub_t *dhd, uint len, uint srcdelay, - uint destdelay, dhd_dmaxfer_t *dma); -static void dhd_msgbuf_dmaxfer_process(dhd_pub_t *dhd, void *msg); - -/* Flowring management communication with dongle */ -static void dhd_prot_flow_ring_create_response_process(dhd_pub_t *dhd, void *msg); -static void dhd_prot_flow_ring_delete_response_process(dhd_pub_t *dhd, void *msg); -static void dhd_prot_flow_ring_flush_response_process(dhd_pub_t *dhd, void *msg); -static void dhd_prot_process_flow_ring_resume_response(dhd_pub_t *dhd, void* msg); -static void dhd_prot_process_flow_ring_suspend_response(dhd_pub_t *dhd, void* msg); - -/* Monitor Mode */ -#ifdef WL_MONITOR -extern bool dhd_monitor_enabled(dhd_pub_t *dhd, int ifidx); -extern void dhd_rx_mon_pkt(dhd_pub_t *dhdp, host_rxbuf_cmpl_t* msg, void *pkt, int ifidx); -#endif /* WL_MONITOR */ - -/* Configure a soft doorbell per D2H ring */ -static void dhd_msgbuf_ring_config_d2h_soft_doorbell(dhd_pub_t *dhd); -static void dhd_prot_process_d2h_ring_config_complete(dhd_pub_t *dhd, void *msg); -static void dhd_prot_process_d2h_ring_create_complete(dhd_pub_t *dhd, void *buf); -static void dhd_prot_process_h2d_ring_create_complete(dhd_pub_t *dhd, void *buf); -static void dhd_prot_process_d2h_mb_data(dhd_pub_t *dhd, void* buf); -static void dhd_prot_process_infobuf_complete(dhd_pub_t *dhd, void* buf); -static void dhd_prot_detach_info_rings(dhd_pub_t *dhd); -static void dhd_prot_process_d2h_host_ts_complete(dhd_pub_t *dhd, void* buf); - -typedef void (*dhd_msgbuf_func_t)(dhd_pub_t *dhd, void *msg); - -/** callback functions for messages generated by the dongle */ -#define MSG_TYPE_INVALID 0 - -static dhd_msgbuf_func_t table_lookup[DHD_PROT_FUNCS] = { - dhd_prot_noop, /* 0 is MSG_TYPE_INVALID */ - dhd_prot_genstatus_process, /* MSG_TYPE_GEN_STATUS */ - dhd_prot_ringstatus_process, /* MSG_TYPE_RING_STATUS */ - NULL, - dhd_prot_flow_ring_create_response_process, /* MSG_TYPE_FLOW_RING_CREATE_CMPLT */ - NULL, - dhd_prot_flow_ring_delete_response_process, /* MSG_TYPE_FLOW_RING_DELETE_CMPLT */ - NULL, - dhd_prot_flow_ring_flush_response_process, /* MSG_TYPE_FLOW_RING_FLUSH_CMPLT */ - NULL, - dhd_prot_ioctack_process, /* MSG_TYPE_IOCTLPTR_REQ_ACK */ - NULL, - dhd_prot_ioctcmplt_process, /* MSG_TYPE_IOCTL_CMPLT */ - NULL, - dhd_prot_event_process, /* MSG_TYPE_WL_EVENT */ - NULL, - dhd_prot_txstatus_process, /* MSG_TYPE_TX_STATUS */ - NULL, - NULL, /* MSG_TYPE_RX_CMPLT use dedicated handler */ - NULL, - dhd_msgbuf_dmaxfer_process, /* MSG_TYPE_LPBK_DMAXFER_CMPLT */ - NULL, /* MSG_TYPE_FLOW_RING_RESUME */ - dhd_prot_process_flow_ring_resume_response, /* MSG_TYPE_FLOW_RING_RESUME_CMPLT */ - NULL, /* MSG_TYPE_FLOW_RING_SUSPEND */ - dhd_prot_process_flow_ring_suspend_response, /* MSG_TYPE_FLOW_RING_SUSPEND_CMPLT */ - NULL, /* MSG_TYPE_INFO_BUF_POST */ - dhd_prot_process_infobuf_complete, /* MSG_TYPE_INFO_BUF_CMPLT */ - NULL, /* MSG_TYPE_H2D_RING_CREATE */ - NULL, /* MSG_TYPE_D2H_RING_CREATE */ - dhd_prot_process_h2d_ring_create_complete, /* MSG_TYPE_H2D_RING_CREATE_CMPLT */ - dhd_prot_process_d2h_ring_create_complete, /* MSG_TYPE_D2H_RING_CREATE_CMPLT */ - NULL, /* MSG_TYPE_H2D_RING_CONFIG */ - NULL, /* MSG_TYPE_D2H_RING_CONFIG */ - NULL, /* MSG_TYPE_H2D_RING_CONFIG_CMPLT */ - dhd_prot_process_d2h_ring_config_complete, /* MSG_TYPE_D2H_RING_CONFIG_CMPLT */ - NULL, /* MSG_TYPE_H2D_MAILBOX_DATA */ - dhd_prot_process_d2h_mb_data, /* MSG_TYPE_D2H_MAILBOX_DATA */ - NULL, /* MSG_TYPE_TIMSTAMP_BUFPOST */ - NULL, /* MSG_TYPE_HOSTTIMSTAMP */ - dhd_prot_process_d2h_host_ts_complete, /* MSG_TYPE_HOSTTIMSTAMP_CMPLT */ - dhd_prot_process_fw_timestamp, /* MSG_TYPE_FIRMWARE_TIMESTAMP */ -}; - - -#ifdef DHD_RX_CHAINING - -#define PKT_CTF_CHAINABLE(dhd, ifidx, evh, prio, h_sa, h_da, h_prio) \ - (dhd_wet_chainable(dhd) && \ - dhd_rx_pkt_chainable((dhd), (ifidx)) && \ - !ETHER_ISNULLDEST(((struct ether_header *)(evh))->ether_dhost) && \ - !ETHER_ISMULTI(((struct ether_header *)(evh))->ether_dhost) && \ - !eacmp((h_da), ((struct ether_header *)(evh))->ether_dhost) && \ - !eacmp((h_sa), ((struct ether_header *)(evh))->ether_shost) && \ - ((h_prio) == (prio)) && (dhd_ctf_hotbrc_check((dhd), (evh), (ifidx))) && \ - ((((struct ether_header *)(evh))->ether_type == HTON16(ETHER_TYPE_IP)) || \ - (((struct ether_header *)(evh))->ether_type == HTON16(ETHER_TYPE_IPV6)))) - -static INLINE void BCMFASTPATH dhd_rxchain_reset(rxchain_info_t *rxchain); -static void BCMFASTPATH dhd_rxchain_frame(dhd_pub_t *dhd, void *pkt, uint ifidx); -static void BCMFASTPATH dhd_rxchain_commit(dhd_pub_t *dhd); - -#define DHD_PKT_CTF_MAX_CHAIN_LEN 64 - -#endif /* DHD_RX_CHAINING */ - -static void dhd_prot_h2d_sync_init(dhd_pub_t *dhd); - -/** - * D2H DMA to completion callback handlers. Based on the mode advertised by the - * dongle through the PCIE shared region, the appropriate callback will be - * registered in the proto layer to be invoked prior to precessing any message - * from a D2H DMA ring. If the dongle uses a read barrier or another mode that - * does not require host participation, then a noop callback handler will be - * bound that simply returns the msg_type. - */ -static void dhd_prot_d2h_sync_livelock(dhd_pub_t *dhd, uint32 msg_seqnum, msgbuf_ring_t *ring, - uint32 tries, volatile uchar *msg, int msglen); -static uint8 dhd_prot_d2h_sync_seqnum(dhd_pub_t *dhd, msgbuf_ring_t *ring, - volatile cmn_msg_hdr_t *msg, int msglen); -static uint8 dhd_prot_d2h_sync_xorcsum(dhd_pub_t *dhd, msgbuf_ring_t *ring, - volatile cmn_msg_hdr_t *msg, int msglen); -static uint8 dhd_prot_d2h_sync_none(dhd_pub_t *dhd, msgbuf_ring_t *ring, - volatile cmn_msg_hdr_t *msg, int msglen); -static void dhd_prot_d2h_sync_init(dhd_pub_t *dhd); -static int dhd_send_d2h_ringcreate(dhd_pub_t *dhd, msgbuf_ring_t *ring_to_create); -static int dhd_send_h2d_ringcreate(dhd_pub_t *dhd, msgbuf_ring_t *ring_to_create); -static uint16 dhd_get_max_flow_rings(dhd_pub_t *dhd); - -bool -dhd_prot_is_cmpl_ring_empty(dhd_pub_t *dhd, void *prot_info) -{ - msgbuf_ring_t *flow_ring = (msgbuf_ring_t *)prot_info; - uint16 rd, wr; - bool ret; - - if (dhd->dma_d2h_ring_upd_support) { - wr = flow_ring->wr; - } else { - dhd_bus_cmn_readshared(dhd->bus, &wr, RING_WR_UPD, flow_ring->idx); - } - if (dhd->dma_h2d_ring_upd_support) { - rd = flow_ring->rd; - } else { - dhd_bus_cmn_readshared(dhd->bus, &rd, RING_RD_UPD, flow_ring->idx); - } - ret = (wr == rd) ? TRUE : FALSE; - return ret; -} -uint16 -dhd_prot_get_h2d_max_txpost(dhd_pub_t *dhd) -{ - return (uint16)h2d_max_txpost; -} -void -dhd_prot_set_h2d_max_txpost(dhd_pub_t *dhd, uint16 max_txpost) -{ - h2d_max_txpost = max_txpost; -} -/** - * dhd_prot_d2h_sync_livelock - when the host determines that a DMA transfer has - * not completed, a livelock condition occurs. Host will avert this livelock by - * dropping this message and moving to the next. This dropped message can lead - * to a packet leak, or even something disastrous in the case the dropped - * message happens to be a control response. - * Here we will log this condition. One may choose to reboot the dongle. - * - */ -static void -dhd_prot_d2h_sync_livelock(dhd_pub_t *dhd, uint32 msg_seqnum, msgbuf_ring_t *ring, uint32 tries, - volatile uchar *msg, int msglen) -{ - uint32 ring_seqnum = ring->seqnum; - DHD_ERROR(( - "LIVELOCK DHD<%p> ring<%s> msg_seqnum<%u> ring_seqnum<%u:%u> tries<%u> max<%lu>" - " tot<%lu> dma_buf va<%p> msg<%p> curr_rd<%d>\n", - dhd, ring->name, msg_seqnum, ring_seqnum, ring_seqnum% D2H_EPOCH_MODULO, tries, - dhd->prot->d2h_sync_wait_max, dhd->prot->d2h_sync_wait_tot, - ring->dma_buf.va, msg, ring->curr_rd)); - prhex("D2H MsgBuf Failure", (volatile uchar *)msg, msglen); - - dhd_bus_dump_console_buffer(dhd->bus); - dhd_prot_debug_info_print(dhd); - -#ifdef DHD_FW_COREDUMP - if (dhd->memdump_enabled) { - /* collect core dump */ - dhd->memdump_type = DUMP_TYPE_BY_LIVELOCK; - dhd_bus_mem_dump(dhd); - } -#endif /* DHD_FW_COREDUMP */ - - dhd_schedule_reset(dhd); - -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - dhd->bus->no_cfg_restore = 1; -#endif /* CONFIG_ARCH_MSM */ - dhd->hang_reason = HANG_REASON_MSGBUF_LIVELOCK; - dhd_os_send_hang_message(dhd); -#endif /* SUPPORT_LINKDOWN_RECOVERY */ -} - -/** - * dhd_prot_d2h_sync_seqnum - Sync on a D2H DMA completion using the SEQNUM - * mode. Sequence number is always in the last word of a message. - */ -static uint8 BCMFASTPATH -dhd_prot_d2h_sync_seqnum(dhd_pub_t *dhd, msgbuf_ring_t *ring, - volatile cmn_msg_hdr_t *msg, int msglen) -{ - uint32 tries; - uint32 ring_seqnum = ring->seqnum % D2H_EPOCH_MODULO; - int num_words = msglen / sizeof(uint32); /* num of 32bit words */ - volatile uint32 *marker = (volatile uint32 *)msg + (num_words - 1); /* last word */ - dhd_prot_t *prot = dhd->prot; - uint32 msg_seqnum; - uint32 step = 0; - uint32 delay = PCIE_D2H_SYNC_DELAY; - uint32 total_tries = 0; - - ASSERT(msglen == ring->item_len); - - BCM_REFERENCE(delay); - /* - * For retries we have to make some sort of stepper algorithm. - * We see that every time when the Dongle comes out of the D3 - * Cold state, the first D2H mem2mem DMA takes more time to - * complete, leading to livelock issues. - * - * Case 1 - Apart from Host CPU some other bus master is - * accessing the DDR port, probably page close to the ring - * so, PCIE does not get a change to update the memory. - * Solution - Increase the number of tries. - * - * Case 2 - The 50usec delay given by the Host CPU is not - * sufficient for the PCIe RC to start its work. - * In this case the breathing time of 50usec given by - * the Host CPU is not sufficient. - * Solution: Increase the delay in a stepper fashion. - * This is done to ensure that there are no - * unwanted extra delay introdcued in normal conditions. - */ - for (step = 1; step <= PCIE_D2H_SYNC_NUM_OF_STEPS; step++) { - for (tries = 0; tries < PCIE_D2H_SYNC_WAIT_TRIES; tries++) { - msg_seqnum = *marker; - if (ltoh32(msg_seqnum) == ring_seqnum) { /* dma upto last word done */ - ring->seqnum++; /* next expected sequence number */ - goto dma_completed; - } - - total_tries = ((step-1) * PCIE_D2H_SYNC_WAIT_TRIES) + tries; - - if (total_tries > prot->d2h_sync_wait_max) - prot->d2h_sync_wait_max = total_tries; - - OSL_CACHE_INV(msg, msglen); /* invalidate and try again */ - OSL_CPU_RELAX(); /* CPU relax for msg_seqnum value to update */ - OSL_DELAY(delay * step); /* Add stepper delay */ - - } /* for PCIE_D2H_SYNC_WAIT_TRIES */ - } /* for PCIE_D2H_SYNC_NUM_OF_STEPS */ - - dhd_prot_d2h_sync_livelock(dhd, msg_seqnum, ring, total_tries, - (volatile uchar *) msg, msglen); - - ring->seqnum++; /* skip this message ... leak of a pktid */ - return MSG_TYPE_INVALID; /* invalid msg_type 0 -> noop callback */ - -dma_completed: - - prot->d2h_sync_wait_tot += tries; - return msg->msg_type; -} - -/** - * dhd_prot_d2h_sync_xorcsum - Sync on a D2H DMA completion using the XORCSUM - * mode. The xorcsum is placed in the last word of a message. Dongle will also - * place a seqnum in the epoch field of the cmn_msg_hdr. - */ -static uint8 BCMFASTPATH -dhd_prot_d2h_sync_xorcsum(dhd_pub_t *dhd, msgbuf_ring_t *ring, - volatile cmn_msg_hdr_t *msg, int msglen) -{ - uint32 tries; - uint32 prot_checksum = 0; /* computed checksum */ - int num_words = msglen / sizeof(uint32); /* num of 32bit words */ - uint8 ring_seqnum = ring->seqnum % D2H_EPOCH_MODULO; - dhd_prot_t *prot = dhd->prot; - uint32 step = 0; - uint32 delay = PCIE_D2H_SYNC_DELAY; - uint32 total_tries = 0; - - ASSERT(msglen == ring->item_len); - - BCM_REFERENCE(delay); - /* - * For retries we have to make some sort of stepper algorithm. - * We see that every time when the Dongle comes out of the D3 - * Cold state, the first D2H mem2mem DMA takes more time to - * complete, leading to livelock issues. - * - * Case 1 - Apart from Host CPU some other bus master is - * accessing the DDR port, probably page close to the ring - * so, PCIE does not get a change to update the memory. - * Solution - Increase the number of tries. - * - * Case 2 - The 50usec delay given by the Host CPU is not - * sufficient for the PCIe RC to start its work. - * In this case the breathing time of 50usec given by - * the Host CPU is not sufficient. - * Solution: Increase the delay in a stepper fashion. - * This is done to ensure that there are no - * unwanted extra delay introdcued in normal conditions. - */ - for (step = 1; step <= PCIE_D2H_SYNC_NUM_OF_STEPS; step++) { - for (tries = 0; tries < PCIE_D2H_SYNC_WAIT_TRIES; tries++) { - prot_checksum = bcm_compute_xor32((volatile uint32 *)msg, num_words); - if (prot_checksum == 0U) { /* checksum is OK */ - if (msg->epoch == ring_seqnum) { - ring->seqnum++; /* next expected sequence number */ - goto dma_completed; - } - } - - total_tries = ((step-1) * PCIE_D2H_SYNC_WAIT_TRIES) + tries; - - if (total_tries > prot->d2h_sync_wait_max) - prot->d2h_sync_wait_max = total_tries; - - OSL_CACHE_INV(msg, msglen); /* invalidate and try again */ - OSL_CPU_RELAX(); /* CPU relax for msg_seqnum value to update */ - OSL_DELAY(delay * step); /* Add stepper delay */ - - } /* for PCIE_D2H_SYNC_WAIT_TRIES */ - } /* for PCIE_D2H_SYNC_NUM_OF_STEPS */ - - DHD_ERROR(("%s: prot_checksum = 0x%x\n", __FUNCTION__, prot_checksum)); - dhd_prot_d2h_sync_livelock(dhd, msg->epoch, ring, total_tries, - (volatile uchar *) msg, msglen); - - ring->seqnum++; /* skip this message ... leak of a pktid */ - return MSG_TYPE_INVALID; /* invalid msg_type 0 -> noop callback */ - -dma_completed: - - prot->d2h_sync_wait_tot += tries; - return msg->msg_type; -} - -/** - * dhd_prot_d2h_sync_none - Dongle ensure that the DMA will complete and host - * need to try to sync. This noop sync handler will be bound when the dongle - * advertises that neither the SEQNUM nor XORCSUM mode of DMA sync is required. - */ -static uint8 BCMFASTPATH -dhd_prot_d2h_sync_none(dhd_pub_t *dhd, msgbuf_ring_t *ring, - volatile cmn_msg_hdr_t *msg, int msglen) -{ - return msg->msg_type; -} - -INLINE void -dhd_wakeup_ioctl_event(dhd_pub_t *dhd, dhd_ioctl_recieved_status_t reason) -{ - /* To synchronize with the previous memory operations call wmb() */ - OSL_SMP_WMB(); - dhd->prot->ioctl_received = reason; - /* Call another wmb() to make sure before waking up the other event value gets updated */ - OSL_SMP_WMB(); - dhd_os_ioctl_resp_wake(dhd); -} - -/** - * dhd_prot_d2h_sync_init - Setup the host side DMA sync mode based on what - * dongle advertizes. - */ -static void -dhd_prot_d2h_sync_init(dhd_pub_t *dhd) -{ - dhd_prot_t *prot = dhd->prot; - prot->d2h_sync_wait_max = 0UL; - prot->d2h_sync_wait_tot = 0UL; - - prot->d2hring_ctrl_cpln.seqnum = D2H_EPOCH_INIT_VAL; - prot->d2hring_ctrl_cpln.current_phase = BCMPCIE_CMNHDR_PHASE_BIT_INIT; - - prot->d2hring_tx_cpln.seqnum = D2H_EPOCH_INIT_VAL; - prot->d2hring_tx_cpln.current_phase = BCMPCIE_CMNHDR_PHASE_BIT_INIT; - - prot->d2hring_rx_cpln.seqnum = D2H_EPOCH_INIT_VAL; - prot->d2hring_rx_cpln.current_phase = BCMPCIE_CMNHDR_PHASE_BIT_INIT; - - if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_SEQNUM) { - prot->d2h_sync_cb = dhd_prot_d2h_sync_seqnum; - DHD_ERROR(("%s(): D2H sync mechanism is SEQNUM \r\n", __FUNCTION__)); - } else if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_XORCSUM) { - prot->d2h_sync_cb = dhd_prot_d2h_sync_xorcsum; - DHD_ERROR(("%s(): D2H sync mechanism is XORCSUM \r\n", __FUNCTION__)); - } else { - prot->d2h_sync_cb = dhd_prot_d2h_sync_none; - DHD_ERROR(("%s(): D2H sync mechanism is NONE \r\n", __FUNCTION__)); - } -} - -/** - * dhd_prot_h2d_sync_init - Per H2D common ring, setup the msgbuf ring seqnum - */ -static void -dhd_prot_h2d_sync_init(dhd_pub_t *dhd) -{ - dhd_prot_t *prot = dhd->prot; - prot->h2dring_rxp_subn.seqnum = H2D_EPOCH_INIT_VAL; - prot->h2dring_rxp_subn.current_phase = 0; - - prot->h2dring_ctrl_subn.seqnum = H2D_EPOCH_INIT_VAL; - prot->h2dring_ctrl_subn.current_phase = 0; -} - -/* +----------------- End of PCIE DHD H2D DMA SYNC ------------------------+ */ - - -/* - * +---------------------------------------------------------------------------+ - * PCIE DMA-able buffer. Sets up a dhd_dma_buf_t object, which includes the - * virtual and physical address, the buffer lenght and the DMA handler. - * A secdma handler is also included in the dhd_dma_buf object. - * +---------------------------------------------------------------------------+ - */ - -static INLINE void -dhd_base_addr_htolpa(sh_addr_t *base_addr, dmaaddr_t pa) -{ - base_addr->low_addr = htol32(PHYSADDRLO(pa)); - base_addr->high_addr = htol32(PHYSADDRHI(pa)); -} - - -/** - * dhd_dma_buf_audit - Any audits on a DHD DMA Buffer. - */ -static int -dhd_dma_buf_audit(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf) -{ - uint32 pa_lowaddr, end; /* dongle uses 32bit ptr arithmetic */ - ASSERT(dma_buf); - pa_lowaddr = PHYSADDRLO(dma_buf->pa); - ASSERT(PHYSADDRLO(dma_buf->pa) || PHYSADDRHI(dma_buf->pa)); - ASSERT(ISALIGNED(pa_lowaddr, DMA_ALIGN_LEN)); - ASSERT(dma_buf->len != 0); - - /* test 32bit offset arithmetic over dma buffer for loss of carry-over */ - end = (pa_lowaddr + dma_buf->len); /* end address */ - - if ((end & 0xFFFFFFFF) < (pa_lowaddr & 0xFFFFFFFF)) { /* exclude carryover */ - DHD_ERROR(("%s: dma_buf %x len %d spans dongle 32bit ptr arithmetic\n", - __FUNCTION__, pa_lowaddr, dma_buf->len)); - return BCME_ERROR; - } - - return BCME_OK; -} - -/** - * dhd_dma_buf_alloc - Allocate a cache coherent DMA-able buffer. - * returns BCME_OK=0 on success - * returns non-zero negative error value on failure. - */ -static int -dhd_dma_buf_alloc(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf, uint32 buf_len) -{ - uint32 dma_pad = 0; - osl_t *osh = dhd->osh; - uint16 dma_align = DMA_ALIGN_LEN; - - - ASSERT(dma_buf != NULL); - ASSERT(dma_buf->va == NULL); - ASSERT(dma_buf->len == 0); - - /* Pad the buffer length by one extra cacheline size. - * Required for D2H direction. - */ - dma_pad = (buf_len % DHD_DMA_PAD) ? DHD_DMA_PAD : 0; - dma_buf->va = DMA_ALLOC_CONSISTENT(osh, buf_len + dma_pad, - dma_align, &dma_buf->_alloced, &dma_buf->pa, &dma_buf->dmah); - - if (dma_buf->va == NULL) { - DHD_ERROR(("%s: buf_len %d, no memory available\n", - __FUNCTION__, buf_len)); - return BCME_NOMEM; - } - - dma_buf->len = buf_len; /* not including padded len */ - - if (dhd_dma_buf_audit(dhd, dma_buf) != BCME_OK) { /* audit dma buf */ - dhd_dma_buf_free(dhd, dma_buf); - return BCME_ERROR; - } - - dhd_dma_buf_reset(dhd, dma_buf); /* zero out and cache flush */ - - return BCME_OK; -} - -/** - * dhd_dma_buf_reset - Reset a cache coherent DMA-able buffer. - */ -static void -dhd_dma_buf_reset(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf) -{ - if ((dma_buf == NULL) || (dma_buf->va == NULL)) - return; - - (void)dhd_dma_buf_audit(dhd, dma_buf); - - /* Zero out the entire buffer and cache flush */ - memset((void*)dma_buf->va, 0, dma_buf->len); - OSL_CACHE_FLUSH((void *)dma_buf->va, dma_buf->len); -} - -/** - * dhd_dma_buf_free - Free a DMA-able buffer that was previously allocated using - * dhd_dma_buf_alloc(). - */ -static void -dhd_dma_buf_free(dhd_pub_t *dhd, dhd_dma_buf_t *dma_buf) -{ - osl_t *osh = dhd->osh; - - ASSERT(dma_buf); - - if (dma_buf->va == NULL) - return; /* Allow for free invocation, when alloc failed */ - - /* DEBUG: dhd_dma_buf_reset(dhd, dma_buf) */ - (void)dhd_dma_buf_audit(dhd, dma_buf); - - /* dma buffer may have been padded at allocation */ - DMA_FREE_CONSISTENT(osh, dma_buf->va, dma_buf->_alloced, - dma_buf->pa, dma_buf->dmah); - - memset(dma_buf, 0, sizeof(dhd_dma_buf_t)); -} - -/** - * dhd_dma_buf_init - Initialize a dhd_dma_buf with speicifed values. - * Do not use dhd_dma_buf_init to zero out a dhd_dma_buf_t object. Use memset 0. - */ -void -dhd_dma_buf_init(dhd_pub_t *dhd, void *dhd_dma_buf, - void *va, uint32 len, dmaaddr_t pa, void *dmah, void *secdma) -{ - dhd_dma_buf_t *dma_buf; - ASSERT(dhd_dma_buf); - dma_buf = (dhd_dma_buf_t *)dhd_dma_buf; - dma_buf->va = va; - dma_buf->len = len; - dma_buf->pa = pa; - dma_buf->dmah = dmah; - dma_buf->secdma = secdma; - - /* Audit user defined configuration */ - (void)dhd_dma_buf_audit(dhd, dma_buf); -} - -/* +------------------ End of PCIE DHD DMA BUF ADT ------------------------+ */ - -/* - * +---------------------------------------------------------------------------+ - * PktId Map: Provides a native packet pointer to unique 32bit PktId mapping. - * Main purpose is to save memory on the dongle, has other purposes as well. - * The packet id map, also includes storage for some packet parameters that - * may be saved. A native packet pointer along with the parameters may be saved - * and a unique 32bit pkt id will be returned. Later, the saved packet pointer - * and the metadata may be retrieved using the previously allocated packet id. - * +---------------------------------------------------------------------------+ - */ -#define DHD_PCIE_PKTID -#define MAX_CTRL_PKTID (1024) /* Maximum number of pktids supported */ -#define MAX_RX_PKTID (1024) -#define MAX_TX_PKTID (3072 * 2) - -/* On Router, the pktptr serves as a pktid. */ - - -#if defined(PROP_TXSTATUS) && !defined(DHD_PCIE_PKTID) -#error "PKTIDMAP must be supported with PROP_TXSTATUS/WLFC" -#endif - -/* Enum for marking the buffer color based on usage */ -typedef enum dhd_pkttype { - PKTTYPE_DATA_TX = 0, - PKTTYPE_DATA_RX, - PKTTYPE_IOCTL_RX, - PKTTYPE_EVENT_RX, - PKTTYPE_INFO_RX, - /* dhd_prot_pkt_free no check, if pktid reserved and no space avail case */ - PKTTYPE_NO_CHECK, - PKTTYPE_TSBUF_RX -} dhd_pkttype_t; - -#define DHD_PKTID_INVALID (0U) -#define DHD_IOCTL_REQ_PKTID (0xFFFE) -#define DHD_FAKE_PKTID (0xFACE) -#define DHD_H2D_DBGRING_REQ_PKTID 0xFFFD -#define DHD_D2H_DBGRING_REQ_PKTID 0xFFFC -#define DHD_H2D_HOSTTS_REQ_PKTID 0xFFFB - -#define IS_FLOWRING(ring) \ - ((strncmp(ring->name, "h2dflr", sizeof("h2dflr"))) == (0)) - -typedef void * dhd_pktid_map_handle_t; /* opaque handle to a pktid map */ - -/* Construct a packet id mapping table, returning an opaque map handle */ -static dhd_pktid_map_handle_t *dhd_pktid_map_init(dhd_pub_t *dhd, uint32 num_items); - -/* Destroy a packet id mapping table, freeing all packets active in the table */ -static void dhd_pktid_map_fini(dhd_pub_t *dhd, dhd_pktid_map_handle_t *map); - -#define DHD_NATIVE_TO_PKTID_INIT(dhd, items) dhd_pktid_map_init((dhd), (items)) -#define DHD_NATIVE_TO_PKTID_RESET(dhd, map) dhd_pktid_map_reset((dhd), (map)) -#define DHD_NATIVE_TO_PKTID_FINI(dhd, map) dhd_pktid_map_fini((dhd), (map)) -#define DHD_NATIVE_TO_PKTID_FINI_IOCTL(osh, map) dhd_pktid_map_fini_ioctl((osh), (map)) - -#ifdef MACOSX_DHD -#undef DHD_PCIE_PKTID -#define DHD_PCIE_PKTID 1 -#endif /* MACOSX_DHD */ - -#if defined(DHD_PCIE_PKTID) -#if defined(MACOSX_DHD) || defined(DHD_EFI) -#define IOCTLRESP_USE_CONSTMEM -static void free_ioctl_return_buffer(dhd_pub_t *dhd, dhd_dma_buf_t *retbuf); -static int alloc_ioctl_return_buffer(dhd_pub_t *dhd, dhd_dma_buf_t *retbuf); -#endif - -/* Determine number of pktids that are available */ -static INLINE uint32 dhd_pktid_map_avail_cnt(dhd_pktid_map_handle_t *handle); - -/* Allocate a unique pktid against which a pkt and some metadata is saved */ -static INLINE uint32 dhd_pktid_map_reserve(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, - void *pkt, dhd_pkttype_t pkttype); -static INLINE void dhd_pktid_map_save(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, - void *pkt, uint32 nkey, dmaaddr_t pa, uint32 len, uint8 dma, - void *dmah, void *secdma, dhd_pkttype_t pkttype); -static uint32 dhd_pktid_map_alloc(dhd_pub_t *dhd, dhd_pktid_map_handle_t *map, - void *pkt, dmaaddr_t pa, uint32 len, uint8 dma, - void *dmah, void *secdma, dhd_pkttype_t pkttype); - -/* Return an allocated pktid, retrieving previously saved pkt and metadata */ -static void *dhd_pktid_map_free(dhd_pub_t *dhd, dhd_pktid_map_handle_t *map, - uint32 id, dmaaddr_t *pa, uint32 *len, void **dmah, - void **secdma, dhd_pkttype_t pkttype, bool rsv_locker); - -/* - * DHD_PKTID_AUDIT_ENABLED: Audit of PktIds in DHD for duplicate alloc and frees - * - * DHD_PKTID_AUDIT_MAP: Audit the LIFO or FIFO PktIdMap allocator - * DHD_PKTID_AUDIT_RING: Audit the pktid during producer/consumer ring operation - * - * CAUTION: When DHD_PKTID_AUDIT_ENABLED is defined, - * either DHD_PKTID_AUDIT_MAP or DHD_PKTID_AUDIT_RING may be selected. - */ -#if defined(DHD_PKTID_AUDIT_ENABLED) -#define USE_DHD_PKTID_AUDIT_LOCK 1 -/* Audit the pktidmap allocator */ -/* #define DHD_PKTID_AUDIT_MAP */ - -/* Audit the pktid during production/consumption of workitems */ -#define DHD_PKTID_AUDIT_RING - -#if defined(DHD_PKTID_AUDIT_MAP) && defined(DHD_PKTID_AUDIT_RING) -#error "May only enabled audit of MAP or RING, at a time." -#endif /* DHD_PKTID_AUDIT_MAP && DHD_PKTID_AUDIT_RING */ - -#define DHD_DUPLICATE_ALLOC 1 -#define DHD_DUPLICATE_FREE 2 -#define DHD_TEST_IS_ALLOC 3 -#define DHD_TEST_IS_FREE 4 - -#ifdef USE_DHD_PKTID_AUDIT_LOCK -#define DHD_PKTID_AUDIT_LOCK_INIT(osh) dhd_os_spin_lock_init(osh) -#define DHD_PKTID_AUDIT_LOCK_DEINIT(osh, lock) dhd_os_spin_lock_deinit(osh, lock) -#define DHD_PKTID_AUDIT_LOCK(lock) dhd_os_spin_lock(lock) -#define DHD_PKTID_AUDIT_UNLOCK(lock, flags) dhd_os_spin_unlock(lock, flags) -#else -#define DHD_PKTID_AUDIT_LOCK_INIT(osh) (void *)(1) -#define DHD_PKTID_AUDIT_LOCK_DEINIT(osh, lock) do { /* noop */ } while (0) -#define DHD_PKTID_AUDIT_LOCK(lock) 0 -#define DHD_PKTID_AUDIT_UNLOCK(lock, flags) do { /* noop */ } while (0) -#endif /* !USE_DHD_PKTID_AUDIT_LOCK */ - -#endif /* DHD_PKTID_AUDIT_ENABLED */ - -/* #define USE_DHD_PKTID_LOCK 1 */ - -#ifdef USE_DHD_PKTID_LOCK -#define DHD_PKTID_LOCK_INIT(osh) dhd_os_spin_lock_init(osh) -#define DHD_PKTID_LOCK_DEINIT(osh, lock) dhd_os_spin_lock_deinit(osh, lock) -#define DHD_PKTID_LOCK(lock) dhd_os_spin_lock(lock) -#define DHD_PKTID_UNLOCK(lock, flags) dhd_os_spin_unlock(lock, flags) -#else -#define DHD_PKTID_LOCK_INIT(osh) (void *)(1) -#define DHD_PKTID_LOCK_DEINIT(osh, lock) \ - do { \ - BCM_REFERENCE(osh); \ - BCM_REFERENCE(lock); \ - } while (0) -#define DHD_PKTID_LOCK(lock) 0 -#define DHD_PKTID_UNLOCK(lock, flags) \ - do { \ - BCM_REFERENCE(lock); \ - BCM_REFERENCE(flags); \ - } while (0) -#endif /* !USE_DHD_PKTID_LOCK */ - -typedef enum dhd_locker_state { - LOCKER_IS_FREE, - LOCKER_IS_BUSY, - LOCKER_IS_RSVD -} dhd_locker_state_t; - -/* Packet metadata saved in packet id mapper */ - -typedef struct dhd_pktid_item { - dhd_locker_state_t state; /* tag a locker to be free, busy or reserved */ - uint8 dir; /* dma map direction (Tx=flush or Rx=invalidate) */ - dhd_pkttype_t pkttype; /* pktlists are maintained based on pkttype */ - uint16 len; /* length of mapped packet's buffer */ - void *pkt; /* opaque native pointer to a packet */ - dmaaddr_t pa; /* physical address of mapped packet's buffer */ - void *dmah; /* handle to OS specific DMA map */ - void *secdma; -} dhd_pktid_item_t; - -typedef uint32 dhd_pktid_key_t; - -typedef struct dhd_pktid_map { - uint32 items; /* total items in map */ - uint32 avail; /* total available items */ - int failures; /* lockers unavailable count */ -#if defined(DHD_PKTID_AUDIT_ENABLED) - void *pktid_audit_lock; - struct bcm_mwbmap *pktid_audit; /* multi word bitmap based audit */ -#endif /* DHD_PKTID_AUDIT_ENABLED */ - dhd_pktid_key_t *keys; /* map_items +1 unique pkt ids */ - dhd_pktid_item_t lockers[0]; /* metadata storage */ -} dhd_pktid_map_t; - -/* - * PktId (Locker) #0 is never allocated and is considered invalid. - * - * On request for a pktid, a value DHD_PKTID_INVALID must be treated as a - * depleted pktid pool and must not be used by the caller. - * - * Likewise, a caller must never free a pktid of value DHD_PKTID_INVALID. - */ - -#define DHD_PKTID_FREE_LOCKER (FALSE) -#define DHD_PKTID_RSV_LOCKER (TRUE) - -#define DHD_PKTID_ITEM_SZ (sizeof(dhd_pktid_item_t)) -#define DHD_PKIDMAP_ITEMS(items) (items) -#define DHD_PKTID_MAP_SZ(items) (sizeof(dhd_pktid_map_t) + \ - (DHD_PKTID_ITEM_SZ * ((items) + 1))) -#define DHD_PKTIDMAP_KEYS_SZ(items) (sizeof(dhd_pktid_key_t) * ((items) + 1)) - -#define DHD_NATIVE_TO_PKTID_RESET_IOCTL(dhd, map) dhd_pktid_map_reset_ioctl((dhd), (map)) - -/* Convert a packet to a pktid, and save pkt pointer in busy locker */ -#define DHD_NATIVE_TO_PKTID_RSV(dhd, map, pkt, pkttype) \ - dhd_pktid_map_reserve((dhd), (map), (pkt), (pkttype)) -/* Reuse a previously reserved locker to save packet params */ -#define DHD_NATIVE_TO_PKTID_SAVE(dhd, map, pkt, nkey, pa, len, dir, dmah, secdma, pkttype) \ - dhd_pktid_map_save((dhd), (map), (void *)(pkt), (nkey), (pa), (uint32)(len), \ - (uint8)(dir), (void *)(dmah), (void *)(secdma), \ - (dhd_pkttype_t)(pkttype)) -/* Convert a packet to a pktid, and save packet params in locker */ -#define DHD_NATIVE_TO_PKTID(dhd, map, pkt, pa, len, dir, dmah, secdma, pkttype) \ - dhd_pktid_map_alloc((dhd), (map), (void *)(pkt), (pa), (uint32)(len), \ - (uint8)(dir), (void *)(dmah), (void *)(secdma), \ - (dhd_pkttype_t)(pkttype)) - -/* Convert pktid to a packet, and free the locker */ -#define DHD_PKTID_TO_NATIVE(dhd, map, pktid, pa, len, dmah, secdma, pkttype) \ - dhd_pktid_map_free((dhd), (map), (uint32)(pktid), \ - (dmaaddr_t *)&(pa), (uint32 *)&(len), (void **)&(dmah), \ - (void **)&(secdma), (dhd_pkttype_t)(pkttype), DHD_PKTID_FREE_LOCKER) - -/* Convert the pktid to a packet, empty locker, but keep it reserved */ -#define DHD_PKTID_TO_NATIVE_RSV(dhd, map, pktid, pa, len, dmah, secdma, pkttype) \ - dhd_pktid_map_free((dhd), (map), (uint32)(pktid), \ - (dmaaddr_t *)&(pa), (uint32 *)&(len), (void **)&(dmah), \ - (void **)&(secdma), (dhd_pkttype_t)(pkttype), DHD_PKTID_RSV_LOCKER) - -#define DHD_PKTID_AVAIL(map) dhd_pktid_map_avail_cnt(map) - -#if defined(DHD_PKTID_AUDIT_ENABLED) -/** -* dhd_pktid_audit - Use the mwbmap to audit validity of a pktid. -*/ -static int -dhd_pktid_audit(dhd_pub_t *dhd, dhd_pktid_map_t *pktid_map, uint32 pktid, - const int test_for, const char *errmsg) -{ -#define DHD_PKT_AUDIT_STR "ERROR: %16s Host PktId Audit: " - struct bcm_mwbmap *handle; - uint32 flags; - bool ignore_audit; - - if (pktid_map == (dhd_pktid_map_t *)NULL) { - DHD_ERROR((DHD_PKT_AUDIT_STR "Pkt id map NULL\n", errmsg)); - return BCME_OK; - } - - flags = DHD_PKTID_AUDIT_LOCK(pktid_map->pktid_audit_lock); - - handle = pktid_map->pktid_audit; - if (handle == (struct bcm_mwbmap *)NULL) { - DHD_ERROR((DHD_PKT_AUDIT_STR "Handle NULL\n", errmsg)); - DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); - return BCME_OK; - } - - /* Exclude special pktids from audit */ - ignore_audit = (pktid == DHD_IOCTL_REQ_PKTID) | (pktid == DHD_FAKE_PKTID); - if (ignore_audit) { - DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); - return BCME_OK; - } - - if ((pktid == DHD_PKTID_INVALID) || (pktid > pktid_map->items)) { - DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> invalid\n", errmsg, pktid)); - /* lock is released in "error" */ - goto error; - } - - /* Perform audit */ - switch (test_for) { - case DHD_DUPLICATE_ALLOC: - if (!bcm_mwbmap_isfree(handle, pktid)) { - DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> alloc duplicate\n", - errmsg, pktid)); - goto error; - } - bcm_mwbmap_force(handle, pktid); - break; - - case DHD_DUPLICATE_FREE: - if (bcm_mwbmap_isfree(handle, pktid)) { - DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> free duplicate\n", - errmsg, pktid)); - goto error; - } - bcm_mwbmap_free(handle, pktid); - break; - - case DHD_TEST_IS_ALLOC: - if (bcm_mwbmap_isfree(handle, pktid)) { - DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> is not allocated\n", - errmsg, pktid)); - goto error; - } - break; - - case DHD_TEST_IS_FREE: - if (!bcm_mwbmap_isfree(handle, pktid)) { - DHD_ERROR((DHD_PKT_AUDIT_STR "PktId<%d> is not free", - errmsg, pktid)); - goto error; - } - break; - - default: - goto error; - } - - DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); - return BCME_OK; - -error: - - DHD_PKTID_AUDIT_UNLOCK(pktid_map->pktid_audit_lock, flags); - /* May insert any trap mechanism here ! */ - dhd_pktid_error_handler(dhd); - - return BCME_ERROR; -} - -#define DHD_PKTID_AUDIT(dhdp, map, pktid, test_for) \ - dhd_pktid_audit((dhdp), (dhd_pktid_map_t *)(map), (pktid), (test_for), __FUNCTION__) - -static int -dhd_pktid_audit_ring_debug(dhd_pub_t *dhdp, dhd_pktid_map_t *map, uint32 pktid, - const int test_for, void *msg, uint32 msg_len, const char * func) -{ - int ret = 0; - ret = DHD_PKTID_AUDIT(dhdp, map, pktid, test_for); - if (ret == BCME_ERROR) { - prhex(func, (uchar *)msg, msg_len); - } - return ret; -} -#define DHD_PKTID_AUDIT_RING_DEBUG(dhdp, map, pktid, test_for, msg, msg_len) \ - dhd_pktid_audit_ring_debug((dhdp), (dhd_pktid_map_t *)(map), \ - (pktid), (test_for), msg, msg_len, __FUNCTION__) - -#endif /* DHD_PKTID_AUDIT_ENABLED */ - - -/** - * +---------------------------------------------------------------------------+ - * Packet to Packet Id mapper using a <numbered_key, locker> paradigm. - * - * dhd_pktid_map manages a set of unique Packet Ids range[1..MAX_xxx_PKTID]. - * - * dhd_pktid_map_alloc() may be used to save some packet metadata, and a unique - * packet id is returned. This unique packet id may be used to retrieve the - * previously saved packet metadata, using dhd_pktid_map_free(). On invocation - * of dhd_pktid_map_free(), the unique packet id is essentially freed. A - * subsequent call to dhd_pktid_map_alloc() may reuse this packet id. - * - * Implementation Note: - * Convert this into a <key,locker> abstraction and place into bcmutils ! - * Locker abstraction should treat contents as opaque storage, and a - * callback should be registered to handle busy lockers on destructor. - * - * +---------------------------------------------------------------------------+ - */ - -/** Allocate and initialize a mapper of num_items <numbered_key, locker> */ - -static dhd_pktid_map_handle_t * -dhd_pktid_map_init(dhd_pub_t *dhd, uint32 num_items) -{ - void* osh; - uint32 nkey; - dhd_pktid_map_t *map; - uint32 dhd_pktid_map_sz; - uint32 map_items; - uint32 map_keys_sz; - osh = dhd->osh; - - dhd_pktid_map_sz = DHD_PKTID_MAP_SZ(num_items); - - map = (dhd_pktid_map_t *)VMALLOC(osh, dhd_pktid_map_sz); - if (map == NULL) { - DHD_ERROR(("%s:%d: MALLOC failed for size %d\n", - __FUNCTION__, __LINE__, dhd_pktid_map_sz)); - return (dhd_pktid_map_handle_t *)NULL; - } - - /* Initialize the lock that protects this structure */ - map->items = num_items; - map->avail = num_items; - - map_items = DHD_PKIDMAP_ITEMS(map->items); - - map_keys_sz = DHD_PKTIDMAP_KEYS_SZ(map->items); - map->keys = (dhd_pktid_key_t *)MALLOC(osh, map_keys_sz); - if (map->keys == NULL) { - DHD_ERROR(("%s:%d: MALLOC failed for map->keys size %d\n", - __FUNCTION__, __LINE__, map_keys_sz)); - goto error; - } - -#if defined(DHD_PKTID_AUDIT_ENABLED) - /* Incarnate a hierarchical multiword bitmap for auditing pktid allocator */ - map->pktid_audit = bcm_mwbmap_init(osh, map_items + 1); - if (map->pktid_audit == (struct bcm_mwbmap *)NULL) { - DHD_ERROR(("%s:%d: pktid_audit init failed\r\n", __FUNCTION__, __LINE__)); - goto error; - } else { - DHD_ERROR(("%s:%d: pktid_audit init succeeded %d\n", - __FUNCTION__, __LINE__, map_items + 1)); - } - map->pktid_audit_lock = DHD_PKTID_AUDIT_LOCK_INIT(osh); -#endif /* DHD_PKTID_AUDIT_ENABLED */ - - for (nkey = 1; nkey <= map_items; nkey++) { /* locker #0 is reserved */ - map->keys[nkey] = nkey; /* populate with unique keys */ - map->lockers[nkey].state = LOCKER_IS_FREE; - map->lockers[nkey].pkt = NULL; /* bzero: redundant */ - map->lockers[nkey].len = 0; - } - - /* Reserve pktid #0, i.e. DHD_PKTID_INVALID to be inuse */ - map->lockers[DHD_PKTID_INVALID].state = LOCKER_IS_BUSY; /* tag locker #0 as inuse */ - map->lockers[DHD_PKTID_INVALID].pkt = NULL; /* bzero: redundant */ - map->lockers[DHD_PKTID_INVALID].len = 0; - -#if defined(DHD_PKTID_AUDIT_ENABLED) - /* do not use dhd_pktid_audit() here, use bcm_mwbmap_force directly */ - bcm_mwbmap_force(map->pktid_audit, DHD_PKTID_INVALID); -#endif /* DHD_PKTID_AUDIT_ENABLED */ - - return (dhd_pktid_map_handle_t *)map; /* opaque handle */ - -error: - if (map) { -#if defined(DHD_PKTID_AUDIT_ENABLED) - if (map->pktid_audit != (struct bcm_mwbmap *)NULL) { - bcm_mwbmap_fini(osh, map->pktid_audit); /* Destruct pktid_audit */ - map->pktid_audit = (struct bcm_mwbmap *)NULL; - if (map->pktid_audit_lock) - DHD_PKTID_AUDIT_LOCK_DEINIT(osh, map->pktid_audit_lock); - } -#endif /* DHD_PKTID_AUDIT_ENABLED */ - if (map->keys) { - MFREE(osh, map->keys, map_keys_sz); - } - VMFREE(osh, map, dhd_pktid_map_sz); - } - return (dhd_pktid_map_handle_t *)NULL; -} - -/** - * Retrieve all allocated keys and free all <numbered_key, locker>. - * Freeing implies: unmapping the buffers and freeing the native packet - * This could have been a callback registered with the pktid mapper. - */ -static void -dhd_pktid_map_reset(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle) -{ - void *osh; - uint32 nkey; - dhd_pktid_map_t *map; - dhd_pktid_item_t *locker; - uint32 map_items; - uint32 flags; - bool data_tx = FALSE; - - map = (dhd_pktid_map_t *)handle; - DHD_GENERAL_LOCK(dhd, flags); - osh = dhd->osh; - - map_items = DHD_PKIDMAP_ITEMS(map->items); - /* skip reserved KEY #0, and start from 1 */ - - for (nkey = 1; nkey <= map_items; nkey++) { - if (map->lockers[nkey].state == LOCKER_IS_BUSY) { - locker = &map->lockers[nkey]; - locker->state = LOCKER_IS_FREE; - data_tx = (locker->pkttype == PKTTYPE_DATA_TX); - if (data_tx) { - dhd->prot->active_tx_count--; - } - -#ifdef DHD_PKTID_AUDIT_RING - DHD_PKTID_AUDIT(dhd, map, nkey, DHD_DUPLICATE_FREE); /* duplicate frees */ -#endif /* DHD_PKTID_AUDIT_RING */ - - { - if (SECURE_DMA_ENAB(dhd->osh)) - SECURE_DMA_UNMAP(osh, locker->pa, - locker->len, locker->dir, 0, - locker->dmah, locker->secdma, 0); - else - DMA_UNMAP(osh, locker->pa, locker->len, - locker->dir, 0, locker->dmah); - } - dhd_prot_packet_free(dhd, (ulong*)locker->pkt, - locker->pkttype, data_tx); - } - else { -#ifdef DHD_PKTID_AUDIT_RING - DHD_PKTID_AUDIT(dhd, map, nkey, DHD_TEST_IS_FREE); -#endif /* DHD_PKTID_AUDIT_RING */ - } - map->keys[nkey] = nkey; /* populate with unique keys */ - } - - map->avail = map_items; - memset(&map->lockers[1], 0, sizeof(dhd_pktid_item_t) * map_items); - DHD_GENERAL_UNLOCK(dhd, flags); -} - -#ifdef IOCTLRESP_USE_CONSTMEM -/** Called in detach scenario. Releasing IOCTL buffers. */ -static void -dhd_pktid_map_reset_ioctl(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle) -{ - uint32 nkey; - dhd_pktid_map_t *map; - dhd_pktid_item_t *locker; - uint32 map_items; - uint32 flags; - - map = (dhd_pktid_map_t *)handle; - DHD_GENERAL_LOCK(dhd, flags); - - map_items = DHD_PKIDMAP_ITEMS(map->items); - /* skip reserved KEY #0, and start from 1 */ - for (nkey = 1; nkey <= map_items; nkey++) { - if (map->lockers[nkey].state == LOCKER_IS_BUSY) { - dhd_dma_buf_t retbuf; - -#ifdef DHD_PKTID_AUDIT_RING - DHD_PKTID_AUDIT(dhd, map, nkey, DHD_DUPLICATE_FREE); /* duplicate frees */ -#endif /* DHD_PKTID_AUDIT_RING */ - - locker = &map->lockers[nkey]; - retbuf.va = locker->pkt; - retbuf.len = locker->len; - retbuf.pa = locker->pa; - retbuf.dmah = locker->dmah; - retbuf.secdma = locker->secdma; - - /* This could be a callback registered with dhd_pktid_map */ - DHD_GENERAL_UNLOCK(dhd, flags); - free_ioctl_return_buffer(dhd, &retbuf); - DHD_GENERAL_LOCK(dhd, flags); - } - else { -#ifdef DHD_PKTID_AUDIT_RING - DHD_PKTID_AUDIT(dhd, map, nkey, DHD_TEST_IS_FREE); -#endif /* DHD_PKTID_AUDIT_RING */ - } - map->keys[nkey] = nkey; /* populate with unique keys */ - } - - map->avail = map_items; - memset(&map->lockers[1], 0, sizeof(dhd_pktid_item_t) * map_items); - DHD_GENERAL_UNLOCK(dhd, flags); -} -#endif /* IOCTLRESP_USE_CONSTMEM */ - - -/** - * Free the pktid map. - */ -static void -dhd_pktid_map_fini(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle) -{ - dhd_pktid_map_t *map; - uint32 dhd_pktid_map_sz; - uint32 map_keys_sz; - - /* Free any pending packets */ - dhd_pktid_map_reset(dhd, handle); - - map = (dhd_pktid_map_t *)handle; - dhd_pktid_map_sz = DHD_PKTID_MAP_SZ(map->items); - map_keys_sz = DHD_PKTIDMAP_KEYS_SZ(map->items); - -#if defined(DHD_PKTID_AUDIT_ENABLED) - if (map->pktid_audit != (struct bcm_mwbmap *)NULL) { - bcm_mwbmap_fini(dhd->osh, map->pktid_audit); /* Destruct pktid_audit */ - map->pktid_audit = (struct bcm_mwbmap *)NULL; - if (map->pktid_audit_lock) { - DHD_PKTID_AUDIT_LOCK_DEINIT(dhd->osh, map->pktid_audit_lock); - } - } -#endif /* DHD_PKTID_AUDIT_ENABLED */ - MFREE(dhd->osh, map->keys, map_keys_sz); - VMFREE(dhd->osh, handle, dhd_pktid_map_sz); -} -#ifdef IOCTLRESP_USE_CONSTMEM -static void -dhd_pktid_map_fini_ioctl(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle) -{ - dhd_pktid_map_t *map; - uint32 dhd_pktid_map_sz; - uint32 map_keys_sz; - - /* Free any pending packets */ - dhd_pktid_map_reset_ioctl(dhd, handle); - - map = (dhd_pktid_map_t *)handle; - dhd_pktid_map_sz = DHD_PKTID_MAP_SZ(map->items); - map_keys_sz = DHD_PKTIDMAP_KEYS_SZ(map->items); - -#if defined(DHD_PKTID_AUDIT_ENABLED) - if (map->pktid_audit != (struct bcm_mwbmap *)NULL) { - bcm_mwbmap_fini(dhd->osh, map->pktid_audit); /* Destruct pktid_audit */ - map->pktid_audit = (struct bcm_mwbmap *)NULL; - if (map->pktid_audit_lock) { - DHD_PKTID_AUDIT_LOCK_DEINIT(dhd->osh, map->pktid_audit_lock); - } - } -#endif /* DHD_PKTID_AUDIT_ENABLED */ - - MFREE(dhd->osh, map->keys, map_keys_sz); - VMFREE(dhd->osh, handle, dhd_pktid_map_sz); -} -#endif /* IOCTLRESP_USE_CONSTMEM */ - -/** Get the pktid free count */ -static INLINE uint32 BCMFASTPATH -dhd_pktid_map_avail_cnt(dhd_pktid_map_handle_t *handle) -{ - dhd_pktid_map_t *map; - uint32 avail; - - ASSERT(handle != NULL); - map = (dhd_pktid_map_t *)handle; - - avail = map->avail; - - return avail; -} - -/** - * dhd_pktid_map_reserve - reserve a unique numbered key. Reserved locker is not - * yet populated. Invoke the pktid save api to populate the packet parameters - * into the locker. This function is not reentrant, and is the caller's - * responsibility. Caller must treat a returned value DHD_PKTID_INVALID as - * a failure case, implying a depleted pool of pktids. - */ -static INLINE uint32 -dhd_pktid_map_reserve(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, - void *pkt, dhd_pkttype_t pkttype) -{ - uint32 nkey; - dhd_pktid_map_t *map; - dhd_pktid_item_t *locker; - - ASSERT(handle != NULL); - map = (dhd_pktid_map_t *)handle; - - if ((int)(map->avail) <= 0) { /* no more pktids to allocate */ - map->failures++; - DHD_INFO(("%s:%d: failed, no free keys\n", __FUNCTION__, __LINE__)); - return DHD_PKTID_INVALID; /* failed alloc request */ - } - - ASSERT(map->avail <= map->items); - nkey = map->keys[map->avail]; /* fetch a free locker, pop stack */ - - if ((map->avail > map->items) || (nkey > map->items)) { - map->failures++; - DHD_ERROR(("%s:%d: failed to allocate a new pktid," - " map->avail<%u>, nkey<%u>, pkttype<%u>\n", - __FUNCTION__, __LINE__, map->avail, nkey, - pkttype)); - return DHD_PKTID_INVALID; /* failed alloc request */ - } - - locker = &map->lockers[nkey]; /* save packet metadata in locker */ - map->avail--; - locker->pkt = pkt; /* pkt is saved, other params not yet saved. */ - locker->len = 0; - locker->state = LOCKER_IS_BUSY; /* reserve this locker */ - - ASSERT(nkey != DHD_PKTID_INVALID); - return nkey; /* return locker's numbered key */ -} - -/* - * dhd_pktid_map_save - Save a packet's parameters into a locker - * corresponding to a previously reserved unique numbered key. - */ -static INLINE void -dhd_pktid_map_save(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, void *pkt, - uint32 nkey, dmaaddr_t pa, uint32 len, uint8 dir, void *dmah, void *secdma, - dhd_pkttype_t pkttype) -{ - dhd_pktid_map_t *map; - dhd_pktid_item_t *locker; - - ASSERT(handle != NULL); - map = (dhd_pktid_map_t *)handle; - - if ((nkey == DHD_PKTID_INVALID) || (nkey > DHD_PKIDMAP_ITEMS(map->items))) { - DHD_ERROR(("%s:%d: Error! saving invalid pktid<%u> pkttype<%u>\n", - __FUNCTION__, __LINE__, nkey, pkttype)); -#ifdef DHD_FW_COREDUMP - if (dhd->memdump_enabled) { - /* collect core dump */ - dhd->memdump_type = DUMP_TYPE_PKTID_INVALID; - dhd_bus_mem_dump(dhd); - } -#else - ASSERT(0); -#endif /* DHD_FW_COREDUMP */ - return; - } - - locker = &map->lockers[nkey]; - - ASSERT(((locker->state == LOCKER_IS_BUSY) && (locker->pkt == pkt)) || - ((locker->state == LOCKER_IS_RSVD) && (locker->pkt == NULL))); - - /* store contents in locker */ - locker->dir = dir; - locker->pa = pa; - locker->len = (uint16)len; /* 16bit len */ - locker->dmah = dmah; /* 16bit len */ - locker->secdma = secdma; - locker->pkttype = pkttype; - locker->pkt = pkt; - locker->state = LOCKER_IS_BUSY; /* make this locker busy */ -} - -/** - * dhd_pktid_map_alloc - Allocate a unique numbered key and save the packet - * contents into the corresponding locker. Return the numbered key. - */ -static uint32 BCMFASTPATH -dhd_pktid_map_alloc(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, void *pkt, - dmaaddr_t pa, uint32 len, uint8 dir, void *dmah, void *secdma, - dhd_pkttype_t pkttype) -{ - uint32 nkey; - - nkey = dhd_pktid_map_reserve(dhd, handle, pkt, pkttype); - if (nkey != DHD_PKTID_INVALID) { - dhd_pktid_map_save(dhd, handle, pkt, nkey, pa, - len, dir, dmah, secdma, pkttype); - } - - return nkey; -} - -/** - * dhd_pktid_map_free - Given a numbered key, return the locker contents. - * dhd_pktid_map_free() is not reentrant, and is the caller's responsibility. - * Caller may not free a pktid value DHD_PKTID_INVALID or an arbitrary pktid - * value. Only a previously allocated pktid may be freed. - */ -static void * BCMFASTPATH -dhd_pktid_map_free(dhd_pub_t *dhd, dhd_pktid_map_handle_t *handle, uint32 nkey, - dmaaddr_t *pa, uint32 *len, void **dmah, void **secdma, dhd_pkttype_t pkttype, - bool rsv_locker) -{ - dhd_pktid_map_t *map; - dhd_pktid_item_t *locker; - void * pkt; - unsigned long long locker_addr; - - ASSERT(handle != NULL); - - map = (dhd_pktid_map_t *)handle; - - if ((nkey == DHD_PKTID_INVALID) || (nkey > DHD_PKIDMAP_ITEMS(map->items))) { - DHD_ERROR(("%s:%d: Error! Try to free invalid pktid<%u>, pkttype<%d>\n", - __FUNCTION__, __LINE__, nkey, pkttype)); -#ifdef DHD_FW_COREDUMP - if (dhd->memdump_enabled) { - /* collect core dump */ - dhd->memdump_type = DUMP_TYPE_PKTID_INVALID; - dhd_bus_mem_dump(dhd); - } -#else - ASSERT(0); -#endif /* DHD_FW_COREDUMP */ - return NULL; - } - - locker = &map->lockers[nkey]; - -#if defined(DHD_PKTID_AUDIT_MAP) - DHD_PKTID_AUDIT(dhd, map, nkey, DHD_DUPLICATE_FREE); /* Audit duplicate FREE */ -#endif /* DHD_PKTID_AUDIT_MAP */ - - /* Debug check for cloned numbered key */ - if (locker->state == LOCKER_IS_FREE) { - DHD_ERROR(("%s:%d: Error! freeing already freed invalid pktid<%u>\n", - __FUNCTION__, __LINE__, nkey)); -#ifdef DHD_FW_COREDUMP - if (dhd->memdump_enabled) { - /* collect core dump */ - dhd->memdump_type = DUMP_TYPE_PKTID_INVALID; - dhd_bus_mem_dump(dhd); - } -#else - ASSERT(0); -#endif /* DHD_FW_COREDUMP */ - return NULL; - } - - /* Check for the colour of the buffer i.e The buffer posted for TX, - * should be freed for TX completion. Similarly the buffer posted for - * IOCTL should be freed for IOCT completion etc. - */ - if ((pkttype != PKTTYPE_NO_CHECK) && (locker->pkttype != pkttype)) { - - DHD_ERROR(("%s:%d: Error! Invalid Buffer Free for pktid<%u> \n", - __FUNCTION__, __LINE__, nkey)); -#ifdef BCMDMA64OSL - PHYSADDRTOULONG(locker->pa, locker_addr); -#else - locker_addr = PHYSADDRLO(locker->pa); -#endif /* BCMDMA64OSL */ - DHD_ERROR(("%s:%d: locker->state <%d>, locker->pkttype <%d>," - "pkttype <%d> locker->pa <0x%llx> \n", - __FUNCTION__, __LINE__, locker->state, locker->pkttype, - pkttype, locker_addr)); -#ifdef DHD_FW_COREDUMP - if (dhd->memdump_enabled) { - /* collect core dump */ - dhd->memdump_type = DUMP_TYPE_PKTID_INVALID; - dhd_bus_mem_dump(dhd); - } -#else - ASSERT(0); -#endif /* DHD_FW_COREDUMP */ - return NULL; - } - - if (rsv_locker == DHD_PKTID_FREE_LOCKER) { - map->avail++; - map->keys[map->avail] = nkey; /* make this numbered key available */ - locker->state = LOCKER_IS_FREE; /* open and free Locker */ - } else { - /* pktid will be reused, but the locker does not have a valid pkt */ - locker->state = LOCKER_IS_RSVD; - } - -#if defined(DHD_PKTID_AUDIT_MAP) - DHD_PKTID_AUDIT(dhd, map, nkey, DHD_TEST_IS_FREE); -#endif /* DHD_PKTID_AUDIT_MAP */ - - *pa = locker->pa; /* return contents of locker */ - *len = (uint32)locker->len; - *dmah = locker->dmah; - *secdma = locker->secdma; - - pkt = locker->pkt; - locker->pkt = NULL; /* Clear pkt */ - locker->len = 0; - - return pkt; -} - -#else /* ! DHD_PCIE_PKTID */ - - -typedef struct pktlist { - PKT_LIST *tx_pkt_list; /* list for tx packets */ - PKT_LIST *rx_pkt_list; /* list for rx packets */ - PKT_LIST *ctrl_pkt_list; /* list for ioctl/event buf post */ -} pktlists_t; - -/* - * Given that each workitem only uses a 32bit pktid, only 32bit hosts may avail - * of a one to one mapping 32bit pktptr and a 32bit pktid. - * - * - When PKTIDMAP is not used, DHD_NATIVE_TO_PKTID variants will never fail. - * - Neither DHD_NATIVE_TO_PKTID nor DHD_PKTID_TO_NATIVE need to be protected by - * a lock. - * - Hence DHD_PKTID_INVALID is not defined when DHD_PCIE_PKTID is undefined. - */ -#define DHD_PKTID32(pktptr32) ((uint32)(pktptr32)) -#define DHD_PKTPTR32(pktid32) ((void *)(pktid32)) - - -static INLINE uint32 dhd_native_to_pktid(dhd_pktid_map_handle_t *map, void *pktptr32, - dmaaddr_t pa, uint32 dma_len, void *dmah, void *secdma, - dhd_pkttype_t pkttype); -static INLINE void * dhd_pktid_to_native(dhd_pktid_map_handle_t *map, uint32 pktid32, - dmaaddr_t *pa, uint32 *dma_len, void **dmah, void **secdma, - dhd_pkttype_t pkttype); - -static dhd_pktid_map_handle_t * -dhd_pktid_map_init(dhd_pub_t *dhd, uint32 num_items) -{ - osl_t *osh = dhd->osh; - pktlists_t *handle = NULL; - - if ((handle = (pktlists_t *) MALLOCZ(osh, sizeof(pktlists_t))) == NULL) { - DHD_ERROR(("%s:%d: MALLOC failed for lists allocation, size=%d\n", - __FUNCTION__, __LINE__, sizeof(pktlists_t))); - goto error_done; - } - - if ((handle->tx_pkt_list = (PKT_LIST *) MALLOC(osh, sizeof(PKT_LIST))) == NULL) { - DHD_ERROR(("%s:%d: MALLOC failed for list allocation, size=%d\n", - __FUNCTION__, __LINE__, sizeof(PKT_LIST))); - goto error; - } - - if ((handle->rx_pkt_list = (PKT_LIST *) MALLOC(osh, sizeof(PKT_LIST))) == NULL) { - DHD_ERROR(("%s:%d: MALLOC failed for list allocation, size=%d\n", - __FUNCTION__, __LINE__, sizeof(PKT_LIST))); - goto error; - } - - if ((handle->ctrl_pkt_list = (PKT_LIST *) MALLOC(osh, sizeof(PKT_LIST))) == NULL) { - DHD_ERROR(("%s:%d: MALLOC failed for list allocation, size=%d\n", - __FUNCTION__, __LINE__, sizeof(PKT_LIST))); - goto error; - } - - PKTLIST_INIT(handle->tx_pkt_list); - PKTLIST_INIT(handle->rx_pkt_list); - PKTLIST_INIT(handle->ctrl_pkt_list); - - return (dhd_pktid_map_handle_t *) handle; - -error: - if (handle->ctrl_pkt_list) { - MFREE(osh, handle->ctrl_pkt_list, sizeof(PKT_LIST)); - } - - if (handle->rx_pkt_list) { - MFREE(osh, handle->rx_pkt_list, sizeof(PKT_LIST)); - } - - if (handle->tx_pkt_list) { - MFREE(osh, handle->tx_pkt_list, sizeof(PKT_LIST)); - } - - if (handle) { - MFREE(osh, handle, sizeof(pktlists_t)); - } - -error_done: - return (dhd_pktid_map_handle_t *)NULL; -} - -static void -dhd_pktid_map_fini(dhd_pub_t *dhd, dhd_pktid_map_handle_t *map) -{ - osl_t *osh = dhd->osh; - pktlists_t *handle = (pktlists_t *) map; - - ASSERT(handle != NULL); - if (handle == (pktlists_t *)NULL) - return; - - if (handle->ctrl_pkt_list) { - PKTLIST_FINI(handle->ctrl_pkt_list); - MFREE(osh, handle->ctrl_pkt_list, sizeof(PKT_LIST)); - } - - if (handle->rx_pkt_list) { - PKTLIST_FINI(handle->rx_pkt_list); - MFREE(osh, handle->rx_pkt_list, sizeof(PKT_LIST)); - } - - if (handle->tx_pkt_list) { - PKTLIST_FINI(handle->tx_pkt_list); - MFREE(osh, handle->tx_pkt_list, sizeof(PKT_LIST)); - } - - if (handle) { - MFREE(osh, handle, sizeof(pktlists_t)); - } -} - -/** Save dma parameters into the packet's pkttag and convert a pktptr to pktid */ -static INLINE uint32 -dhd_native_to_pktid(dhd_pktid_map_handle_t *map, void *pktptr32, - dmaaddr_t pa, uint32 dma_len, void *dmah, void *secdma, - dhd_pkttype_t pkttype) -{ - pktlists_t *handle = (pktlists_t *) map; - ASSERT(pktptr32 != NULL); - DHD_PKT_SET_DMA_LEN(pktptr32, dma_len); - DHD_PKT_SET_DMAH(pktptr32, dmah); - DHD_PKT_SET_PA(pktptr32, pa); - DHD_PKT_SET_SECDMA(pktptr32, secdma); - - if (pkttype == PKTTYPE_DATA_TX) { - PKTLIST_ENQ(handle->tx_pkt_list, pktptr32); - } else if (pkttype == PKTTYPE_DATA_RX) { - PKTLIST_ENQ(handle->rx_pkt_list, pktptr32); - } else { - PKTLIST_ENQ(handle->ctrl_pkt_list, pktptr32); - } - - return DHD_PKTID32(pktptr32); -} - -/** Convert a pktid to pktptr and retrieve saved dma parameters from packet */ -static INLINE void * -dhd_pktid_to_native(dhd_pktid_map_handle_t *map, uint32 pktid32, - dmaaddr_t *pa, uint32 *dma_len, void **dmah, void **secdma, - dhd_pkttype_t pkttype) -{ - pktlists_t *handle = (pktlists_t *) map; - void *pktptr32; - - ASSERT(pktid32 != 0U); - pktptr32 = DHD_PKTPTR32(pktid32); - *dma_len = DHD_PKT_GET_DMA_LEN(pktptr32); - *dmah = DHD_PKT_GET_DMAH(pktptr32); - *pa = DHD_PKT_GET_PA(pktptr32); - *secdma = DHD_PKT_GET_SECDMA(pktptr32); - - if (pkttype == PKTTYPE_DATA_TX) { - PKTLIST_UNLINK(handle->tx_pkt_list, pktptr32); - } else if (pkttype == PKTTYPE_DATA_RX) { - PKTLIST_UNLINK(handle->rx_pkt_list, pktptr32); - } else { - PKTLIST_UNLINK(handle->ctrl_pkt_list, pktptr32); - } - - return pktptr32; -} - -#define DHD_NATIVE_TO_PKTID_RSV(dhd, map, pkt, pkttype) DHD_PKTID32(pkt) - -#define DHD_NATIVE_TO_PKTID_SAVE(dhd, map, pkt, nkey, pa, len, dma_dir, dmah, secdma, pkttype) \ - ({ BCM_REFERENCE(dhd); BCM_REFERENCE(nkey); BCM_REFERENCE(dma_dir); \ - dhd_native_to_pktid((dhd_pktid_map_handle_t *) map, (pkt), (pa), (len), \ - (dmah), (secdma), (dhd_pkttype_t)(pkttype)); \ - }) - -#define DHD_NATIVE_TO_PKTID(dhd, map, pkt, pa, len, dma_dir, dmah, secdma, pkttype) \ - ({ BCM_REFERENCE(dhd); BCM_REFERENCE(dma_dir); \ - dhd_native_to_pktid((dhd_pktid_map_handle_t *) map, (pkt), (pa), (len), \ - (dmah), (secdma), (dhd_pkttype_t)(pkttype)); \ - }) - -#define DHD_PKTID_TO_NATIVE(dhd, map, pktid, pa, len, dmah, secdma, pkttype) \ - ({ BCM_REFERENCE(dhd); BCM_REFERENCE(pkttype); \ - dhd_pktid_to_native((dhd_pktid_map_handle_t *) map, (uint32)(pktid), \ - (dmaaddr_t *)&(pa), (uint32 *)&(len), (void **)&(dmah), \ - (void **)&secdma, (dhd_pkttype_t)(pkttype)); \ - }) - -#define DHD_PKTID_AVAIL(map) (~0) - -#endif /* ! DHD_PCIE_PKTID */ - -/* +------------------ End of PCIE DHD PKTID MAPPER -----------------------+ */ - - -/** - * The PCIE FD protocol layer is constructed in two phases: - * Phase 1. dhd_prot_attach() - * Phase 2. dhd_prot_init() - * - * dhd_prot_attach() - Allocates a dhd_prot_t object and resets all its fields. - * All Common rings are allose attached (msgbuf_ring_t objects are allocated - * with DMA-able buffers). - * All dhd_dma_buf_t objects are also allocated here. - * - * As dhd_prot_attach is invoked prior to the pcie_shared object is read, any - * initialization of objects that requires information advertized by the dongle - * may not be performed here. - * E.g. the number of TxPost flowrings is not know at this point, neither do - * we know shich form of D2H DMA sync mechanism is advertized by the dongle, or - * whether the dongle supports DMA-ing of WR/RD indices for the H2D and/or D2H - * rings (common + flow). - * - * dhd_prot_init() is invoked after the bus layer has fetched the information - * advertized by the dongle in the pcie_shared_t. - */ -int -dhd_prot_attach(dhd_pub_t *dhd) -{ - osl_t *osh = dhd->osh; - dhd_prot_t *prot; - - /* Allocate prot structure */ - if (!(prot = (dhd_prot_t *)DHD_OS_PREALLOC(dhd, DHD_PREALLOC_PROT, - sizeof(dhd_prot_t)))) { - DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - goto fail; - } - memset(prot, 0, sizeof(*prot)); - - prot->osh = osh; - dhd->prot = prot; - - /* DMAing ring completes supported? FALSE by default */ - dhd->dma_d2h_ring_upd_support = FALSE; - dhd->dma_h2d_ring_upd_support = FALSE; - dhd->dma_ring_upd_overwrite = FALSE; - - dhd->idma_inited = 0; - dhd->ifrm_inited = 0; - - /* Common Ring Allocations */ - - /* Ring 0: H2D Control Submission */ - if (dhd_prot_ring_attach(dhd, &prot->h2dring_ctrl_subn, "h2dctrl", - H2DRING_CTRL_SUB_MAX_ITEM, H2DRING_CTRL_SUB_ITEMSIZE, - BCMPCIE_H2D_MSGRING_CONTROL_SUBMIT) != BCME_OK) { - DHD_ERROR(("%s: dhd_prot_ring_attach H2D Ctrl Submission failed\n", - __FUNCTION__)); - goto fail; - } - - /* Ring 1: H2D Receive Buffer Post */ - if (dhd_prot_ring_attach(dhd, &prot->h2dring_rxp_subn, "h2drxp", - H2DRING_RXPOST_MAX_ITEM, H2DRING_RXPOST_ITEMSIZE, - BCMPCIE_H2D_MSGRING_RXPOST_SUBMIT) != BCME_OK) { - DHD_ERROR(("%s: dhd_prot_ring_attach H2D RxPost failed\n", - __FUNCTION__)); - goto fail; - } - - /* Ring 2: D2H Control Completion */ - if (dhd_prot_ring_attach(dhd, &prot->d2hring_ctrl_cpln, "d2hctrl", - D2HRING_CTRL_CMPLT_MAX_ITEM, D2HRING_CTRL_CMPLT_ITEMSIZE, - BCMPCIE_D2H_MSGRING_CONTROL_COMPLETE) != BCME_OK) { - DHD_ERROR(("%s: dhd_prot_ring_attach D2H Ctrl Completion failed\n", - __FUNCTION__)); - goto fail; - } - - /* Ring 3: D2H Transmit Complete */ - if (dhd_prot_ring_attach(dhd, &prot->d2hring_tx_cpln, "d2htxcpl", - D2HRING_TXCMPLT_MAX_ITEM, D2HRING_TXCMPLT_ITEMSIZE, - BCMPCIE_D2H_MSGRING_TX_COMPLETE) != BCME_OK) { - DHD_ERROR(("%s: dhd_prot_ring_attach D2H Tx Completion failed\n", - __FUNCTION__)); - goto fail; - - } - - /* Ring 4: D2H Receive Complete */ - if (dhd_prot_ring_attach(dhd, &prot->d2hring_rx_cpln, "d2hrxcpl", - D2HRING_RXCMPLT_MAX_ITEM, D2HRING_RXCMPLT_ITEMSIZE, - BCMPCIE_D2H_MSGRING_RX_COMPLETE) != BCME_OK) { - DHD_ERROR(("%s: dhd_prot_ring_attach D2H Rx Completion failed\n", - __FUNCTION__)); - goto fail; - - } - - /* - * Max number of flowrings is not yet known. msgbuf_ring_t with DMA-able - * buffers for flowrings will be instantiated, in dhd_prot_init() . - * See dhd_prot_flowrings_pool_attach() - */ - /* ioctl response buffer */ - if (dhd_dma_buf_alloc(dhd, &prot->retbuf, IOCT_RETBUF_SIZE)) { - goto fail; - } - - /* IOCTL request buffer */ - if (dhd_dma_buf_alloc(dhd, &prot->ioctbuf, IOCT_RETBUF_SIZE)) { - goto fail; - } - - /* Host TS request buffer one buffer for now */ - if (dhd_dma_buf_alloc(dhd, &prot->hostts_req_buf, CTRLSUB_HOSTTS_MEESAGE_SIZE)) { - goto fail; - } - prot->hostts_req_buf_inuse = FALSE; - - /* Scratch buffer for dma rx offset */ -#ifdef BCM_HOST_BUF - if (dhd_dma_buf_alloc(dhd, &prot->d2h_dma_scratch_buf, - ROUNDUP(DMA_D2H_SCRATCH_BUF_LEN, 16) + DMA_HOST_BUFFER_LEN)) -#else - if (dhd_dma_buf_alloc(dhd, &prot->d2h_dma_scratch_buf, DMA_D2H_SCRATCH_BUF_LEN)) -#endif /* BCM_HOST_BUF */ - { - goto fail; - } - - /* scratch buffer bus throughput measurement */ - if (dhd_dma_buf_alloc(dhd, &prot->host_bus_throughput_buf, DHD_BUS_TPUT_BUF_LEN)) { - goto fail; - } - -#ifdef DHD_RX_CHAINING - dhd_rxchain_reset(&prot->rxchain); -#endif - - prot->rx_lock = dhd_os_spin_lock_init(dhd->osh); - - prot->pktid_ctrl_map = DHD_NATIVE_TO_PKTID_INIT(dhd, MAX_CTRL_PKTID); - if (prot->pktid_ctrl_map == NULL) { - goto fail; - } - - prot->pktid_rx_map = DHD_NATIVE_TO_PKTID_INIT(dhd, MAX_RX_PKTID); - if (prot->pktid_rx_map == NULL) - goto fail; - - prot->pktid_tx_map = DHD_NATIVE_TO_PKTID_INIT(dhd, MAX_TX_PKTID); - if (prot->pktid_rx_map == NULL) - goto fail; - -#ifdef IOCTLRESP_USE_CONSTMEM - prot->pktid_map_handle_ioctl = DHD_NATIVE_TO_PKTID_INIT(dhd, - DHD_FLOWRING_MAX_IOCTLRESPBUF_POST); - if (prot->pktid_map_handle_ioctl == NULL) { - goto fail; - } -#endif /* IOCTLRESP_USE_CONSTMEM */ - - /* Initialize the work queues to be used by the Load Balancing logic */ -#if defined(DHD_LB_TXC) - { - void *buffer; - buffer = MALLOC(dhd->osh, sizeof(void*) * DHD_LB_WORKQ_SZ); - bcm_workq_init(&prot->tx_compl_prod, &prot->tx_compl_cons, - buffer, DHD_LB_WORKQ_SZ); - prot->tx_compl_prod_sync = 0; - DHD_INFO(("%s: created tx_compl_workq <%p,%d>\n", - __FUNCTION__, buffer, DHD_LB_WORKQ_SZ)); - } -#endif /* DHD_LB_TXC */ - -#if defined(DHD_LB_RXC) - { - void *buffer; - buffer = MALLOC(dhd->osh, sizeof(void*) * DHD_LB_WORKQ_SZ); - bcm_workq_init(&prot->rx_compl_prod, &prot->rx_compl_cons, - buffer, DHD_LB_WORKQ_SZ); - prot->rx_compl_prod_sync = 0; - DHD_INFO(("%s: created rx_compl_workq <%p,%d>\n", - __FUNCTION__, buffer, DHD_LB_WORKQ_SZ)); - } -#endif /* DHD_LB_RXC */ - /* Initialize trap buffer */ - if (dhd_dma_buf_alloc(dhd, &dhd->prot->fw_trap_buf, BCMPCIE_EXT_TRAP_DATA_MAXLEN)) { - DHD_ERROR(("%s: dhd_init_trap_buffer falied\n", __FUNCTION__)); - goto fail; - } - - return BCME_OK; - -fail: - -#ifndef CONFIG_DHD_USE_STATIC_BUF - if (prot != NULL) { - dhd_prot_detach(dhd); - } -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - - return BCME_NOMEM; -} /* dhd_prot_attach */ - -void -dhd_set_host_cap(dhd_pub_t *dhd) -{ - uint32 data = 0; - dhd_prot_t *prot = dhd->prot; - - if (dhd->bus->api.fw_rev >= PCIE_SHARED_VERSION_6) { - if (dhd->h2d_phase_supported) { - - data |= HOSTCAP_H2D_VALID_PHASE; - - if (dhd->force_dongletrap_on_bad_h2d_phase) { - data |= HOSTCAP_H2D_ENABLE_TRAP_ON_BADPHASE; - } - } - if (prot->host_ipc_version > prot->device_ipc_version) { - prot->active_ipc_version = prot->device_ipc_version; - } else { - prot->active_ipc_version = prot->host_ipc_version; - } - - data |= prot->active_ipc_version; - - if (dhdpcie_bus_get_pcie_hostready_supported(dhd->bus)) { - - DHD_INFO(("Advertise Hostready Capability\n")); - - data |= HOSTCAP_H2D_ENABLE_HOSTRDY; - } -#ifdef PCIE_INB_DW - if (dhdpcie_bus_get_pcie_inband_dw_supported(dhd->bus)) { - DHD_INFO(("Advertise Inband-DW Capability\n")); - data |= HOSTCAP_DS_INBAND_DW; - data |= HOSTCAP_DS_NO_OOB_DW; - dhdpcie_bus_enab_pcie_dw(dhd->bus, DEVICE_WAKE_INB); - } else -#endif /* PCIE_INB_DW */ -#ifdef PCIE_OOB - if (dhdpcie_bus_get_pcie_oob_dw_supported(dhd->bus)) { - dhdpcie_bus_enab_pcie_dw(dhd->bus, DEVICE_WAKE_OOB); - } else -#endif /* PCIE_OOB */ - { - /* Disable DS altogether */ - data |= HOSTCAP_DS_NO_OOB_DW; - dhdpcie_bus_enab_pcie_dw(dhd->bus, DEVICE_WAKE_NONE); - } - - if (dhdpcie_bus_get_pcie_idma_supported(dhd->bus)) { - - DHD_ERROR(("IDMA inited\n")); - data |= HOSTCAP_H2D_IDMA; - dhd->idma_inited = TRUE; - } - - if (dhdpcie_bus_get_pcie_ifrm_supported(dhd->bus)) { - DHD_ERROR(("IFRM Inited\n")); - data |= HOSTCAP_H2D_IFRM; - dhd->ifrm_inited = TRUE; - dhd->dma_h2d_ring_upd_support = FALSE; - dhd_prot_dma_indx_free(dhd); - } - - /* Indicate support for TX status metadata */ - data |= HOSTCAP_TXSTATUS_METADATA; - - /* Indicate support for extended trap data */ - data |= HOSTCAP_EXTENDED_TRAP_DATA; - - DHD_INFO(("%s:Active Ver:%d, Host Ver:%d, FW Ver:%d\n", - __FUNCTION__, - prot->active_ipc_version, prot->host_ipc_version, - prot->device_ipc_version)); - - dhd_bus_cmn_writeshared(dhd->bus, &data, sizeof(uint32), HOST_API_VERSION, 0); - dhd_bus_cmn_writeshared(dhd->bus, &prot->fw_trap_buf.pa, - sizeof(prot->fw_trap_buf.pa), DNGL_TO_HOST_TRAP_ADDR, 0); - } -#ifdef HOFFLOAD_MODULES - dhd_bus_cmn_writeshared(dhd->bus, &dhd->hmem.data_addr, - sizeof(dhd->hmem.data_addr), WRT_HOST_MODULE_ADDR, 0); -#endif - -#ifdef DHD_TIMESYNC - dhd_timesync_notify_ipc_rev(dhd->ts, prot->active_ipc_version); -#endif /* DHD_TIMESYNC */ -} - -/** - * dhd_prot_init - second stage of dhd_prot_attach. Now that the dongle has - * completed it's initialization of the pcie_shared structure, we may now fetch - * the dongle advertized features and adjust the protocol layer accordingly. - * - * dhd_prot_init() may be invoked again after a dhd_prot_reset(). - */ -int -dhd_prot_init(dhd_pub_t *dhd) -{ - sh_addr_t base_addr; - dhd_prot_t *prot = dhd->prot; - int ret = 0; - - /** - * A user defined value can be assigned to global variable h2d_max_txpost via - * 1. DHD IOVAR h2d_max_txpost, before firmware download - * 2. module parameter h2d_max_txpost - * prot->h2d_max_txpost is assigned with H2DRING_TXPOST_MAX_ITEM, - * if user has not defined any buffers by one of the above methods. - */ - prot->h2d_max_txpost = (uint16)h2d_max_txpost; - - DHD_ERROR(("%s:%d: h2d_max_txpost = %d\n", __FUNCTION__, __LINE__, prot->h2d_max_txpost)); - - /* Read max rx packets supported by dongle */ - dhd_bus_cmn_readshared(dhd->bus, &prot->max_rxbufpost, MAX_HOST_RXBUFS, 0); - if (prot->max_rxbufpost == 0) { - /* This would happen if the dongle firmware is not */ - /* using the latest shared structure template */ - prot->max_rxbufpost = DEFAULT_RX_BUFFERS_TO_POST; - } - DHD_INFO(("%s:%d: MAX_RXBUFPOST = %d\n", __FUNCTION__, __LINE__, prot->max_rxbufpost)); - - /* Initialize. bzero() would blow away the dma pointers. */ - prot->max_eventbufpost = DHD_FLOWRING_MAX_EVENTBUF_POST; - prot->max_ioctlrespbufpost = DHD_FLOWRING_MAX_IOCTLRESPBUF_POST; - prot->max_infobufpost = DHD_H2D_INFORING_MAX_BUF_POST; - prot->max_tsbufpost = DHD_MAX_TSBUF_POST; - - prot->cur_ioctlresp_bufs_posted = 0; - prot->active_tx_count = 0; - prot->data_seq_no = 0; - prot->ioctl_seq_no = 0; - prot->rxbufpost = 0; - prot->cur_event_bufs_posted = 0; - prot->ioctl_state = 0; - prot->curr_ioctl_cmd = 0; - prot->cur_ts_bufs_posted = 0; - prot->infobufpost = 0; - - prot->dmaxfer.srcmem.va = NULL; - prot->dmaxfer.dstmem.va = NULL; - prot->dmaxfer.in_progress = FALSE; - - prot->metadata_dbg = FALSE; - prot->rx_metadata_offset = 0; - prot->tx_metadata_offset = 0; - prot->txp_threshold = TXP_FLUSH_MAX_ITEMS_FLUSH_CNT; - - /* To catch any rollover issues fast, starting with higher ioctl_trans_id */ - prot->ioctl_trans_id = MAXBITVAL(NBITS(prot->ioctl_trans_id)) - BUFFER_BEFORE_ROLLOVER; - prot->ioctl_state = 0; - prot->ioctl_status = 0; - prot->ioctl_resplen = 0; - prot->ioctl_received = IOCTL_WAIT; - - /* Register the interrupt function upfront */ - /* remove corerev checks in data path */ - prot->mb_ring_fn = dhd_bus_get_mbintr_fn(dhd->bus); - - prot->mb_2_ring_fn = dhd_bus_get_mbintr_2_fn(dhd->bus); - - /* Initialize Common MsgBuf Rings */ - - prot->device_ipc_version = dhd->bus->api.fw_rev; - prot->host_ipc_version = PCIE_SHARED_VERSION; - - /* Init the host API version */ - dhd_set_host_cap(dhd); - - dhd_prot_ring_init(dhd, &prot->h2dring_ctrl_subn); - dhd_prot_ring_init(dhd, &prot->h2dring_rxp_subn); - dhd_prot_ring_init(dhd, &prot->d2hring_ctrl_cpln); - - /* Make it compatibile with pre-rev7 Firmware */ - if (prot->active_ipc_version < PCIE_SHARED_VERSION_7) { - prot->d2hring_tx_cpln.item_len = - D2HRING_TXCMPLT_ITEMSIZE_PREREV7; - prot->d2hring_rx_cpln.item_len = - D2HRING_RXCMPLT_ITEMSIZE_PREREV7; - } - dhd_prot_ring_init(dhd, &prot->d2hring_tx_cpln); - dhd_prot_ring_init(dhd, &prot->d2hring_rx_cpln); - - dhd_prot_d2h_sync_init(dhd); - - dhd_prot_h2d_sync_init(dhd); - -#ifdef PCIE_INB_DW - /* Set the initial DS state */ - if (INBAND_DW_ENAB(dhd->bus)) { - dhdpcie_bus_set_pcie_inband_dw_state(dhd->bus, - DW_DEVICE_DS_ACTIVE); - } -#endif /* PCIE_INB_DW */ - - /* init the scratch buffer */ - dhd_base_addr_htolpa(&base_addr, prot->d2h_dma_scratch_buf.pa); - dhd_bus_cmn_writeshared(dhd->bus, &base_addr, sizeof(base_addr), - D2H_DMA_SCRATCH_BUF, 0); - dhd_bus_cmn_writeshared(dhd->bus, &prot->d2h_dma_scratch_buf.len, - sizeof(prot->d2h_dma_scratch_buf.len), D2H_DMA_SCRATCH_BUF_LEN, 0); - - /* If supported by the host, indicate the memory block - * for completion writes / submission reads to shared space - */ - if (dhd->dma_d2h_ring_upd_support) { - dhd_base_addr_htolpa(&base_addr, prot->d2h_dma_indx_wr_buf.pa); - dhd_bus_cmn_writeshared(dhd->bus, &base_addr, sizeof(base_addr), - D2H_DMA_INDX_WR_BUF, 0); - dhd_base_addr_htolpa(&base_addr, prot->h2d_dma_indx_rd_buf.pa); - dhd_bus_cmn_writeshared(dhd->bus, &base_addr, sizeof(base_addr), - H2D_DMA_INDX_RD_BUF, 0); - } - - if (dhd->dma_h2d_ring_upd_support || IDMA_ENAB(dhd)) { - dhd_base_addr_htolpa(&base_addr, prot->h2d_dma_indx_wr_buf.pa); - dhd_bus_cmn_writeshared(dhd->bus, &base_addr, sizeof(base_addr), - H2D_DMA_INDX_WR_BUF, 0); - dhd_base_addr_htolpa(&base_addr, prot->d2h_dma_indx_rd_buf.pa); - dhd_bus_cmn_writeshared(dhd->bus, &base_addr, sizeof(base_addr), - D2H_DMA_INDX_RD_BUF, 0); - - } - - /* Signal to the dongle that common ring init is complete */ - dhd_bus_hostready(dhd->bus); - - /* - * If the DMA-able buffers for flowring needs to come from a specific - * contiguous memory region, then setup prot->flowrings_dma_buf here. - * dhd_prot_flowrings_pool_attach() will carve out DMA-able buffers from - * this contiguous memory region, for each of the flowrings. - */ - - /* Pre-allocate pool of msgbuf_ring for flowrings */ - if (dhd_prot_flowrings_pool_attach(dhd) != BCME_OK) { - return BCME_ERROR; - } - - /* If IFRM is enabled, wait for FW to setup the DMA channel */ - if (IFRM_ENAB(dhd)) { - dhd_base_addr_htolpa(&base_addr, prot->h2d_ifrm_indx_wr_buf.pa); - dhd_bus_cmn_writeshared(dhd->bus, &base_addr, sizeof(base_addr), - H2D_IFRM_INDX_WR_BUF, 0); - } - - /* See if info rings could be created */ - if (dhd->bus->api.fw_rev >= PCIE_SHARED_VERSION_6) { - if ((ret = dhd_prot_init_info_rings(dhd)) != BCME_OK) { - /* For now log and proceed, further clean up action maybe necessary - * when we have more clarity. - */ - DHD_ERROR(("%s Info rings couldn't be created: Err Code%d", - __FUNCTION__, ret)); - } - } - - /* Host should configure soft doorbells if needed ... here */ - - /* Post to dongle host configured soft doorbells */ - dhd_msgbuf_ring_config_d2h_soft_doorbell(dhd); - - /* Post buffers for packet reception and ioctl/event responses */ - dhd_msgbuf_rxbuf_post(dhd, FALSE); /* alloc pkt ids */ - dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd); - /* Fix re-entry problem without general lock */ - atomic_set(&dhd_msgbuf_rxbuf_post_event_bufs_running, 0); - dhd_msgbuf_rxbuf_post_event_bufs(dhd); - - return BCME_OK; -} /* dhd_prot_init */ - - -/** - * dhd_prot_detach - PCIE FD protocol layer destructor. - * Unlink, frees allocated protocol memory (including dhd_prot) - */ -void dhd_prot_detach(dhd_pub_t *dhd) -{ - dhd_prot_t *prot = dhd->prot; - - /* Stop the protocol module */ - if (prot) { - - /* free up all DMA-able buffers allocated during prot attach/init */ - - dhd_dma_buf_free(dhd, &prot->d2h_dma_scratch_buf); - dhd_dma_buf_free(dhd, &prot->retbuf); - dhd_dma_buf_free(dhd, &prot->ioctbuf); - dhd_dma_buf_free(dhd, &prot->host_bus_throughput_buf); - dhd_dma_buf_free(dhd, &prot->hostts_req_buf); - dhd_dma_buf_free(dhd, &prot->fw_trap_buf); - - /* DMA-able buffers for DMAing H2D/D2H WR/RD indices */ - dhd_dma_buf_free(dhd, &prot->h2d_dma_indx_wr_buf); - dhd_dma_buf_free(dhd, &prot->h2d_dma_indx_rd_buf); - dhd_dma_buf_free(dhd, &prot->d2h_dma_indx_wr_buf); - dhd_dma_buf_free(dhd, &prot->d2h_dma_indx_rd_buf); - - dhd_dma_buf_free(dhd, &prot->h2d_ifrm_indx_wr_buf); - - /* Common MsgBuf Rings */ - dhd_prot_ring_detach(dhd, &prot->h2dring_ctrl_subn); - dhd_prot_ring_detach(dhd, &prot->h2dring_rxp_subn); - dhd_prot_ring_detach(dhd, &prot->d2hring_ctrl_cpln); - dhd_prot_ring_detach(dhd, &prot->d2hring_tx_cpln); - dhd_prot_ring_detach(dhd, &prot->d2hring_rx_cpln); - - /* Detach each DMA-able buffer and free the pool of msgbuf_ring_t */ - dhd_prot_flowrings_pool_detach(dhd); - - /* detach info rings */ - dhd_prot_detach_info_rings(dhd); - - /* if IOCTLRESP_USE_CONSTMEM is defined IOCTL PKTs use pktid_map_handle_ioctl - * handler and PKT memory is allocated using alloc_ioctl_return_buffer(), Otherwise - * they will be part of pktid_ctrl_map handler and PKT memory is allocated using - * PKTGET_STATIC (if DHD_USE_STATIC_CTRLBUF is defined) OR PKGET. - * Similarly for freeing PKT buffers DHD_NATIVE_TO_PKTID_FINI will be used - * which calls PKTFREE_STATIC (if DHD_USE_STATIC_CTRLBUF is defined) OR PKFREE. - * Else if IOCTLRESP_USE_CONSTMEM is defined IOCTL PKTs will be freed using - * DHD_NATIVE_TO_PKTID_FINI_IOCTL which calls free_ioctl_return_buffer. - */ - DHD_NATIVE_TO_PKTID_FINI(dhd, prot->pktid_ctrl_map); - DHD_NATIVE_TO_PKTID_FINI(dhd, prot->pktid_rx_map); - DHD_NATIVE_TO_PKTID_FINI(dhd, prot->pktid_tx_map); -#ifdef IOCTLRESP_USE_CONSTMEM - DHD_NATIVE_TO_PKTID_FINI_IOCTL(dhd, prot->pktid_map_handle_ioctl); -#endif - - dhd_os_spin_lock_deinit(dhd->osh, prot->rx_lock); - -#ifndef CONFIG_DHD_USE_STATIC_BUF - MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t)); -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - -#if defined(DHD_LB_TXC) - if (prot->tx_compl_prod.buffer) - MFREE(dhd->osh, prot->tx_compl_prod.buffer, - sizeof(void*) * DHD_LB_WORKQ_SZ); -#endif /* DHD_LB_TXC */ -#if defined(DHD_LB_RXC) - if (prot->rx_compl_prod.buffer) - MFREE(dhd->osh, prot->rx_compl_prod.buffer, - sizeof(void*) * DHD_LB_WORKQ_SZ); -#endif /* DHD_LB_RXC */ - - dhd->prot = NULL; - } -} /* dhd_prot_detach */ - - -/** - * dhd_prot_reset - Reset the protocol layer without freeing any objects. - * This may be invoked to soft reboot the dongle, without having to - * detach and attach the entire protocol layer. - * - * After dhd_prot_reset(), dhd_prot_init() may be invoked - * without going througha dhd_prot_attach() phase. - */ -void -dhd_prot_reset(dhd_pub_t *dhd) -{ - struct dhd_prot *prot = dhd->prot; - - DHD_TRACE(("%s\n", __FUNCTION__)); - - if (prot == NULL) { - return; - } - - dhd_prot_flowrings_pool_reset(dhd); - - /* Reset Common MsgBuf Rings */ - dhd_prot_ring_reset(dhd, &prot->h2dring_ctrl_subn); - dhd_prot_ring_reset(dhd, &prot->h2dring_rxp_subn); - dhd_prot_ring_reset(dhd, &prot->d2hring_ctrl_cpln); - dhd_prot_ring_reset(dhd, &prot->d2hring_tx_cpln); - dhd_prot_ring_reset(dhd, &prot->d2hring_rx_cpln); - - /* Reset info rings */ - if (prot->h2dring_info_subn) { - dhd_prot_ring_reset(dhd, prot->h2dring_info_subn); - } - - if (prot->d2hring_info_cpln) { - dhd_prot_ring_reset(dhd, prot->d2hring_info_cpln); - } - - /* Reset all DMA-able buffers allocated during prot attach */ - dhd_dma_buf_reset(dhd, &prot->d2h_dma_scratch_buf); - dhd_dma_buf_reset(dhd, &prot->retbuf); - dhd_dma_buf_reset(dhd, &prot->ioctbuf); - dhd_dma_buf_reset(dhd, &prot->host_bus_throughput_buf); - dhd_dma_buf_reset(dhd, &prot->hostts_req_buf); - dhd_dma_buf_reset(dhd, &prot->fw_trap_buf); - - dhd_dma_buf_reset(dhd, &prot->h2d_ifrm_indx_wr_buf); - - /* Reset all DMA-able buffers for DMAing H2D/D2H WR/RD indices */ - dhd_dma_buf_reset(dhd, &prot->h2d_dma_indx_rd_buf); - dhd_dma_buf_reset(dhd, &prot->h2d_dma_indx_wr_buf); - dhd_dma_buf_reset(dhd, &prot->d2h_dma_indx_rd_buf); - dhd_dma_buf_reset(dhd, &prot->d2h_dma_indx_wr_buf); - - - prot->rx_metadata_offset = 0; - prot->tx_metadata_offset = 0; - - prot->rxbufpost = 0; - prot->cur_event_bufs_posted = 0; - prot->cur_ioctlresp_bufs_posted = 0; - - prot->active_tx_count = 0; - prot->data_seq_no = 0; - prot->ioctl_seq_no = 0; - prot->ioctl_state = 0; - prot->curr_ioctl_cmd = 0; - prot->ioctl_received = IOCTL_WAIT; - /* To catch any rollover issues fast, starting with higher ioctl_trans_id */ - prot->ioctl_trans_id = MAXBITVAL(NBITS(prot->ioctl_trans_id)) - BUFFER_BEFORE_ROLLOVER; - - /* dhd_flow_rings_init is located at dhd_bus_start, - * so when stopping bus, flowrings shall be deleted - */ - if (dhd->flow_rings_inited) { - dhd_flow_rings_deinit(dhd); - } - - /* Reset PKTID map */ - DHD_NATIVE_TO_PKTID_RESET(dhd, prot->pktid_ctrl_map); - DHD_NATIVE_TO_PKTID_RESET(dhd, prot->pktid_rx_map); - DHD_NATIVE_TO_PKTID_RESET(dhd, prot->pktid_tx_map); -#ifdef IOCTLRESP_USE_CONSTMEM - DHD_NATIVE_TO_PKTID_RESET_IOCTL(dhd, prot->pktid_map_handle_ioctl); -#endif /* IOCTLRESP_USE_CONSTMEM */ -#ifdef DMAMAP_STATS - dhd->dma_stats.txdata = dhd->dma_stats.txdata_sz = 0; - dhd->dma_stats.rxdata = dhd->dma_stats.rxdata_sz = 0; -#ifndef IOCTLRESP_USE_CONSTMEM - dhd->dma_stats.ioctl_rx = dhd->dma_stats.ioctl_rx_sz = 0; -#endif /* IOCTLRESP_USE_CONSTMEM */ - dhd->dma_stats.event_rx = dhd->dma_stats.event_rx_sz = 0; - dhd->dma_stats.info_rx = dhd->dma_stats.info_rx_sz = 0; - dhd->dma_stats.tsbuf_rx = dhd->dma_stats.tsbuf_rx_sz = 0; -#endif /* DMAMAP_STATS */ -} /* dhd_prot_reset */ - -#if defined(DHD_LB_RXP) -#define DHD_LB_DISPATCH_RX_PROCESS(dhdp) dhd_lb_dispatch_rx_process(dhdp) -#else /* !DHD_LB_RXP */ -#define DHD_LB_DISPATCH_RX_PROCESS(dhdp) do { /* noop */ } while (0) -#endif /* !DHD_LB_RXP */ - -#if defined(DHD_LB_RXC) -#define DHD_LB_DISPATCH_RX_COMPL(dhdp) dhd_lb_dispatch_rx_compl(dhdp) -#else /* !DHD_LB_RXC */ -#define DHD_LB_DISPATCH_RX_COMPL(dhdp) do { /* noop */ } while (0) -#endif /* !DHD_LB_RXC */ - -#if defined(DHD_LB_TXC) -#define DHD_LB_DISPATCH_TX_COMPL(dhdp) dhd_lb_dispatch_tx_compl(dhdp) -#else /* !DHD_LB_TXC */ -#define DHD_LB_DISPATCH_TX_COMPL(dhdp) do { /* noop */ } while (0) -#endif /* !DHD_LB_TXC */ - - -#if defined(DHD_LB) -/* DHD load balancing: deferral of work to another online CPU */ -/* DHD_LB_TXC DHD_LB_RXC DHD_LB_RXP dispatchers, in dhd_linux.c */ -extern void dhd_lb_tx_compl_dispatch(dhd_pub_t *dhdp); -extern void dhd_lb_rx_compl_dispatch(dhd_pub_t *dhdp); -extern void dhd_lb_rx_napi_dispatch(dhd_pub_t *dhdp); -extern void dhd_lb_rx_pkt_enqueue(dhd_pub_t *dhdp, void *pkt, int ifidx); - -#if defined(DHD_LB_RXP) -/** - * dhd_lb_dispatch_rx_process - load balance by dispatch Rx processing work - * to other CPU cores - */ -static INLINE void -dhd_lb_dispatch_rx_process(dhd_pub_t *dhdp) -{ - dhd_lb_rx_napi_dispatch(dhdp); /* dispatch rx_process_napi */ -} -#endif /* DHD_LB_RXP */ - -#if defined(DHD_LB_TXC) -/** - * dhd_lb_dispatch_tx_compl - load balance by dispatch Tx complition work - * to other CPU cores - */ -static INLINE void -dhd_lb_dispatch_tx_compl(dhd_pub_t *dhdp, uint16 ring_idx) -{ - bcm_workq_prod_sync(&dhdp->prot->tx_compl_prod); /* flush WR index */ - dhd_lb_tx_compl_dispatch(dhdp); /* dispatch tx_compl_tasklet */ -} - -/** - * DHD load balanced tx completion tasklet handler, that will perform the - * freeing of packets on the selected CPU. Packet pointers are delivered to - * this tasklet via the tx complete workq. - */ -void -dhd_lb_tx_compl_handler(unsigned long data) -{ - int elem_ix; - void *pkt, **elem; - dmaaddr_t pa; - uint32 pa_len; - dhd_pub_t *dhd = (dhd_pub_t *)data; - dhd_prot_t *prot = dhd->prot; - bcm_workq_t *workq = &prot->tx_compl_cons; - uint32 count = 0; - - int curr_cpu; - curr_cpu = get_cpu(); - put_cpu(); - - DHD_LB_STATS_TXC_PERCPU_CNT_INCR(dhd); - - while (1) { - elem_ix = bcm_ring_cons(WORKQ_RING(workq), DHD_LB_WORKQ_SZ); - - if (elem_ix == BCM_RING_EMPTY) { - break; - } - - elem = WORKQ_ELEMENT(void *, workq, elem_ix); - pkt = *elem; - - DHD_INFO(("%s: tx_compl_cons pkt<%p>\n", __FUNCTION__, pkt)); - - OSL_PREFETCH(PKTTAG(pkt)); - OSL_PREFETCH(pkt); - - pa = DHD_PKTTAG_PA((dhd_pkttag_fr_t *)PKTTAG(pkt)); - pa_len = DHD_PKTTAG_PA_LEN((dhd_pkttag_fr_t *)PKTTAG(pkt)); - - DMA_UNMAP(dhd->osh, pa, pa_len, DMA_RX, 0, 0); -#if defined(BCMPCIE) - dhd_txcomplete(dhd, pkt, true); -#endif - - PKTFREE(dhd->osh, pkt, TRUE); - count++; - } - - /* smp_wmb(); */ - bcm_workq_cons_sync(workq); - DHD_LB_STATS_UPDATE_TXC_HISTO(dhd, count); -} -#endif /* DHD_LB_TXC */ - -#if defined(DHD_LB_RXC) - -/** - * dhd_lb_dispatch_rx_compl - load balance by dispatch rx complition work - * to other CPU cores - */ -static INLINE void -dhd_lb_dispatch_rx_compl(dhd_pub_t *dhdp) -{ - dhd_prot_t *prot = dhdp->prot; - /* Schedule the takslet only if we have to */ - if (prot->rxbufpost <= (prot->max_rxbufpost - RXBUFPOST_THRESHOLD)) { - /* flush WR index */ - bcm_workq_prod_sync(&dhdp->prot->rx_compl_prod); - dhd_lb_rx_compl_dispatch(dhdp); /* dispatch rx_compl_tasklet */ - } -} - -void -dhd_lb_rx_compl_handler(unsigned long data) -{ - dhd_pub_t *dhd = (dhd_pub_t *)data; - bcm_workq_t *workq = &dhd->prot->rx_compl_cons; - - DHD_LB_STATS_RXC_PERCPU_CNT_INCR(dhd); - - dhd_msgbuf_rxbuf_post(dhd, TRUE); /* re-use pktids */ - bcm_workq_cons_sync(workq); -} -#endif /* DHD_LB_RXC */ -#endif /* DHD_LB */ - -void -dhd_prot_rx_dataoffset(dhd_pub_t *dhd, uint32 rx_offset) -{ - dhd_prot_t *prot = dhd->prot; - prot->rx_dataoffset = rx_offset; -} - -static int -dhd_check_create_info_rings(dhd_pub_t *dhd) -{ - dhd_prot_t *prot = dhd->prot; - int ret = BCME_ERROR; - uint16 ringid = dhd->bus->max_tx_flowrings + BCMPCIE_COMMON_MSGRINGS; - - if (prot->h2dring_info_subn && prot->d2hring_info_cpln) { - return BCME_OK; /* dhd_prot_init rentry after a dhd_prot_reset */ - } - - if (prot->h2dring_info_subn == NULL) { - prot->h2dring_info_subn = MALLOCZ(prot->osh, sizeof(msgbuf_ring_t)); - - if (prot->h2dring_info_subn == NULL) { - DHD_ERROR(("%s: couldn't alloc memory for h2dring_info_subn\n", - __FUNCTION__)); - return BCME_NOMEM; - } - - DHD_INFO(("%s: about to create debug submit ring\n", __FUNCTION__)); - ret = dhd_prot_ring_attach(dhd, prot->h2dring_info_subn, "h2dinfo", - H2DRING_DYNAMIC_INFO_MAX_ITEM, H2DRING_INFO_BUFPOST_ITEMSIZE, - ringid); - if (ret != BCME_OK) { - DHD_ERROR(("%s: couldn't alloc resources for dbg submit ring\n", - __FUNCTION__)); - goto err; - } - } - - if (prot->d2hring_info_cpln == NULL) { - prot->d2hring_info_cpln = MALLOCZ(prot->osh, sizeof(msgbuf_ring_t)); - - if (prot->d2hring_info_cpln == NULL) { - DHD_ERROR(("%s: couldn't alloc memory for h2dring_info_subn\n", - __FUNCTION__)); - return BCME_NOMEM; - } - - /* create the debug info completion ring next to debug info submit ring - * ringid = id next to debug info submit ring - */ - ringid = ringid + 1; - - DHD_INFO(("%s: about to create debug cpl ring\n", __FUNCTION__)); - ret = dhd_prot_ring_attach(dhd, prot->d2hring_info_cpln, "d2hinfo", - D2HRING_DYNAMIC_INFO_MAX_ITEM, D2HRING_INFO_BUFCMPLT_ITEMSIZE, - ringid); - if (ret != BCME_OK) { - DHD_ERROR(("%s: couldn't alloc resources for dbg cpl ring\n", - __FUNCTION__)); - dhd_prot_ring_detach(dhd, prot->h2dring_info_subn); - goto err; - } - } - - return ret; -err: - MFREE(prot->osh, prot->h2dring_info_subn, sizeof(msgbuf_ring_t)); - prot->h2dring_info_subn = NULL; - - if (prot->d2hring_info_cpln) { - MFREE(prot->osh, prot->d2hring_info_cpln, sizeof(msgbuf_ring_t)); - prot->d2hring_info_cpln = NULL; - } - return ret; -} /* dhd_check_create_info_rings */ - -int -dhd_prot_init_info_rings(dhd_pub_t *dhd) -{ - dhd_prot_t *prot = dhd->prot; - int ret = BCME_OK; - - if ((ret = dhd_check_create_info_rings(dhd)) != BCME_OK) { - DHD_ERROR(("%s: info rings aren't created! \n", - __FUNCTION__)); - return ret; - } - - if ((prot->d2hring_info_cpln->inited) || (prot->d2hring_info_cpln->create_pending)) { - DHD_INFO(("Info completion ring was created!\n")); - return ret; - } - - DHD_TRACE(("trying to send create d2h info ring: id %d\n", prot->d2hring_info_cpln->idx)); - ret = dhd_send_d2h_ringcreate(dhd, prot->d2hring_info_cpln); - if (ret != BCME_OK) - return ret; - - prot->d2hring_info_cpln->seqnum = D2H_EPOCH_INIT_VAL; - - DHD_TRACE(("trying to send create h2d info ring id %d\n", prot->h2dring_info_subn->idx)); - prot->h2dring_info_subn->n_completion_ids = 1; - prot->h2dring_info_subn->compeltion_ring_ids[0] = prot->d2hring_info_cpln->idx; - - ret = dhd_send_h2d_ringcreate(dhd, prot->h2dring_info_subn); - - /* Note that there is no way to delete d2h or h2d ring deletion incase either fails, - * so can not cleanup if one ring was created while the other failed - */ - return ret; -} /* dhd_prot_init_info_rings */ - -static void -dhd_prot_detach_info_rings(dhd_pub_t *dhd) -{ - if (dhd->prot->h2dring_info_subn) { - dhd_prot_ring_detach(dhd, dhd->prot->h2dring_info_subn); - MFREE(dhd->prot->osh, dhd->prot->h2dring_info_subn, sizeof(msgbuf_ring_t)); - dhd->prot->h2dring_info_subn = NULL; - } - if (dhd->prot->d2hring_info_cpln) { - dhd_prot_ring_detach(dhd, dhd->prot->d2hring_info_cpln); - MFREE(dhd->prot->osh, dhd->prot->d2hring_info_cpln, sizeof(msgbuf_ring_t)); - dhd->prot->d2hring_info_cpln = NULL; - } -} - -/** - * Initialize protocol: sync w/dongle state. - * Sets dongle media info (iswl, drv_version, mac address). - */ -int dhd_sync_with_dongle(dhd_pub_t *dhd) -{ - int ret = 0; - wlc_rev_info_t revinfo; - - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - dhd_os_set_ioctl_resp_timeout(IOCTL_RESP_TIMEOUT); - - /* Post ts buffer after shim layer is attached */ - ret = dhd_msgbuf_rxbuf_post_ts_bufs(dhd); - - -#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) { - DHD_ERROR(("%s: GET revinfo FAILED\n", __FUNCTION__)); - goto done; - } - DHD_ERROR(("%s: GET_REVINFO device 0x%x, vendor 0x%x, chipnum 0x%x\n", __FUNCTION__, - revinfo.deviceid, revinfo.vendorid, revinfo.chipnum)); - - 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; -} /* dhd_sync_with_dongle */ - - -#define DHD_DBG_SHOW_METADATA 0 - -#if DHD_DBG_SHOW_METADATA -static void BCMFASTPATH -dhd_prot_print_metadata(dhd_pub_t *dhd, void *ptr, int len) -{ - uint8 tlv_t; - uint8 tlv_l; - uint8 *tlv_v = (uint8 *)ptr; - - if (len <= BCMPCIE_D2H_METADATA_HDRLEN) - return; - - len -= BCMPCIE_D2H_METADATA_HDRLEN; - tlv_v += BCMPCIE_D2H_METADATA_HDRLEN; - - while (len > TLV_HDR_LEN) { - tlv_t = tlv_v[TLV_TAG_OFF]; - tlv_l = tlv_v[TLV_LEN_OFF]; - - len -= TLV_HDR_LEN; - tlv_v += TLV_HDR_LEN; - if (len < tlv_l) - break; - if ((tlv_t == 0) || (tlv_t == WLFC_CTL_TYPE_FILLER)) - break; - - switch (tlv_t) { - case WLFC_CTL_TYPE_TXSTATUS: { - uint32 txs; - memcpy(&txs, tlv_v, sizeof(uint32)); - if (tlv_l < (sizeof(wl_txstatus_additional_info_t) + sizeof(uint32))) { - printf("METADATA TX_STATUS: %08x\n", txs); - } else { - wl_txstatus_additional_info_t tx_add_info; - memcpy(&tx_add_info, tlv_v + sizeof(uint32), - sizeof(wl_txstatus_additional_info_t)); - printf("METADATA TX_STATUS: %08x WLFCTS[%04x | %08x - %08x - %08x]" - " rate = %08x tries = %d - %d\n", txs, - tx_add_info.seq, tx_add_info.entry_ts, - tx_add_info.enq_ts, tx_add_info.last_ts, - tx_add_info.rspec, tx_add_info.rts_cnt, - tx_add_info.tx_cnt); - } - } break; - - case WLFC_CTL_TYPE_RSSI: { - if (tlv_l == 1) - printf("METADATA RX_RSSI: rssi = %d\n", *tlv_v); - else - printf("METADATA RX_RSSI[%04x]: rssi = %d snr = %d\n", - (*(tlv_v + 3) << 8) | *(tlv_v + 2), - (int8)(*tlv_v), *(tlv_v + 1)); - } break; - - case WLFC_CTL_TYPE_FIFO_CREDITBACK: - bcm_print_bytes("METADATA FIFO_CREDITBACK", tlv_v, tlv_l); - break; - - case WLFC_CTL_TYPE_TX_ENTRY_STAMP: - bcm_print_bytes("METADATA TX_ENTRY", tlv_v, tlv_l); - break; - - case WLFC_CTL_TYPE_RX_STAMP: { - struct { - uint32 rspec; - uint32 bus_time; - uint32 wlan_time; - } rx_tmstamp; - memcpy(&rx_tmstamp, tlv_v, sizeof(rx_tmstamp)); - printf("METADATA RX TIMESTMAP: WLFCTS[%08x - %08x] rate = %08x\n", - rx_tmstamp.wlan_time, rx_tmstamp.bus_time, rx_tmstamp.rspec); - } break; - - case WLFC_CTL_TYPE_TRANS_ID: - bcm_print_bytes("METADATA TRANS_ID", tlv_v, tlv_l); - break; - - case WLFC_CTL_TYPE_COMP_TXSTATUS: - bcm_print_bytes("METADATA COMP_TXSTATUS", tlv_v, tlv_l); - break; - - default: - bcm_print_bytes("METADATA UNKNOWN", tlv_v, tlv_l); - break; - } - - len -= tlv_l; - tlv_v += tlv_l; - } -} -#endif /* DHD_DBG_SHOW_METADATA */ - -static INLINE void BCMFASTPATH -dhd_prot_packet_free(dhd_pub_t *dhd, void *pkt, uint8 pkttype, bool send) -{ - if (pkt) { - if (pkttype == PKTTYPE_IOCTL_RX || - pkttype == PKTTYPE_EVENT_RX || - pkttype == PKTTYPE_INFO_RX || - pkttype == PKTTYPE_TSBUF_RX) { -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhd->osh, pkt, send); -#else - PKTFREE(dhd->osh, pkt, send); -#endif /* DHD_USE_STATIC_CTRLBUF */ - } else { - PKTFREE(dhd->osh, pkt, send); - } - } -} - -/* dhd_prot_packet_get should be called only for items having pktid_ctrl_map handle */ -static INLINE void * BCMFASTPATH -dhd_prot_packet_get(dhd_pub_t *dhd, uint32 pktid, uint8 pkttype, bool free_pktid) -{ - void *PKTBUF; - dmaaddr_t pa; - uint32 len; - void *dmah; - void *secdma; - -#ifdef DHD_PCIE_PKTID - if (free_pktid) { - PKTBUF = DHD_PKTID_TO_NATIVE(dhd, dhd->prot->pktid_ctrl_map, - pktid, pa, len, dmah, secdma, pkttype); - } else { - PKTBUF = DHD_PKTID_TO_NATIVE_RSV(dhd, dhd->prot->pktid_ctrl_map, - pktid, pa, len, dmah, secdma, pkttype); - } -#else - PKTBUF = DHD_PKTID_TO_NATIVE(dhd, dhd->prot->pktid_ctrl_map, pktid, pa, - len, dmah, secdma, pkttype); -#endif /* DHD_PCIE_PKTID */ - if (PKTBUF) { - { - if (SECURE_DMA_ENAB(dhd->osh)) - SECURE_DMA_UNMAP(dhd->osh, pa, (uint) len, DMA_RX, 0, dmah, - secdma, 0); - else - DMA_UNMAP(dhd->osh, pa, (uint) len, DMA_RX, 0, dmah); -#ifdef DMAMAP_STATS - switch (pkttype) { -#ifndef IOCTLRESP_USE_CONSTMEM - case PKTTYPE_IOCTL_RX: - dhd->dma_stats.ioctl_rx--; - dhd->dma_stats.ioctl_rx_sz -= len; - break; -#endif /* IOCTLRESP_USE_CONSTMEM */ - case PKTTYPE_EVENT_RX: - dhd->dma_stats.event_rx--; - dhd->dma_stats.event_rx_sz -= len; - break; - case PKTTYPE_INFO_RX: - dhd->dma_stats.info_rx--; - dhd->dma_stats.info_rx_sz -= len; - break; - case PKTTYPE_TSBUF_RX: - dhd->dma_stats.tsbuf_rx--; - dhd->dma_stats.tsbuf_rx_sz -= len; - break; - } -#endif /* DMAMAP_STATS */ - } - } - - return PKTBUF; -} - -#ifdef IOCTLRESP_USE_CONSTMEM -static INLINE void BCMFASTPATH -dhd_prot_ioctl_ret_buffer_get(dhd_pub_t *dhd, uint32 pktid, dhd_dma_buf_t *retbuf) -{ - memset(retbuf, 0, sizeof(dhd_dma_buf_t)); - retbuf->va = DHD_PKTID_TO_NATIVE(dhd, dhd->prot->pktid_map_handle_ioctl, pktid, - retbuf->pa, retbuf->len, retbuf->dmah, retbuf->secdma, PKTTYPE_IOCTL_RX); - - return; -} -#endif - -#ifdef PCIE_INB_DW -static int -dhd_prot_inc_hostactive_devwake_assert(dhd_bus_t *bus) -{ - unsigned long flags = 0; - - if (INBAND_DW_ENAB(bus)) { - DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); - bus->host_active_cnt++; - DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); - if (dhd_bus_set_device_wake(bus, TRUE) != BCME_OK) { - DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); - bus->host_active_cnt--; - dhd_bus_inb_ack_pending_ds_req(bus); - DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); - return BCME_ERROR; - } - } - - return BCME_OK; -} - -static void -dhd_prot_dec_hostactive_ack_pending_dsreq(dhd_bus_t *bus) -{ - unsigned long flags = 0; - if (INBAND_DW_ENAB(bus)) { - DHD_BUS_INB_DW_LOCK(bus->inb_lock, flags); - bus->host_active_cnt--; - dhd_bus_inb_ack_pending_ds_req(bus); - DHD_BUS_INB_DW_UNLOCK(bus->inb_lock, flags); - } -} -#endif /* PCIE_INB_DW */ - -static void BCMFASTPATH -dhd_msgbuf_rxbuf_post(dhd_pub_t *dhd, bool use_rsv_pktid) -{ - dhd_prot_t *prot = dhd->prot; - int16 fillbufs; - uint16 cnt = 256; - int retcount = 0; - - fillbufs = prot->max_rxbufpost - prot->rxbufpost; - while (fillbufs >= RX_BUF_BURST) { - cnt--; - if (cnt == 0) { - /* find a better way to reschedule rx buf post if space not available */ - DHD_ERROR(("h2d rx post ring not available to post host buffers \n")); - DHD_ERROR(("Current posted host buf count %d \n", prot->rxbufpost)); - break; - } - - /* Post in a burst of 32 buffers at a time */ - fillbufs = MIN(fillbufs, RX_BUF_BURST); - - /* Post buffers */ - retcount = dhd_prot_rxbuf_post(dhd, fillbufs, use_rsv_pktid); - - if (retcount >= 0) { - prot->rxbufpost += (uint16)retcount; -#ifdef DHD_LB_RXC - /* dhd_prot_rxbuf_post returns the number of buffers posted */ - DHD_LB_STATS_UPDATE_RXC_HISTO(dhd, retcount); -#endif /* DHD_LB_RXC */ - /* how many more to post */ - fillbufs = prot->max_rxbufpost - prot->rxbufpost; - } else { - /* Make sure we don't run loop any further */ - fillbufs = 0; - } - } -} - -/** Post 'count' no of rx buffers to dongle */ -static int BCMFASTPATH -dhd_prot_rxbuf_post(dhd_pub_t *dhd, uint16 count, bool use_rsv_pktid) -{ - void *p, **pktbuf; - uint16 pktsz = DHD_FLOWRING_RX_BUFPOST_PKTSZ; - uint8 *rxbuf_post_tmp; - host_rxbuf_post_t *rxbuf_post; - void *msg_start; - dmaaddr_t pa, *pktbuf_pa; - uint32 *pktlen; - uint16 i = 0, alloced = 0; - unsigned long flags; - uint32 pktid; - dhd_prot_t *prot = dhd->prot; - msgbuf_ring_t *ring = &prot->h2dring_rxp_subn; - void *lcl_buf; - uint16 lcl_buf_size; - -#ifdef PCIE_INB_DW - if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) - return BCME_ERROR; -#endif /* PCIE_INB_DW */ - - /* allocate a local buffer to store pkt buffer va, pa and length */ - lcl_buf_size = (sizeof(void *) + sizeof(dmaaddr_t) + sizeof(uint32)) * - RX_BUF_BURST; - lcl_buf = MALLOC(dhd->osh, lcl_buf_size); - if (!lcl_buf) { - DHD_ERROR(("%s: local scratch buffer allocation failed\n", __FUNCTION__)); -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - return 0; - } - pktbuf = lcl_buf; - pktbuf_pa = (dmaaddr_t *)((uint8 *)pktbuf + sizeof(void *) * RX_BUF_BURST); - pktlen = (uint32 *)((uint8 *)pktbuf_pa + sizeof(dmaaddr_t) * RX_BUF_BURST); - - for (i = 0; i < count; i++) { - if ((p = PKTGET(dhd->osh, pktsz, FALSE)) == NULL) { - DHD_ERROR(("%s:%d: PKTGET for rxbuf failed\n", __FUNCTION__, __LINE__)); - dhd->rx_pktgetfail++; - break; - } - - pktlen[i] = PKTLEN(dhd->osh, p); - if (SECURE_DMA_ENAB(dhd->osh)) { - pa = SECURE_DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen[i], - DMA_RX, p, 0, ring->dma_buf.secdma, 0); - } -#ifndef BCM_SECURE_DMA - else - pa = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen[i], DMA_RX, p, 0); -#endif /* #ifndef BCM_SECURE_DMA */ - - if (PHYSADDRISZERO(pa)) { - PKTFREE(dhd->osh, p, FALSE); - DHD_ERROR(("Invalid phyaddr 0\n")); - ASSERT(0); - break; - } -#ifdef DMAMAP_STATS - dhd->dma_stats.rxdata++; - dhd->dma_stats.rxdata_sz += pktlen[i]; -#endif /* DMAMAP_STATS */ - - PKTPULL(dhd->osh, p, prot->rx_metadata_offset); - pktlen[i] = PKTLEN(dhd->osh, p); - pktbuf[i] = p; - pktbuf_pa[i] = pa; - } - - /* only post what we have */ - count = i; - - /* grab the rx lock to allocate pktid and post on ring */ - DHD_SPIN_LOCK(prot->rx_lock, flags); - - /* Claim space for exactly 'count' no of messages, for mitigation purpose */ - msg_start = (void *) - dhd_prot_alloc_ring_space(dhd, ring, count, &alloced, TRUE); - if (msg_start == NULL) { - DHD_INFO(("%s:%d: Rxbufpost Msgbuf Not available\n", __FUNCTION__, __LINE__)); - goto cleanup; - } - /* if msg_start != NULL, we should have alloced space for atleast 1 item */ - ASSERT(alloced > 0); - - rxbuf_post_tmp = (uint8*)msg_start; - - for (i = 0; i < alloced; i++) { - rxbuf_post = (host_rxbuf_post_t *)rxbuf_post_tmp; - p = pktbuf[i]; - pa = pktbuf_pa[i]; - -#if defined(DHD_LB_RXC) - if (use_rsv_pktid == TRUE) { - bcm_workq_t *workq = &prot->rx_compl_cons; - int elem_ix = bcm_ring_cons(WORKQ_RING(workq), DHD_LB_WORKQ_SZ); - - if (elem_ix == BCM_RING_EMPTY) { - DHD_INFO(("%s rx_compl_cons ring is empty\n", __FUNCTION__)); - pktid = DHD_PKTID_INVALID; - goto alloc_pkt_id; - } else { - uint32 *elem = WORKQ_ELEMENT(uint32, workq, elem_ix); - pktid = *elem; - } - - rxbuf_post->cmn_hdr.request_id = htol32(pktid); - - /* Now populate the previous locker with valid information */ - if (pktid != DHD_PKTID_INVALID) { - DHD_NATIVE_TO_PKTID_SAVE(dhd, dhd->prot->pktid_rx_map, - p, pktid, pa, pktlen[i], DMA_RX, NULL, NULL, - PKTTYPE_DATA_RX); - } - } else -#endif /* ! DHD_LB_RXC */ - { -#if defined(DHD_LB_RXC) -alloc_pkt_id: -#endif /* DHD_LB_RXC */ - pktid = DHD_NATIVE_TO_PKTID(dhd, dhd->prot->pktid_rx_map, p, pa, - pktlen[i], DMA_RX, NULL, ring->dma_buf.secdma, PKTTYPE_DATA_RX); -#if defined(DHD_PCIE_PKTID) - if (pktid == DHD_PKTID_INVALID) { - break; - } -#endif /* DHD_PCIE_PKTID */ - } - - /* Common msg header */ - rxbuf_post->cmn_hdr.msg_type = MSG_TYPE_RXBUF_POST; - rxbuf_post->cmn_hdr.if_id = 0; - rxbuf_post->cmn_hdr.epoch = ring->seqnum % H2D_EPOCH_MODULO; - rxbuf_post->cmn_hdr.flags = ring->current_phase; - ring->seqnum++; - rxbuf_post->data_buf_len = htol16((uint16)pktlen[i]); - rxbuf_post->data_buf_addr.high_addr = htol32(PHYSADDRHI(pa)); - rxbuf_post->data_buf_addr.low_addr = - htol32(PHYSADDRLO(pa) + prot->rx_metadata_offset); - - if (prot->rx_metadata_offset) { - rxbuf_post->metadata_buf_len = prot->rx_metadata_offset; - rxbuf_post->metadata_buf_addr.high_addr = htol32(PHYSADDRHI(pa)); - rxbuf_post->metadata_buf_addr.low_addr = htol32(PHYSADDRLO(pa)); - } else { - rxbuf_post->metadata_buf_len = 0; - rxbuf_post->metadata_buf_addr.high_addr = 0; - rxbuf_post->metadata_buf_addr.low_addr = 0; - } - -#ifdef DHD_PKTID_AUDIT_RING - DHD_PKTID_AUDIT(dhd, prot->pktid_rx_map, pktid, DHD_DUPLICATE_ALLOC); -#endif /* DHD_PKTID_AUDIT_RING */ - - rxbuf_post->cmn_hdr.request_id = htol32(pktid); - - /* Move rxbuf_post_tmp to next item */ - rxbuf_post_tmp = rxbuf_post_tmp + ring->item_len; - } - - if (i < alloced) { - if (ring->wr < (alloced - i)) - ring->wr = ring->max_items - (alloced - i); - else - ring->wr -= (alloced - i); - - if (ring->wr == 0) { - DHD_INFO(("%s: flipping the phase now\n", ring->name)); - ring->current_phase = ring->current_phase ? - 0 : BCMPCIE_CMNHDR_PHASE_BIT_INIT; - } - - alloced = i; - } - - /* update ring's WR index and ring doorbell to dongle */ - if (alloced > 0) { - unsigned long flags1; - DHD_GENERAL_LOCK(dhd, flags1); - dhd_prot_ring_write_complete(dhd, ring, msg_start, alloced); - DHD_GENERAL_UNLOCK(dhd, flags1); - } - - DHD_SPIN_UNLOCK(prot->rx_lock, flags); - -cleanup: - for (i = alloced; i < count; i++) { - p = pktbuf[i]; - pa = pktbuf_pa[i]; - - if (SECURE_DMA_ENAB(dhd->osh)) - SECURE_DMA_UNMAP(dhd->osh, pa, pktlen[i], DMA_RX, 0, - DHD_DMAH_NULL, ring->dma_buf.secdma, 0); - else - DMA_UNMAP(dhd->osh, pa, pktlen[i], DMA_RX, 0, DHD_DMAH_NULL); - PKTFREE(dhd->osh, p, FALSE); - } - - MFREE(dhd->osh, lcl_buf, lcl_buf_size); -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - return alloced; -} /* dhd_prot_rxbufpost */ - -static int -dhd_prot_infobufpost(dhd_pub_t *dhd) -{ - unsigned long flags; - uint32 pktid; - dhd_prot_t *prot = dhd->prot; - msgbuf_ring_t *ring = prot->h2dring_info_subn; - uint16 alloced = 0; - uint16 pktsz = DHD_FLOWRING_RX_BUFPOST_PKTSZ; - uint32 pktlen; - info_buf_post_msg_t *infobuf_post; - uint8 *infobuf_post_tmp; - void *p; - void* msg_start; - uint8 i = 0; - dmaaddr_t pa; - int16 count; - - if (ring == NULL) - return 0; - - if (ring->inited != TRUE) - return 0; - if (prot->max_infobufpost == 0) - return 0; - - count = prot->max_infobufpost - prot->infobufpost; - - if (count <= 0) { - DHD_INFO(("%s: Cannot post more than max info resp buffers\n", - __FUNCTION__)); - return 0; - } - -#ifdef PCIE_INB_DW - if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) - return BCME_ERROR; -#endif /* PCIE_INB_DW */ - - DHD_GENERAL_LOCK(dhd, flags); - /* Claim space for exactly 'count' no of messages, for mitigation purpose */ - msg_start = (void *) dhd_prot_alloc_ring_space(dhd, ring, count, &alloced, FALSE); - DHD_GENERAL_UNLOCK(dhd, flags); - - if (msg_start == NULL) { - DHD_INFO(("%s:%d: infobufpost Msgbuf Not available\n", __FUNCTION__, __LINE__)); -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - return -1; - } - - /* if msg_start != NULL, we should have alloced space for atleast 1 item */ - ASSERT(alloced > 0); - - infobuf_post_tmp = (uint8*) msg_start; - - /* loop through each allocated message in the host ring */ - for (i = 0; i < alloced; i++) { - infobuf_post = (info_buf_post_msg_t *) infobuf_post_tmp; - /* Create a rx buffer */ -#ifdef DHD_USE_STATIC_CTRLBUF - p = PKTGET_STATIC(dhd->osh, pktsz, FALSE); -#else - p = PKTGET(dhd->osh, pktsz, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ - if (p == NULL) { - DHD_ERROR(("%s:%d: PKTGET for infobuf failed\n", __FUNCTION__, __LINE__)); - dhd->rx_pktgetfail++; - break; - } - pktlen = PKTLEN(dhd->osh, p); - if (SECURE_DMA_ENAB(dhd->osh)) { - pa = SECURE_DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, - DMA_RX, p, 0, ring->dma_buf.secdma, 0); - } -#ifndef BCM_SECURE_DMA - else - pa = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, DMA_RX, p, 0); -#endif /* #ifndef BCM_SECURE_DMA */ - if (PHYSADDRISZERO(pa)) { - if (SECURE_DMA_ENAB(dhd->osh)) { - SECURE_DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, DHD_DMAH_NULL, - ring->dma_buf.secdma, 0); - } - else - DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, DHD_DMAH_NULL); -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhd->osh, p, FALSE); -#else - PKTFREE(dhd->osh, p, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ - DHD_ERROR(("Invalid phyaddr 0\n")); - ASSERT(0); - break; - } -#ifdef DMAMAP_STATS - dhd->dma_stats.info_rx++; - dhd->dma_stats.info_rx_sz += pktlen; -#endif /* DMAMAP_STATS */ - pktlen = PKTLEN(dhd->osh, p); - - /* Common msg header */ - infobuf_post->cmn_hdr.msg_type = MSG_TYPE_INFO_BUF_POST; - infobuf_post->cmn_hdr.if_id = 0; - infobuf_post->cmn_hdr.epoch = ring->seqnum % H2D_EPOCH_MODULO; - infobuf_post->cmn_hdr.flags = ring->current_phase; - ring->seqnum++; - -#if defined(DHD_PCIE_PKTID) - /* get the lock before calling DHD_NATIVE_TO_PKTID */ - DHD_GENERAL_LOCK(dhd, flags); -#endif /* DHD_PCIE_PKTID */ - - pktid = DHD_NATIVE_TO_PKTID(dhd, dhd->prot->pktid_ctrl_map, p, pa, - pktlen, DMA_RX, NULL, ring->dma_buf.secdma, PKTTYPE_INFO_RX); - - -#if defined(DHD_PCIE_PKTID) - /* free lock */ - DHD_GENERAL_UNLOCK(dhd, flags); - - if (pktid == DHD_PKTID_INVALID) { - if (SECURE_DMA_ENAB(dhd->osh)) { - DHD_GENERAL_LOCK(dhd, flags); - SECURE_DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, 0, - ring->dma_buf.secdma, 0); - DHD_GENERAL_UNLOCK(dhd, flags); - } else - DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, 0); - -#ifdef DHD_USE_STATIC_CTRLBUF - PKTFREE_STATIC(dhd->osh, p, FALSE); -#else - PKTFREE(dhd->osh, p, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ - DHD_ERROR(("%s: Pktid pool depleted.\n", __FUNCTION__)); - break; - } -#endif /* DHD_PCIE_PKTID */ - - infobuf_post->host_buf_len = htol16((uint16)pktlen); - infobuf_post->host_buf_addr.high_addr = htol32(PHYSADDRHI(pa)); - infobuf_post->host_buf_addr.low_addr = htol32(PHYSADDRLO(pa)); - -#ifdef DHD_PKTID_AUDIT_RING - DHD_PKTID_AUDIT(dhd, prot->pktid_ctrl_map, pktid, DHD_DUPLICATE_ALLOC); -#endif /* DHD_PKTID_AUDIT_RING */ - - DHD_INFO(("ID %d, low_addr 0x%08x, high_addr 0x%08x\n", - infobuf_post->cmn_hdr.request_id, infobuf_post->host_buf_addr.low_addr, - infobuf_post->host_buf_addr.high_addr)); - - infobuf_post->cmn_hdr.request_id = htol32(pktid); - /* Move rxbuf_post_tmp to next item */ - infobuf_post_tmp = infobuf_post_tmp + ring->item_len; - } - - if (i < alloced) { - if (ring->wr < (alloced - i)) - ring->wr = ring->max_items - (alloced - i); - else - ring->wr -= (alloced - i); - - alloced = i; - if (alloced && ring->wr == 0) { - DHD_INFO(("%s: flipping the phase now\n", ring->name)); - ring->current_phase = ring->current_phase ? - 0 : BCMPCIE_CMNHDR_PHASE_BIT_INIT; - } - } - - /* Update the write pointer in TCM & ring bell */ - if (alloced > 0) { - prot->infobufpost += alloced; - DHD_INFO(("allocated %d buffers for info ring\n", alloced)); - DHD_GENERAL_LOCK(dhd, flags); - dhd_prot_ring_write_complete(dhd, ring, msg_start, alloced); - DHD_GENERAL_UNLOCK(dhd, flags); - } -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - return alloced; -} /* dhd_prot_infobufpost */ - -#ifdef IOCTLRESP_USE_CONSTMEM -static int -alloc_ioctl_return_buffer(dhd_pub_t *dhd, dhd_dma_buf_t *retbuf) -{ - int err; - memset(retbuf, 0, sizeof(dhd_dma_buf_t)); - - if ((err = dhd_dma_buf_alloc(dhd, retbuf, IOCT_RETBUF_SIZE)) != BCME_OK) { - DHD_ERROR(("%s: dhd_dma_buf_alloc err %d\n", __FUNCTION__, err)); - ASSERT(0); - return BCME_NOMEM; - } - - return BCME_OK; -} - -static void -free_ioctl_return_buffer(dhd_pub_t *dhd, dhd_dma_buf_t *retbuf) -{ - /* retbuf (declared on stack) not fully populated ... */ - if (retbuf->va) { - uint32 dma_pad; - dma_pad = (IOCT_RETBUF_SIZE % DHD_DMA_PAD) ? DHD_DMA_PAD : 0; - retbuf->len = IOCT_RETBUF_SIZE; - retbuf->_alloced = retbuf->len + dma_pad; - } - - dhd_dma_buf_free(dhd, retbuf); - return; -} -#endif /* IOCTLRESP_USE_CONSTMEM */ - -static int -dhd_prot_rxbufpost_ctrl(dhd_pub_t *dhd, uint8 msg_type) -{ - void *p; - uint16 pktsz; - ioctl_resp_evt_buf_post_msg_t *rxbuf_post; - dmaaddr_t pa; - uint32 pktlen; - dhd_prot_t *prot = dhd->prot; - uint16 alloced = 0; - unsigned long flags; - dhd_dma_buf_t retbuf; - void *dmah = NULL; - uint32 pktid; - void *map_handle; - msgbuf_ring_t *ring = &prot->h2dring_ctrl_subn; - bool non_ioctl_resp_buf = 0; - dhd_pkttype_t buf_type; - - if (dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__)); - return -1; - } - memset(&retbuf, 0, sizeof(dhd_dma_buf_t)); - - if (msg_type == MSG_TYPE_IOCTLRESP_BUF_POST) - buf_type = PKTTYPE_IOCTL_RX; - else if (msg_type == MSG_TYPE_EVENT_BUF_POST) - buf_type = PKTTYPE_EVENT_RX; - else if (msg_type == MSG_TYPE_TIMSTAMP_BUFPOST) - buf_type = PKTTYPE_TSBUF_RX; - else { - DHD_ERROR(("invalid message type to be posted to Ctrl ring %d\n", msg_type)); - return -1; - } - - - if ((msg_type == MSG_TYPE_EVENT_BUF_POST) || (msg_type == MSG_TYPE_TIMSTAMP_BUFPOST)) - non_ioctl_resp_buf = TRUE; - else - non_ioctl_resp_buf = FALSE; - - if (non_ioctl_resp_buf) { - /* Allocate packet for not ioctl resp buffer post */ - pktsz = DHD_FLOWRING_RX_BUFPOST_PKTSZ; - } else { - /* Allocate packet for ctrl/ioctl buffer post */ - pktsz = DHD_FLOWRING_IOCTL_BUFPOST_PKTSZ; - } - -#ifdef IOCTLRESP_USE_CONSTMEM - if (!non_ioctl_resp_buf) { - if (alloc_ioctl_return_buffer(dhd, &retbuf) != BCME_OK) { - DHD_ERROR(("Could not allocate IOCTL response buffer\n")); - return -1; - } - ASSERT(retbuf.len == IOCT_RETBUF_SIZE); - p = retbuf.va; - pktlen = retbuf.len; - pa = retbuf.pa; - dmah = retbuf.dmah; - } else -#endif /* IOCTLRESP_USE_CONSTMEM */ - { -#ifdef DHD_USE_STATIC_CTRLBUF - p = PKTGET_STATIC(dhd->osh, pktsz, FALSE); -#else - p = PKTGET(dhd->osh, pktsz, FALSE); -#endif /* DHD_USE_STATIC_CTRLBUF */ - if (p == NULL) { - DHD_ERROR(("%s:%d: PKTGET for %s buf failed\n", - __FUNCTION__, __LINE__, non_ioctl_resp_buf ? - "EVENT" : "IOCTL RESP")); - dhd->rx_pktgetfail++; - return -1; - } - - pktlen = PKTLEN(dhd->osh, p); - - if (SECURE_DMA_ENAB(dhd->osh)) { - DHD_GENERAL_LOCK(dhd, flags); - pa = SECURE_DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, - DMA_RX, p, 0, ring->dma_buf.secdma, 0); - DHD_GENERAL_UNLOCK(dhd, flags); - } -#ifndef BCM_SECURE_DMA - else - pa = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, p), pktlen, DMA_RX, p, 0); -#endif /* #ifndef BCM_SECURE_DMA */ - - if (PHYSADDRISZERO(pa)) { - DHD_ERROR(("Invalid physaddr 0\n")); - ASSERT(0); - goto free_pkt_return; - } - -#ifdef DMAMAP_STATS - switch (buf_type) { -#ifndef IOCTLRESP_USE_CONSTMEM - case PKTTYPE_IOCTL_RX: - dhd->dma_stats.ioctl_rx++; - dhd->dma_stats.ioctl_rx_sz += pktlen; - break; -#endif /* !IOCTLRESP_USE_CONSTMEM */ - case PKTTYPE_EVENT_RX: - dhd->dma_stats.event_rx++; - dhd->dma_stats.event_rx_sz += pktlen; - break; - case PKTTYPE_TSBUF_RX: - dhd->dma_stats.tsbuf_rx++; - dhd->dma_stats.tsbuf_rx_sz += pktlen; - break; - default: - break; - } -#endif /* DMAMAP_STATS */ - - } -#ifdef PCIE_INB_DW - if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) - return BCME_ERROR; -#endif /* PCIE_INB_DW */ - - DHD_GENERAL_LOCK(dhd, flags); - - rxbuf_post = (ioctl_resp_evt_buf_post_msg_t *) - dhd_prot_alloc_ring_space(dhd, ring, 1, &alloced, FALSE); - - if (rxbuf_post == NULL) { - DHD_GENERAL_UNLOCK(dhd, flags); - DHD_ERROR(("%s:%d: Ctrl submit Msgbuf Not available to post buffer \n", - __FUNCTION__, __LINE__)); - -#ifdef IOCTLRESP_USE_CONSTMEM - if (non_ioctl_resp_buf) -#endif /* IOCTLRESP_USE_CONSTMEM */ - { - if (SECURE_DMA_ENAB(dhd->osh)) { - DHD_GENERAL_LOCK(dhd, flags); - SECURE_DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, DHD_DMAH_NULL, - ring->dma_buf.secdma, 0); - DHD_GENERAL_UNLOCK(dhd, flags); - } else { - DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, DHD_DMAH_NULL); - } - } - goto free_pkt_return; - } - - /* CMN msg header */ - rxbuf_post->cmn_hdr.msg_type = msg_type; - -#ifdef IOCTLRESP_USE_CONSTMEM - if (!non_ioctl_resp_buf) { - map_handle = dhd->prot->pktid_map_handle_ioctl; - pktid = DHD_NATIVE_TO_PKTID(dhd, map_handle, p, pa, pktlen, DMA_RX, dmah, - ring->dma_buf.secdma, buf_type); - } else -#endif /* IOCTLRESP_USE_CONSTMEM */ - { - map_handle = dhd->prot->pktid_ctrl_map; - pktid = DHD_NATIVE_TO_PKTID(dhd, map_handle, - p, pa, pktlen, DMA_RX, dmah, ring->dma_buf.secdma, - buf_type); - } - - if (pktid == DHD_PKTID_INVALID) { - if (ring->wr == 0) { - ring->wr = ring->max_items - 1; - } else { - ring->wr--; - if (ring->wr == 0) { - ring->current_phase = ring->current_phase ? 0 : - BCMPCIE_CMNHDR_PHASE_BIT_INIT; - } - } - DHD_GENERAL_UNLOCK(dhd, flags); - DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, DHD_DMAH_NULL); - DHD_ERROR(("%s: Pktid pool depleted.\n", __FUNCTION__)); - goto free_pkt_return; - } - -#ifdef DHD_PKTID_AUDIT_RING - DHD_PKTID_AUDIT(dhd, map_handle, pktid, DHD_DUPLICATE_ALLOC); -#endif /* DHD_PKTID_AUDIT_RING */ - - rxbuf_post->cmn_hdr.request_id = htol32(pktid); - rxbuf_post->cmn_hdr.if_id = 0; - rxbuf_post->cmn_hdr.epoch = ring->seqnum % H2D_EPOCH_MODULO; - ring->seqnum++; - rxbuf_post->cmn_hdr.flags = ring->current_phase; - -#if defined(DHD_PCIE_PKTID) - if (rxbuf_post->cmn_hdr.request_id == DHD_PKTID_INVALID) { - if (ring->wr == 0) { - ring->wr = ring->max_items - 1; - } else { - if (ring->wr == 0) { - ring->current_phase = ring->current_phase ? 0 : - BCMPCIE_CMNHDR_PHASE_BIT_INIT; - } - } - DHD_GENERAL_UNLOCK(dhd, flags); -#ifdef IOCTLRESP_USE_CONSTMEM - if (non_ioctl_resp_buf) -#endif /* IOCTLRESP_USE_CONSTMEM */ - { - if (SECURE_DMA_ENAB(dhd->osh)) { - DHD_GENERAL_LOCK(dhd, flags); - SECURE_DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, DHD_DMAH_NULL, - ring->dma_buf.secdma, 0); - DHD_GENERAL_UNLOCK(dhd, flags); - } else - DMA_UNMAP(dhd->osh, pa, pktlen, DMA_RX, 0, DHD_DMAH_NULL); - } - goto free_pkt_return; - } -#endif /* DHD_PCIE_PKTID */ - -#ifndef IOCTLRESP_USE_CONSTMEM - rxbuf_post->host_buf_len = htol16((uint16)PKTLEN(dhd->osh, p)); -#else - rxbuf_post->host_buf_len = htol16((uint16)pktlen); -#endif /* IOCTLRESP_USE_CONSTMEM */ - rxbuf_post->host_buf_addr.high_addr = htol32(PHYSADDRHI(pa)); - rxbuf_post->host_buf_addr.low_addr = htol32(PHYSADDRLO(pa)); - - /* update ring's WR index and ring doorbell to dongle */ - dhd_prot_ring_write_complete(dhd, ring, rxbuf_post, 1); - DHD_GENERAL_UNLOCK(dhd, flags); - -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - - return 1; - -free_pkt_return: -#ifdef IOCTLRESP_USE_CONSTMEM - if (!non_ioctl_resp_buf) { - free_ioctl_return_buffer(dhd, &retbuf); - } else -#endif - { - dhd_prot_packet_free(dhd, p, buf_type, FALSE); - } - -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - - return -1; -} /* dhd_prot_rxbufpost_ctrl */ - -static uint16 -dhd_msgbuf_rxbuf_post_ctrlpath(dhd_pub_t *dhd, uint8 msg_type, uint32 max_to_post) -{ - uint32 i = 0; - int32 ret_val; - - DHD_INFO(("max to post %d, event %d \n", max_to_post, msg_type)); - - if (dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: bus is already down.\n", __FUNCTION__)); - return 0; - } - - while (i < max_to_post) { - ret_val = dhd_prot_rxbufpost_ctrl(dhd, msg_type); - if (ret_val < 0) - break; - i++; - } - DHD_INFO(("posted %d buffers of type %d\n", i, msg_type)); - return (uint16)i; -} - -static void -dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd_pub_t *dhd) -{ - dhd_prot_t *prot = dhd->prot; - int max_to_post; - - DHD_INFO(("ioctl resp buf post\n")); - max_to_post = prot->max_ioctlrespbufpost - prot->cur_ioctlresp_bufs_posted; - if (max_to_post <= 0) { - DHD_INFO(("%s: Cannot post more than max IOCTL resp buffers\n", - __FUNCTION__)); - return; - } - prot->cur_ioctlresp_bufs_posted += dhd_msgbuf_rxbuf_post_ctrlpath(dhd, - MSG_TYPE_IOCTLRESP_BUF_POST, max_to_post); -} - -static void -dhd_msgbuf_rxbuf_post_event_bufs(dhd_pub_t *dhd) -{ - dhd_prot_t *prot = dhd->prot; - int max_to_post; - - /* Use atomic variable to avoid re-entry */ - if (atomic_read(&dhd_msgbuf_rxbuf_post_event_bufs_running) > 0) { - return; - } - atomic_inc(&dhd_msgbuf_rxbuf_post_event_bufs_running); - - max_to_post = prot->max_eventbufpost - prot->cur_event_bufs_posted; - if (max_to_post <= 0) { - DHD_ERROR(("%s: Cannot post more than max event buffers\n", - __FUNCTION__)); - return; - } - prot->cur_event_bufs_posted += dhd_msgbuf_rxbuf_post_ctrlpath(dhd, - MSG_TYPE_EVENT_BUF_POST, max_to_post); - - atomic_dec(&dhd_msgbuf_rxbuf_post_event_bufs_running); -} - -static int -dhd_msgbuf_rxbuf_post_ts_bufs(dhd_pub_t *dhd) -{ -#ifdef DHD_TIMESYNC - dhd_prot_t *prot = dhd->prot; - int max_to_post; - - if (prot->active_ipc_version < 7) { - DHD_ERROR(("no ts buffers to device ipc rev is %d, needs to be atleast 7\n", - prot->active_ipc_version)); - return 0; - } - - max_to_post = prot->max_tsbufpost - prot->cur_ts_bufs_posted; - if (max_to_post <= 0) { - DHD_INFO(("%s: Cannot post more than max ts buffers\n", - __FUNCTION__)); - return 0; - } - - prot->cur_ts_bufs_posted += dhd_msgbuf_rxbuf_post_ctrlpath(dhd, - MSG_TYPE_TIMSTAMP_BUFPOST, max_to_post); -#endif /* DHD_TIMESYNC */ - return 0; -} - -bool BCMFASTPATH -dhd_prot_process_msgbuf_infocpl(dhd_pub_t *dhd, uint bound) -{ - dhd_prot_t *prot = dhd->prot; - bool more = TRUE; - uint n = 0; - msgbuf_ring_t *ring = prot->d2hring_info_cpln; - - if (ring == NULL) - return FALSE; - if (ring->inited != TRUE) - return FALSE; - - /* Process all the messages - DTOH direction */ - while (!dhd_is_device_removed(dhd)) { - uint8 *msg_addr; - uint32 msg_len; - - if (dhd->hang_was_sent) { - more = FALSE; - break; - } - - /* Get the message from ring */ - msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len); - if (msg_addr == NULL) { - more = FALSE; - break; - } - - /* Prefetch data to populate the cache */ - OSL_PREFETCH(msg_addr); - - if (dhd_prot_process_msgtype(dhd, ring, msg_addr, msg_len) != BCME_OK) { - DHD_ERROR(("%s: Error at process rxpl msgbuf of len %d\n", - __FUNCTION__, msg_len)); - } - - /* Update read pointer */ - dhd_prot_upd_read_idx(dhd, ring); - - /* After batch processing, check RX bound */ - n += msg_len / ring->item_len; - if (n >= bound) { - break; - } - } - - return more; -} - -/** called when DHD needs to check for 'receive complete' messages from the dongle */ -bool BCMFASTPATH -dhd_prot_process_msgbuf_rxcpl(dhd_pub_t *dhd, uint bound) -{ - bool more = FALSE; - uint n = 0; - dhd_prot_t *prot = dhd->prot; - msgbuf_ring_t *ring = &prot->d2hring_rx_cpln; - uint16 item_len = ring->item_len; - host_rxbuf_cmpl_t *msg = NULL; - uint8 *msg_addr; - uint32 msg_len; - uint16 pkt_cnt, pkt_cnt_newidx; - unsigned long flags; - dmaaddr_t pa; - uint32 len; - void *dmah; - void *secdma; - int ifidx = 0, if_newidx = 0; - void *pkt, *pktqhead = NULL, *prevpkt = NULL, *pkt_newidx, *nextpkt; - uint32 pktid; - int i; - uint8 sync; - - while (1) { - if (dhd_is_device_removed(dhd)) - break; - - if (dhd->hang_was_sent) - break; - - pkt_cnt = 0; - pktqhead = pkt_newidx = NULL; - pkt_cnt_newidx = 0; - - DHD_SPIN_LOCK(prot->rx_lock, flags); - - /* Get the address of the next message to be read from ring */ - msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len); - if (msg_addr == NULL) { - DHD_SPIN_UNLOCK(prot->rx_lock, flags); - break; - } - - while (msg_len > 0) { - msg = (host_rxbuf_cmpl_t *)msg_addr; - - /* Wait until DMA completes, then fetch msg_type */ - sync = prot->d2h_sync_cb(dhd, ring, &msg->cmn_hdr, item_len); - /* - * Update the curr_rd to the current index in the ring, from where - * the work item is fetched. This way if the fetched work item - * fails in LIVELOCK, we can print the exact read index in the ring - * that shows up the corrupted work item. - */ - if ((ring->curr_rd + 1) >= ring->max_items) { - ring->curr_rd = 0; - } else { - ring->curr_rd += 1; - } - - if (!sync) { - msg_len -= item_len; - msg_addr += item_len; - continue; - } - - pktid = ltoh32(msg->cmn_hdr.request_id); - -#ifdef DHD_PKTID_AUDIT_RING - DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_rx_map, pktid, - DHD_DUPLICATE_FREE, msg, D2HRING_RXCMPLT_ITEMSIZE); -#endif /* DHD_PKTID_AUDIT_RING */ - - pkt = DHD_PKTID_TO_NATIVE(dhd, prot->pktid_rx_map, pktid, pa, - len, dmah, secdma, PKTTYPE_DATA_RX); - if (!pkt) { - msg_len -= item_len; - msg_addr += item_len; - continue; - } - - if (SECURE_DMA_ENAB(dhd->osh)) - SECURE_DMA_UNMAP(dhd->osh, pa, (uint) len, DMA_RX, 0, - dmah, secdma, 0); - else - DMA_UNMAP(dhd->osh, pa, (uint) len, DMA_RX, 0, dmah); - -#ifdef DMAMAP_STATS - dhd->dma_stats.rxdata--; - dhd->dma_stats.rxdata_sz -= len; -#endif /* DMAMAP_STATS */ - DHD_INFO(("id 0x%04x, offset %d, len %d, idx %d, phase 0x%02x, " - "pktdata %p, metalen %d\n", - ltoh32(msg->cmn_hdr.request_id), - ltoh16(msg->data_offset), - ltoh16(msg->data_len), msg->cmn_hdr.if_id, - msg->cmn_hdr.flags, PKTDATA(dhd->osh, pkt), - ltoh16(msg->metadata_len))); - - pkt_cnt++; - msg_len -= item_len; - msg_addr += item_len; - -#if DHD_DBG_SHOW_METADATA - if (prot->metadata_dbg && prot->rx_metadata_offset && - msg->metadata_len) { - uchar *ptr; - ptr = PKTDATA(dhd->osh, pkt) - (prot->rx_metadata_offset); - /* header followed by data */ - bcm_print_bytes("rxmetadata", ptr, msg->metadata_len); - dhd_prot_print_metadata(dhd, ptr, msg->metadata_len); - } -#endif /* DHD_DBG_SHOW_METADATA */ - - /* data_offset from buf start */ - if (ltoh16(msg->data_offset)) { - /* data offset given from dongle after split rx */ - PKTPULL(dhd->osh, pkt, ltoh16(msg->data_offset)); - } - else if (prot->rx_dataoffset) { - /* DMA RX offset updated through shared area */ - PKTPULL(dhd->osh, pkt, prot->rx_dataoffset); - } - /* Actual length of the packet */ - PKTSETLEN(dhd->osh, pkt, ltoh16(msg->data_len)); -#if defined(WL_MONITOR) - if (dhd_monitor_enabled(dhd, ifidx) && - (msg->flags & BCMPCIE_PKT_FLAGS_FRAME_802_11)) { - dhd_rx_mon_pkt(dhd, msg, pkt, ifidx); - continue; - } -#endif - - if (!pktqhead) { - pktqhead = prevpkt = pkt; - ifidx = msg->cmn_hdr.if_id; - } else { - if (ifidx != msg->cmn_hdr.if_id) { - pkt_newidx = pkt; - if_newidx = msg->cmn_hdr.if_id; - pkt_cnt--; - pkt_cnt_newidx = 1; - break; - } else { - PKTSETNEXT(dhd->osh, prevpkt, pkt); - prevpkt = pkt; - } - } - -#ifdef DHD_TIMESYNC - if (dhd->prot->rx_ts_log_enabled) { - ts_timestamp_t *ts = (ts_timestamp_t *)&msg->ts; - dhd_timesync_log_rx_timestamp(dhd->ts, ifidx, ts->low, ts->high); - } -#endif /* DHD_TIMESYNC */ - } - - /* roll back read pointer for unprocessed message */ - if (msg_len > 0) { - if (ring->rd < msg_len / item_len) - ring->rd = ring->max_items - msg_len / item_len; - else - ring->rd -= msg_len / item_len; - } - - /* Update read pointer */ - dhd_prot_upd_read_idx(dhd, ring); - - DHD_SPIN_UNLOCK(prot->rx_lock, flags); - - pkt = pktqhead; - for (i = 0; pkt && i < pkt_cnt; i++, pkt = nextpkt) { - nextpkt = PKTNEXT(dhd->osh, pkt); - PKTSETNEXT(dhd->osh, pkt, NULL); -#ifdef DHD_LB_RXP - dhd_lb_rx_pkt_enqueue(dhd, pkt, ifidx); -#elif defined(DHD_RX_CHAINING) - dhd_rxchain_frame(dhd, pkt, ifidx); -#else - dhd_bus_rx_frame(dhd->bus, pkt, ifidx, 1); -#endif /* DHD_LB_RXP */ - } - - if (pkt_newidx) { -#ifdef DHD_LB_RXP - dhd_lb_rx_pkt_enqueue(dhd, pkt_newidx, if_newidx); -#elif defined(DHD_RX_CHAINING) - dhd_rxchain_frame(dhd, pkt_newidx, if_newidx); -#else - dhd_bus_rx_frame(dhd->bus, pkt_newidx, if_newidx, 1); -#endif /* DHD_LB_RXP */ - } - - pkt_cnt += pkt_cnt_newidx; - - /* Post another set of rxbufs to the device */ - dhd_prot_return_rxbuf(dhd, 0, pkt_cnt); - - /* After batch processing, check RX bound */ - n += pkt_cnt; - if (n >= bound) { - more = TRUE; - break; - } - } - - /* Call lb_dispatch only if packets are queued */ - if (n) { - DHD_LB_DISPATCH_RX_COMPL(dhd); - DHD_LB_DISPATCH_RX_PROCESS(dhd); - } - - return more; -} - -/** - * Hands transmit packets (with a caller provided flow_id) over to dongle territory (the flow ring) - */ -void -dhd_prot_update_txflowring(dhd_pub_t *dhd, uint16 flowid, void *msgring) -{ - msgbuf_ring_t *ring = (msgbuf_ring_t *)msgring; - - if (ring == NULL) { - DHD_ERROR(("%s: NULL txflowring. exiting...\n", __FUNCTION__)); - return; - } - /* Update read pointer */ - if (dhd->dma_d2h_ring_upd_support) { - ring->rd = dhd_prot_dma_indx_get(dhd, H2D_DMA_INDX_RD_UPD, ring->idx); - } - - DHD_TRACE(("ringid %d flowid %d write %d read %d \n\n", - ring->idx, flowid, ring->wr, ring->rd)); - - /* Need more logic here, but for now use it directly */ - dhd_bus_schedule_queue(dhd->bus, flowid, TRUE); /* from queue to flowring */ -} - -/** called when DHD needs to check for 'transmit complete' messages from the dongle */ -bool BCMFASTPATH -dhd_prot_process_msgbuf_txcpl(dhd_pub_t *dhd, uint bound) -{ - bool more = TRUE; - uint n = 0; - msgbuf_ring_t *ring = &dhd->prot->d2hring_tx_cpln; - - /* Process all the messages - DTOH direction */ - while (!dhd_is_device_removed(dhd)) { - uint8 *msg_addr; - uint32 msg_len; - - if (dhd->hang_was_sent) { - more = FALSE; - break; - } - - /* Get the address of the next message to be read from ring */ - msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len); - if (msg_addr == NULL) { - more = FALSE; - break; - } - - /* Prefetch data to populate the cache */ - OSL_PREFETCH(msg_addr); - - if (dhd_prot_process_msgtype(dhd, ring, msg_addr, msg_len) != BCME_OK) { - DHD_ERROR(("%s: process %s msg addr %p len %d\n", - __FUNCTION__, ring->name, msg_addr, msg_len)); - } - - /* Write to dngl rd ptr */ - dhd_prot_upd_read_idx(dhd, ring); - - /* After batch processing, check bound */ - n += msg_len / ring->item_len; - if (n >= bound) { - break; - } - } - - DHD_LB_DISPATCH_TX_COMPL(dhd); - - return more; -} - -int BCMFASTPATH -dhd_prot_process_trapbuf(dhd_pub_t *dhd) -{ - uint32 data; - dhd_dma_buf_t *trap_addr = &dhd->prot->fw_trap_buf; - - /* Interrupts can come in before this struct - * has been initialized. - */ - if (trap_addr->va == NULL) { - DHD_ERROR(("%s: trap_addr->va is NULL\n", __FUNCTION__)); - return 0; - } - - OSL_CACHE_INV((void *)trap_addr->va, sizeof(uint32)); - data = *(uint32 *)(trap_addr->va); - - if (data & D2H_DEV_FWHALT) { - DHD_ERROR(("Firmware trapped and trap_data is 0x%04x\n", data)); - if (data & D2H_DEV_EXT_TRAP_DATA) - { - if (dhd->extended_trap_data) { - OSL_CACHE_INV((void *)trap_addr->va, - BCMPCIE_EXT_TRAP_DATA_MAXLEN); - memcpy(dhd->extended_trap_data, (uint32 *)trap_addr->va, - BCMPCIE_EXT_TRAP_DATA_MAXLEN); - } - DHD_ERROR(("Extended trap data available\n")); - } - return data; - } - return 0; -} - -/** called when DHD needs to check for 'ioctl complete' messages from the dongle */ -int BCMFASTPATH -dhd_prot_process_ctrlbuf(dhd_pub_t *dhd) -{ - dhd_prot_t *prot = dhd->prot; - msgbuf_ring_t *ring = &prot->d2hring_ctrl_cpln; - - /* Process all the messages - DTOH direction */ - while (!dhd_is_device_removed(dhd)) { - uint8 *msg_addr; - uint32 msg_len; - - if (dhd->hang_was_sent) { - break; - } - - /* Get the address of the next message to be read from ring */ - msg_addr = dhd_prot_get_read_addr(dhd, ring, &msg_len); - if (msg_addr == NULL) { - break; - } - - /* Prefetch data to populate the cache */ - OSL_PREFETCH(msg_addr); - if (dhd_prot_process_msgtype(dhd, ring, msg_addr, msg_len) != BCME_OK) { - DHD_ERROR(("%s: process %s msg addr %p len %d\n", - __FUNCTION__, ring->name, msg_addr, msg_len)); - } - - /* Write to dngl rd ptr */ - dhd_prot_upd_read_idx(dhd, ring); - } - - return 0; -} - -/** - * Consume messages out of the D2H ring. Ensure that the message's DMA to host - * memory has completed, before invoking the message handler via a table lookup - * of the cmn_msg_hdr::msg_type. - */ -static int BCMFASTPATH -dhd_prot_process_msgtype(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint8 *buf, uint32 len) -{ - uint32 buf_len = len; - uint16 item_len; - uint8 msg_type; - cmn_msg_hdr_t *msg = NULL; - int ret = BCME_OK; - - ASSERT(ring); - item_len = ring->item_len; - if (item_len == 0) { - DHD_ERROR(("%s: ringidx %d, item_len %d buf_len %d \n", - __FUNCTION__, ring->idx, item_len, buf_len)); - return BCME_ERROR; - } - - while (buf_len > 0) { - if (dhd->hang_was_sent) { - ret = BCME_ERROR; - goto done; - } - - msg = (cmn_msg_hdr_t *)buf; - - /* Wait until DMA completes, then fetch msg_type */ - msg_type = dhd->prot->d2h_sync_cb(dhd, ring, msg, item_len); - - /* - * Update the curr_rd to the current index in the ring, from where - * the work item is fetched. This way if the fetched work item - * fails in LIVELOCK, we can print the exact read index in the ring - * that shows up the corrupted work item. - */ - if ((ring->curr_rd + 1) >= ring->max_items) { - ring->curr_rd = 0; - } else { - ring->curr_rd += 1; - } - - /* Prefetch data to populate the cache */ - OSL_PREFETCH(buf + item_len); - - DHD_INFO(("msg_type %d item_len %d buf_len %d\n", - msg_type, item_len, buf_len)); - - if (msg_type == MSG_TYPE_LOOPBACK) { - bcm_print_bytes("LPBK RESP: ", (uint8 *)msg, item_len); - DHD_ERROR((" MSG_TYPE_LOOPBACK, len %d\n", item_len)); - } - - ASSERT(msg_type < DHD_PROT_FUNCS); - if (msg_type >= DHD_PROT_FUNCS) { - DHD_ERROR(("%s: msg_type %d, item_len %d buf_len %d\n", - __FUNCTION__, msg_type, item_len, buf_len)); - ret = BCME_ERROR; - goto done; - } - - if (table_lookup[msg_type]) { - table_lookup[msg_type](dhd, buf); - } - - if (buf_len < item_len) { - ret = BCME_ERROR; - goto done; - } - buf_len = buf_len - item_len; - buf = buf + item_len; - } - -done: - -#ifdef DHD_RX_CHAINING - dhd_rxchain_commit(dhd); -#endif - - return ret; -} /* dhd_prot_process_msgtype */ - -static void -dhd_prot_noop(dhd_pub_t *dhd, void *msg) -{ - return; -} - -/** called on MSG_TYPE_RING_STATUS message received from dongle */ -static void -dhd_prot_ringstatus_process(dhd_pub_t *dhd, void *msg) -{ - pcie_ring_status_t *ring_status = (pcie_ring_status_t *) msg; - uint32 request_id = ltoh32(ring_status->cmn_hdr.request_id); - uint16 status = ltoh16(ring_status->compl_hdr.status); - uint16 ring_id = ltoh16(ring_status->compl_hdr.flow_ring_id); - - DHD_ERROR(("ring status: request_id %d, status 0x%04x, flow ring %d, write_idx %d \n", - request_id, status, ring_id, ltoh16(ring_status->write_idx))); - - if (ltoh16(ring_status->compl_hdr.ring_id) != BCMPCIE_H2D_MSGRING_CONTROL_SUBMIT) - return; - if (status == BCMPCIE_BAD_PHASE) { - /* bad phase report from */ - DHD_ERROR(("Bad phase\n")); - } - if (status != BCMPCIE_BADOPTION) - return; - - if (request_id == DHD_H2D_DBGRING_REQ_PKTID) { - if (dhd->prot->h2dring_info_subn != NULL) { - if (dhd->prot->h2dring_info_subn->create_pending == TRUE) { - DHD_ERROR(("H2D ring create failed for info ring\n")); - dhd->prot->h2dring_info_subn->create_pending = FALSE; - } - else - DHD_ERROR(("ring create ID for a ring, create not pending\n")); - } else { - DHD_ERROR(("%s info submit ring doesn't exist\n", __FUNCTION__)); - } - } - else if (request_id == DHD_D2H_DBGRING_REQ_PKTID) { - if (dhd->prot->d2hring_info_cpln != NULL) { - if (dhd->prot->d2hring_info_cpln->create_pending == TRUE) { - DHD_ERROR(("D2H ring create failed for info ring\n")); - dhd->prot->d2hring_info_cpln->create_pending = FALSE; - } - else - DHD_ERROR(("ring create ID for info ring, create not pending\n")); - } else { - DHD_ERROR(("%s info cpl ring doesn't exist\n", __FUNCTION__)); - } - } - else { - DHD_ERROR(("don;t know how to pair with original request\n")); - } - /* How do we track this to pair it with ??? */ - return; -} - -/** called on MSG_TYPE_GEN_STATUS ('general status') message received from dongle */ -static void -dhd_prot_genstatus_process(dhd_pub_t *dhd, void *msg) -{ - pcie_gen_status_t *gen_status = (pcie_gen_status_t *)msg; - DHD_ERROR(("ERROR: gen status: request_id %d, STATUS 0x%04x, flow ring %d \n", - gen_status->cmn_hdr.request_id, gen_status->compl_hdr.status, - gen_status->compl_hdr.flow_ring_id)); - - /* How do we track this to pair it with ??? */ - return; -} - -/** - * Called on MSG_TYPE_IOCTLPTR_REQ_ACK ('ioctl ack') message received from dongle, meaning that the - * dongle received the ioctl message in dongle memory. - */ -static void -dhd_prot_ioctack_process(dhd_pub_t *dhd, void *msg) -{ - ioctl_req_ack_msg_t *ioct_ack = (ioctl_req_ack_msg_t *)msg; - unsigned long flags; -#ifdef DHD_PKTID_AUDIT_RING - uint32 pktid = ltoh32(ioct_ack->cmn_hdr.request_id); - - /* Skip audit for ADHD_IOCTL_REQ_PKTID = 0xFFFE */ - if (pktid != DHD_IOCTL_REQ_PKTID) { -#ifndef IOCTLRESP_USE_CONSTMEM - DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_ctrl_map, pktid, - DHD_TEST_IS_ALLOC, msg, D2HRING_CTRL_CMPLT_ITEMSIZE); -#else - DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_map_handle_ioctl, pktid, - DHD_TEST_IS_ALLOC, msg, D2HRING_CTRL_CMPLT_ITEMSIZE); -#endif /* !IOCTLRESP_USE_CONSTMEM */ - } -#endif /* DHD_PKTID_AUDIT_RING */ - - DHD_GENERAL_LOCK(dhd, flags); - if ((dhd->prot->ioctl_state & MSGBUF_IOCTL_ACK_PENDING) && - (dhd->prot->ioctl_state & MSGBUF_IOCTL_RESP_PENDING)) { - dhd->prot->ioctl_state &= ~MSGBUF_IOCTL_ACK_PENDING; - } else { - DHD_ERROR(("%s: received ioctl ACK with state %02x trans_id = %d\n", - __FUNCTION__, dhd->prot->ioctl_state, dhd->prot->ioctl_trans_id)); - prhex("dhd_prot_ioctack_process:", - (uchar *)msg, D2HRING_CTRL_CMPLT_ITEMSIZE); - } - DHD_GENERAL_UNLOCK(dhd, flags); - - DHD_CTL(("ioctl req ack: request_id %d, status 0x%04x, flow ring %d \n", - ioct_ack->cmn_hdr.request_id, ioct_ack->compl_hdr.status, - ioct_ack->compl_hdr.flow_ring_id)); - if (ioct_ack->compl_hdr.status != 0) { - DHD_ERROR(("got an error status for the ioctl request...need to handle that\n")); - } -#ifdef REPORT_FATAL_TIMEOUTS - else { - dhd_stop_bus_timer(dhd); - } -#endif /* REPORT_FATAL_TIMEOUTS */ -} - -/** called on MSG_TYPE_IOCTL_CMPLT message received from dongle */ -static void -dhd_prot_ioctcmplt_process(dhd_pub_t *dhd, void *msg) -{ - dhd_prot_t *prot = dhd->prot; - uint32 pkt_id, xt_id; - ioctl_comp_resp_msg_t *ioct_resp = (ioctl_comp_resp_msg_t *)msg; - void *pkt; - unsigned long flags; - dhd_dma_buf_t retbuf; -#ifdef REPORT_FATAL_TIMEOUTS - uint16 dhd_xt_id; -#endif - - memset(&retbuf, 0, sizeof(dhd_dma_buf_t)); - - pkt_id = ltoh32(ioct_resp->cmn_hdr.request_id); - -#ifdef DHD_PKTID_AUDIT_RING -#ifndef IOCTLRESP_USE_CONSTMEM - DHD_PKTID_AUDIT_RING_DEBUG(dhd, prot->pktid_ctrl_map, pkt_id, - DHD_DUPLICATE_FREE, msg, D2HRING_CTRL_CMPLT_ITEMSIZE); -#else - DHD_PKTID_AUDIT_RING_DEBUG(dhd, prot->pktid_map_handle_ioctl, pkt_id, - DHD_DUPLICATE_FREE, msg, D2HRING_CTRL_CMPLT_ITEMSIZE); -#endif /* !IOCTLRESP_USE_CONSTMEM */ -#endif /* DHD_PKTID_AUDIT_RING */ - - DHD_GENERAL_LOCK(dhd, flags); - if ((prot->ioctl_state & MSGBUF_IOCTL_ACK_PENDING) || - !(prot->ioctl_state & MSGBUF_IOCTL_RESP_PENDING)) { - DHD_ERROR(("%s: received ioctl response with state %02x trans_id = %d\n", - __FUNCTION__, dhd->prot->ioctl_state, dhd->prot->ioctl_trans_id)); - prhex("dhd_prot_ioctcmplt_process:", - (uchar *)msg, D2HRING_CTRL_CMPLT_ITEMSIZE); - DHD_GENERAL_UNLOCK(dhd, flags); - return; - } - - /* Clear Response pending bit */ - prot->ioctl_state &= ~MSGBUF_IOCTL_RESP_PENDING; - -#ifndef IOCTLRESP_USE_CONSTMEM - pkt = dhd_prot_packet_get(dhd, pkt_id, PKTTYPE_IOCTL_RX, TRUE); -#else - dhd_prot_ioctl_ret_buffer_get(dhd, pkt_id, &retbuf); - pkt = retbuf.va; -#endif /* !IOCTLRESP_USE_CONSTMEM */ - if (!pkt) { - DHD_GENERAL_UNLOCK(dhd, flags); - DHD_ERROR(("%s: received ioctl response with NULL pkt\n", __FUNCTION__)); - prhex("dhd_prot_ioctcmplt_process:", - (uchar *)msg, D2HRING_CTRL_CMPLT_ITEMSIZE); - return; - } - DHD_GENERAL_UNLOCK(dhd, flags); - - prot->ioctl_resplen = ltoh16(ioct_resp->resp_len); - prot->ioctl_status = ltoh16(ioct_resp->compl_hdr.status); - xt_id = ltoh16(ioct_resp->trans_id); - - if (xt_id != prot->ioctl_trans_id || prot->curr_ioctl_cmd != ioct_resp->cmd) { - DHD_ERROR(("%s: transaction id(%d %d) or cmd(%d %d) mismatch\n", - __FUNCTION__, xt_id, prot->ioctl_trans_id, - prot->curr_ioctl_cmd, ioct_resp->cmd)); -#ifdef REPORT_FATAL_TIMEOUTS - dhd_stop_cmd_timer(dhd); -#endif /* REPORT_FATAL_TIMEOUTS */ - dhd_wakeup_ioctl_event(dhd, IOCTL_RETURN_ON_ERROR); - dhd_prot_debug_info_print(dhd); -#ifdef DHD_FW_COREDUMP - if (dhd->memdump_enabled) { - /* collect core dump */ - dhd->memdump_type = DUMP_TYPE_TRANS_ID_MISMATCH; - dhd_bus_mem_dump(dhd); - } -#else - ASSERT(0); -#endif /* DHD_FW_COREDUMP */ - dhd_schedule_reset(dhd); - goto exit; - } -#ifdef REPORT_FATAL_TIMEOUTS - dhd_xt_id = dhd_get_request_id(dhd); - if (xt_id == dhd_xt_id) { - dhd_stop_cmd_timer(dhd); - } else { - DHD_ERROR(("%s: Cmd timer not stopped received xt_id %d stored xt_id %d", - __FUNCTION__, xt_id, dhd_xt_id)); - } -#endif /* REPORT_FATAL_TIMEOUTS */ - DHD_CTL(("IOCTL_COMPLETE: req_id %x transid %d status %x resplen %d\n", - pkt_id, xt_id, prot->ioctl_status, prot->ioctl_resplen)); - - if (prot->ioctl_resplen > 0) { -#ifndef IOCTLRESP_USE_CONSTMEM - bcopy(PKTDATA(dhd->osh, pkt), prot->retbuf.va, prot->ioctl_resplen); -#else - bcopy(pkt, prot->retbuf.va, prot->ioctl_resplen); -#endif /* !IOCTLRESP_USE_CONSTMEM */ - } - - /* wake up any dhd_os_ioctl_resp_wait() */ - dhd_wakeup_ioctl_event(dhd, IOCTL_RETURN_ON_SUCCESS); - -exit: -#ifndef IOCTLRESP_USE_CONSTMEM - dhd_prot_packet_free(dhd, pkt, - PKTTYPE_IOCTL_RX, FALSE); -#else - free_ioctl_return_buffer(dhd, &retbuf); -#endif /* !IOCTLRESP_USE_CONSTMEM */ - - /* Post another ioctl buf to the device */ - if (prot->cur_ioctlresp_bufs_posted > 0) { - prot->cur_ioctlresp_bufs_posted--; - } - - dhd_msgbuf_rxbuf_post_ioctlresp_bufs(dhd); -} - -/** called on MSG_TYPE_TX_STATUS message received from dongle */ -static void BCMFASTPATH -dhd_prot_txstatus_process(dhd_pub_t *dhd, void *msg) -{ - dhd_prot_t *prot = dhd->prot; - host_txbuf_cmpl_t * txstatus; - unsigned long flags; - uint32 pktid; - void *pkt; - dmaaddr_t pa; - uint32 len; - void *dmah; - void *secdma; - bool pkt_fate; -#ifdef DEVICE_TX_STUCK_DETECT - flow_ring_node_t *flow_ring_node; - uint16 flowid; -#endif /* DEVICE_TX_STUCK_DETECT */ - - - txstatus = (host_txbuf_cmpl_t *)msg; -#ifdef DEVICE_TX_STUCK_DETECT - flowid = txstatus->compl_hdr.flow_ring_id; - flow_ring_node = DHD_FLOW_RING(dhd, flowid); - /** - * Since we got a completion message on this flowid, - * update tx_cmpl time stamp - */ - flow_ring_node->tx_cmpl = OSL_SYSUPTIME(); -#endif /* DEVICE_TX_STUCK_DETECT */ - - /* locks required to protect circular buffer accesses */ - DHD_GENERAL_LOCK(dhd, flags); - pktid = ltoh32(txstatus->cmn_hdr.request_id); - pkt_fate = TRUE; - -#ifdef DHD_PKTID_AUDIT_RING - DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_tx_map, pktid, - DHD_DUPLICATE_FREE, msg, D2HRING_TXCMPLT_ITEMSIZE); -#endif /* DHD_PKTID_AUDIT_RING */ - - DHD_INFO(("txstatus for pktid 0x%04x\n", pktid)); - if (prot->active_tx_count) { - prot->active_tx_count--; - - /* Release the Lock when no more tx packets are pending */ - if (prot->active_tx_count == 0) - DHD_TXFL_WAKE_UNLOCK(dhd); - } else { - DHD_ERROR(("Extra packets are freed\n")); - } - - ASSERT(pktid != 0); -#if defined(DHD_LB_TXC) && !defined(BCM_SECURE_DMA) - { - int elem_ix; - void **elem; - bcm_workq_t *workq; - dmaaddr_t pa; - uint32 pa_len; - - pkt = DHD_PKTID_TO_NATIVE(dhd, dhd->prot->pktid_tx_map, - pktid, pa, pa_len, dmah, secdma, PKTTYPE_DATA_TX); - - workq = &prot->tx_compl_prod; - /* - * Produce the packet into the tx_compl workq for the tx compl tasklet - * to consume. - */ - OSL_PREFETCH(PKTTAG(pkt)); - - /* fetch next available slot in workq */ - elem_ix = bcm_ring_prod(WORKQ_RING(workq), DHD_LB_WORKQ_SZ); - - DHD_PKTTAG_SET_PA((dhd_pkttag_fr_t *)PKTTAG(pkt), pa); - DHD_PKTTAG_SET_PA_LEN((dhd_pkttag_fr_t *)PKTTAG(pkt), pa_len); - - if (elem_ix == BCM_RING_FULL) { - DHD_ERROR(("tx_compl_prod BCM_RING_FULL\n")); - goto workq_ring_full; - } - - elem = WORKQ_ELEMENT(void *, &prot->tx_compl_prod, elem_ix); - *elem = pkt; - - smp_wmb(); - - /* Sync WR index to consumer if the SYNC threshold has been reached */ - if (++prot->tx_compl_prod_sync >= DHD_LB_WORKQ_SYNC) { - bcm_workq_prod_sync(workq); - prot->tx_compl_prod_sync = 0; - } - - DHD_INFO(("%s: tx_compl_prod pkt<%p> sync<%d>\n", - __FUNCTION__, pkt, prot->tx_compl_prod_sync)); - - DHD_GENERAL_UNLOCK(dhd, flags); - - return; - } - -workq_ring_full: - -#endif /* !DHD_LB_TXC */ - - pkt = DHD_PKTID_TO_NATIVE(dhd, dhd->prot->pktid_tx_map, pktid, - pa, len, dmah, secdma, PKTTYPE_DATA_TX); - - if (pkt) { - if (SECURE_DMA_ENAB(dhd->osh)) { - int offset = 0; - BCM_REFERENCE(offset); - - if (dhd->prot->tx_metadata_offset) - offset = dhd->prot->tx_metadata_offset + ETHER_HDR_LEN; - SECURE_DMA_UNMAP(dhd->osh, (uint) pa, - (uint) dhd->prot->tx_metadata_offset, DMA_RX, 0, dmah, - secdma, offset); - } else - DMA_UNMAP(dhd->osh, pa, (uint) len, DMA_RX, 0, dmah); -#ifdef DMAMAP_STATS - dhd->dma_stats.txdata--; - dhd->dma_stats.txdata_sz -= len; -#endif /* DMAMAP_STATS */ -#if defined(DBG_PKT_MON) || defined(DHD_PKT_LOGGING) - if (dhd->d11_tx_status) { - uint16 tx_status; - - tx_status = ltoh16(txstatus->compl_hdr.status) & - WLFC_CTL_PKTFLAG_MASK; - pkt_fate = (tx_status == WLFC_CTL_PKTFLAG_DISCARD) ? TRUE : FALSE; - - DHD_DBG_PKT_MON_TX_STATUS(dhd, pkt, pktid, tx_status); -#ifdef DHD_PKT_LOGGING - DHD_PKTLOG_TXS(dhd, pkt, pktid, tx_status); -#endif /* DHD_PKT_LOGGING */ - } -#endif /* DBG_PKT_MON || DHD_PKT_LOGGING */ -#if defined(BCMPCIE) - dhd_txcomplete(dhd, pkt, pkt_fate); -#endif - -#if DHD_DBG_SHOW_METADATA - if (dhd->prot->metadata_dbg && - dhd->prot->tx_metadata_offset && txstatus->metadata_len) { - uchar *ptr; - /* The Ethernet header of TX frame was copied and removed. - * Here, move the data pointer forward by Ethernet header size. - */ - PKTPULL(dhd->osh, pkt, ETHER_HDR_LEN); - ptr = PKTDATA(dhd->osh, pkt) - (dhd->prot->tx_metadata_offset); - bcm_print_bytes("txmetadata", ptr, txstatus->metadata_len); - dhd_prot_print_metadata(dhd, ptr, txstatus->metadata_len); - } -#endif /* DHD_DBG_SHOW_METADATA */ - DHD_GENERAL_UNLOCK(dhd, flags); - PKTFREE(dhd->osh, pkt, TRUE); - DHD_GENERAL_LOCK(dhd, flags); - DHD_FLOWRING_TXSTATUS_CNT_UPDATE(dhd->bus, txstatus->compl_hdr.flow_ring_id, - txstatus->tx_status); - -#ifdef DHD_TIMESYNC - if (dhd->prot->tx_ts_log_enabled) { - ts_timestamp_t *ts = (ts_timestamp_t *)&(txstatus->ts); - dhd_timesync_log_tx_timestamp(dhd->ts, - txstatus->compl_hdr.flow_ring_id, - txstatus->cmn_hdr.if_id, - ts->low, ts->high); - } -#endif /* DHD_TIMESYNC */ - } - - DHD_GENERAL_UNLOCK(dhd, flags); - - return; -} /* dhd_prot_txstatus_process */ - -/** called on MSG_TYPE_WL_EVENT message received from dongle */ -static void -dhd_prot_event_process(dhd_pub_t *dhd, void *msg) -{ - wlevent_req_msg_t *evnt; - uint32 bufid; - uint16 buflen; - int ifidx = 0; - void* pkt; - unsigned long flags; - dhd_prot_t *prot = dhd->prot; - - /* Event complete header */ - evnt = (wlevent_req_msg_t *)msg; - bufid = ltoh32(evnt->cmn_hdr.request_id); - -#ifdef DHD_PKTID_AUDIT_RING - DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_ctrl_map, bufid, - DHD_DUPLICATE_FREE, msg, D2HRING_CTRL_CMPLT_ITEMSIZE); -#endif /* DHD_PKTID_AUDIT_RING */ - - buflen = ltoh16(evnt->event_data_len); - - ifidx = BCMMSGBUF_API_IFIDX(&evnt->cmn_hdr); - - /* Post another rxbuf to the device */ - if (prot->cur_event_bufs_posted) - prot->cur_event_bufs_posted--; - dhd_msgbuf_rxbuf_post_event_bufs(dhd); - - /* locks required to protect pktid_map */ - DHD_GENERAL_LOCK(dhd, flags); - pkt = dhd_prot_packet_get(dhd, bufid, PKTTYPE_EVENT_RX, TRUE); - DHD_GENERAL_UNLOCK(dhd, flags); - - if (!pkt) { - DHD_ERROR(("%s: pkt is NULL for pktid %d\n", __FUNCTION__, bufid)); - return; - } - - /* DMA RX offset updated through shared area */ - if (dhd->prot->rx_dataoffset) - PKTPULL(dhd->osh, pkt, dhd->prot->rx_dataoffset); - - PKTSETLEN(dhd->osh, pkt, buflen); - - dhd_bus_rx_frame(dhd->bus, pkt, ifidx, 1); -} - -/** called on MSG_TYPE_INFO_BUF_CMPLT message received from dongle */ -static void BCMFASTPATH -dhd_prot_process_infobuf_complete(dhd_pub_t *dhd, void* buf) -{ - info_buf_resp_t *resp; - uint32 pktid; - uint16 buflen; - void * pkt; - unsigned long flags; - - resp = (info_buf_resp_t *)buf; - pktid = ltoh32(resp->cmn_hdr.request_id); - buflen = ltoh16(resp->info_data_len); - -#ifdef DHD_PKTID_AUDIT_RING - DHD_PKTID_AUDIT_RING_DEBUG(dhd, dhd->prot->pktid_ctrl_map, pktid, - DHD_DUPLICATE_FREE, buf, D2HRING_INFO_BUFCMPLT_ITEMSIZE); -#endif /* DHD_PKTID_AUDIT_RING */ - - DHD_INFO(("id 0x%04x, len %d, phase 0x%02x, seqnum %d, rx_dataoffset %d\n", - pktid, buflen, resp->cmn_hdr.flags, ltoh16(resp->seqnum), - dhd->prot->rx_dataoffset)); - - if (!dhd->prot->infobufpost) { - DHD_ERROR(("infobuf posted are zero, but there is a completion\n")); - return; - } - - dhd->prot->infobufpost--; - dhd_prot_infobufpost(dhd); - - DHD_GENERAL_LOCK(dhd, flags); - pkt = dhd_prot_packet_get(dhd, pktid, PKTTYPE_INFO_RX, TRUE); - DHD_GENERAL_UNLOCK(dhd, flags); - - if (!pkt) - return; - - /* DMA RX offset updated through shared area */ - if (dhd->prot->rx_dataoffset) - PKTPULL(dhd->osh, pkt, dhd->prot->rx_dataoffset); - - PKTSETLEN(dhd->osh, pkt, buflen); - - /* info ring "debug" data, which is not a 802.3 frame, is sent/hacked with a - * special ifidx of -1. This is just internal to dhd to get the data to - * dhd_linux.c:dhd_rx_frame() from here (dhd_prot_infobuf_cmplt_process). - */ - dhd_bus_rx_frame(dhd->bus, pkt, DHD_EVENT_IF /* ifidx HACK */, 1); -} - -/** Stop protocol: sync w/dongle state. */ -void dhd_prot_stop(dhd_pub_t *dhd) -{ - ASSERT(dhd); - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - -} - -/* Add any protocol-specific data header. - * Caller must reserve prot_hdrlen prepend space. - */ -void BCMFASTPATH -dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *PKTBUF) -{ - return; -} - -uint -dhd_prot_hdrlen(dhd_pub_t *dhd, void *PKTBUF) -{ - return 0; -} - - -#define PKTBUF pktbuf - -/** - * Called when a tx ethernet packet has been dequeued from a flow queue, and has to be inserted in - * the corresponding flow ring. - */ -int BCMFASTPATH -dhd_prot_txdata(dhd_pub_t *dhd, void *PKTBUF, uint8 ifidx) -{ - unsigned long flags; - dhd_prot_t *prot = dhd->prot; - host_txbuf_post_t *txdesc = NULL; - dmaaddr_t pa, meta_pa; - uint8 *pktdata; - uint32 pktlen; - uint32 pktid; - uint8 prio; - uint16 flowid = 0; - uint16 alloced = 0; - uint16 headroom; - msgbuf_ring_t *ring; - flow_ring_table_t *flow_ring_table; - flow_ring_node_t *flow_ring_node; - - if (dhd->flow_ring_table == NULL) { - return BCME_NORESOURCE; - } - - flowid = DHD_PKT_GET_FLOWID(PKTBUF); - flow_ring_table = (flow_ring_table_t *)dhd->flow_ring_table; - flow_ring_node = (flow_ring_node_t *)&flow_ring_table[flowid]; - - ring = (msgbuf_ring_t *)flow_ring_node->prot_info; - -#ifdef PCIE_INB_DW - if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) - return BCME_ERROR; -#endif /* PCIE_INB_DW */ - - DHD_GENERAL_LOCK(dhd, flags); - - /* Create a unique 32-bit packet id */ - pktid = DHD_NATIVE_TO_PKTID_RSV(dhd, dhd->prot->pktid_tx_map, - PKTBUF, PKTTYPE_DATA_TX); -#if defined(DHD_PCIE_PKTID) - if (pktid == DHD_PKTID_INVALID) { - DHD_ERROR(("%s: Pktid pool depleted.\n", __FUNCTION__)); - /* - * If we return error here, the caller would queue the packet - * again. So we'll just free the skb allocated in DMA Zone. - * Since we have not freed the original SKB yet the caller would - * requeue the same. - */ - goto err_no_res_pktfree; - } -#endif /* DHD_PCIE_PKTID */ - - /* Reserve space in the circular buffer */ - txdesc = (host_txbuf_post_t *) - dhd_prot_alloc_ring_space(dhd, ring, 1, &alloced, FALSE); - if (txdesc == NULL) { - DHD_INFO(("%s:%d: HTOD Msgbuf Not available TxCount = %d\n", - __FUNCTION__, __LINE__, prot->active_tx_count)); - goto err_free_pktid; - } - -#ifdef DBG_PKT_MON - DHD_DBG_PKT_MON_TX(dhd, PKTBUF, pktid); -#endif /* DBG_PKT_MON */ -#ifdef DHD_PKT_LOGGING - DHD_PKTLOG_TX(dhd, PKTBUF, pktid); -#endif /* DHD_PKT_LOGGING */ - - - /* Extract the data pointer and length information */ - pktdata = PKTDATA(dhd->osh, PKTBUF); - pktlen = PKTLEN(dhd->osh, PKTBUF); - - /* Ethernet header: Copy before we cache flush packet using DMA_MAP */ - bcopy(pktdata, txdesc->txhdr, ETHER_HDR_LEN); - - /* Extract the ethernet header and adjust the data pointer and length */ - pktdata = PKTPULL(dhd->osh, PKTBUF, ETHER_HDR_LEN); - pktlen -= ETHER_HDR_LEN; - - /* Map the data pointer to a DMA-able address */ - if (SECURE_DMA_ENAB(dhd->osh)) { - int offset = 0; - BCM_REFERENCE(offset); - - if (prot->tx_metadata_offset) - offset = prot->tx_metadata_offset + ETHER_HDR_LEN; - - pa = SECURE_DMA_MAP(dhd->osh, PKTDATA(dhd->osh, PKTBUF), pktlen, - DMA_TX, PKTBUF, 0, ring->dma_buf.secdma, offset); - } -#ifndef BCM_SECURE_DMA - else - pa = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, PKTBUF), pktlen, DMA_TX, PKTBUF, 0); -#endif /* #ifndef BCM_SECURE_DMA */ - - if (PHYSADDRISZERO(pa)) { - DHD_ERROR(("%s: Something really bad, unless 0 is " - "a valid phyaddr for pa\n", __FUNCTION__)); - ASSERT(0); - goto err_rollback_idx; - } - -#ifdef DMAMAP_STATS - dhd->dma_stats.txdata++; - dhd->dma_stats.txdata_sz += pktlen; -#endif /* DMAMAP_STATS */ - /* No need to lock. Save the rest of the packet's metadata */ - DHD_NATIVE_TO_PKTID_SAVE(dhd, dhd->prot->pktid_tx_map, PKTBUF, pktid, - pa, pktlen, DMA_TX, NULL, ring->dma_buf.secdma, PKTTYPE_DATA_TX); - -#ifdef TXP_FLUSH_NITEMS - if (ring->pend_items_count == 0) - ring->start_addr = (void *)txdesc; - ring->pend_items_count++; -#endif - - /* Form the Tx descriptor message buffer */ - - /* Common message hdr */ - txdesc->cmn_hdr.msg_type = MSG_TYPE_TX_POST; - txdesc->cmn_hdr.if_id = ifidx; - txdesc->cmn_hdr.flags = ring->current_phase; - - txdesc->flags = BCMPCIE_PKT_FLAGS_FRAME_802_3; - prio = (uint8)PKTPRIO(PKTBUF); - - - txdesc->flags |= (prio & 0x7) << BCMPCIE_PKT_FLAGS_PRIO_SHIFT; - txdesc->seg_cnt = 1; - - txdesc->data_len = htol16((uint16) pktlen); - txdesc->data_buf_addr.high_addr = htol32(PHYSADDRHI(pa)); - txdesc->data_buf_addr.low_addr = htol32(PHYSADDRLO(pa)); - - /* Move data pointer to keep ether header in local PKTBUF for later reference */ - PKTPUSH(dhd->osh, PKTBUF, ETHER_HDR_LEN); - - /* Handle Tx metadata */ - headroom = (uint16)PKTHEADROOM(dhd->osh, PKTBUF); - if (prot->tx_metadata_offset && (headroom < prot->tx_metadata_offset)) - DHD_ERROR(("No headroom for Metadata tx %d %d\n", - prot->tx_metadata_offset, headroom)); - - if (prot->tx_metadata_offset && (headroom >= prot->tx_metadata_offset)) { - DHD_TRACE(("Metadata in tx %d\n", prot->tx_metadata_offset)); - - /* Adjust the data pointer to account for meta data in DMA_MAP */ - PKTPUSH(dhd->osh, PKTBUF, prot->tx_metadata_offset); - - if (SECURE_DMA_ENAB(dhd->osh)) { - meta_pa = SECURE_DMA_MAP_TXMETA(dhd->osh, PKTDATA(dhd->osh, PKTBUF), - prot->tx_metadata_offset + ETHER_HDR_LEN, DMA_RX, PKTBUF, - 0, ring->dma_buf.secdma); - } -#ifndef BCM_SECURE_DMA - else - meta_pa = DMA_MAP(dhd->osh, PKTDATA(dhd->osh, PKTBUF), - prot->tx_metadata_offset, DMA_RX, PKTBUF, 0); -#endif /* #ifndef BCM_SECURE_DMA */ - - if (PHYSADDRISZERO(meta_pa)) { - /* Unmap the data pointer to a DMA-able address */ - if (SECURE_DMA_ENAB(dhd->osh)) { - - int offset = 0; - BCM_REFERENCE(offset); - - if (prot->tx_metadata_offset) { - offset = prot->tx_metadata_offset + ETHER_HDR_LEN; - } - - SECURE_DMA_UNMAP(dhd->osh, pa, pktlen, - DMA_TX, 0, DHD_DMAH_NULL, ring->dma_buf.secdma, offset); - } -#ifndef BCM_SECURE_DMA - else { - DMA_UNMAP(dhd->osh, pa, pktlen, DMA_TX, 0, DHD_DMAH_NULL); - } -#endif /* #ifndef BCM_SECURE_DMA */ -#ifdef TXP_FLUSH_NITEMS - /* update pend_items_count */ - ring->pend_items_count--; -#endif /* TXP_FLUSH_NITEMS */ - - DHD_ERROR(("%s: Something really bad, unless 0 is " - "a valid phyaddr for meta_pa\n", __FUNCTION__)); - ASSERT(0); - goto err_rollback_idx; - } - - /* Adjust the data pointer back to original value */ - PKTPULL(dhd->osh, PKTBUF, prot->tx_metadata_offset); - - txdesc->metadata_buf_len = prot->tx_metadata_offset; - txdesc->metadata_buf_addr.high_addr = htol32(PHYSADDRHI(meta_pa)); - txdesc->metadata_buf_addr.low_addr = htol32(PHYSADDRLO(meta_pa)); - } else { - txdesc->metadata_buf_len = htol16(0); - txdesc->metadata_buf_addr.high_addr = 0; - txdesc->metadata_buf_addr.low_addr = 0; - } - -#ifdef DHD_PKTID_AUDIT_RING - DHD_PKTID_AUDIT(dhd, prot->pktid_tx_map, pktid, DHD_DUPLICATE_ALLOC); -#endif /* DHD_PKTID_AUDIT_RING */ - - txdesc->cmn_hdr.request_id = htol32(pktid); - - DHD_TRACE(("txpost: data_len %d, pktid 0x%04x\n", txdesc->data_len, - txdesc->cmn_hdr.request_id)); - - /* Update the write pointer in TCM & ring bell */ -#ifdef TXP_FLUSH_NITEMS - /* Flush if we have either hit the txp_threshold or if this msg is */ - /* occupying the last slot in the flow_ring - before wrap around. */ - if ((ring->pend_items_count == prot->txp_threshold) || - ((uint8 *) txdesc == (uint8 *) DHD_RING_END_VA(ring))) { - dhd_prot_txdata_write_flush(dhd, flowid, TRUE); - } -#else - /* update ring's WR index and ring doorbell to dongle */ - dhd_prot_ring_write_complete(dhd, ring, txdesc, 1); -#endif - - prot->active_tx_count++; - - /* - * Take a wake lock, do not sleep if we have atleast one packet - * to finish. - */ - if (prot->active_tx_count >= 1) - DHD_TXFL_WAKE_LOCK_TIMEOUT(dhd, MAX_TX_TIMEOUT); - - DHD_GENERAL_UNLOCK(dhd, flags); - -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - - return BCME_OK; - -err_rollback_idx: - /* roll back write pointer for unprocessed message */ - if (ring->wr == 0) { - ring->wr = ring->max_items - 1; - } else { - ring->wr--; - if (ring->wr == 0) { - DHD_INFO(("%s: flipping the phase now\n", ring->name)); - ring->current_phase = ring->current_phase ? - 0 : BCMPCIE_CMNHDR_PHASE_BIT_INIT; - } - } - -err_free_pktid: -#if defined(DHD_PCIE_PKTID) - { - void *dmah; - void *secdma; - /* Free up the PKTID. physaddr and pktlen will be garbage. */ - DHD_PKTID_TO_NATIVE(dhd, dhd->prot->pktid_tx_map, pktid, - pa, pktlen, dmah, secdma, PKTTYPE_NO_CHECK); - } - -err_no_res_pktfree: -#endif /* DHD_PCIE_PKTID */ - - - - DHD_GENERAL_UNLOCK(dhd, flags); -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - return BCME_NORESOURCE; -} /* dhd_prot_txdata */ - -/* called with a lock */ -/** optimization to write "n" tx items at a time to ring */ -void BCMFASTPATH -dhd_prot_txdata_write_flush(dhd_pub_t *dhd, uint16 flowid, bool in_lock) -{ -#ifdef TXP_FLUSH_NITEMS - unsigned long flags = 0; - flow_ring_table_t *flow_ring_table; - flow_ring_node_t *flow_ring_node; - msgbuf_ring_t *ring; - - if (dhd->flow_ring_table == NULL) { - return; - } - - if (!in_lock) { - DHD_GENERAL_LOCK(dhd, flags); - } - - flow_ring_table = (flow_ring_table_t *)dhd->flow_ring_table; - flow_ring_node = (flow_ring_node_t *)&flow_ring_table[flowid]; - ring = (msgbuf_ring_t *)flow_ring_node->prot_info; - - if (ring->pend_items_count) { - /* update ring's WR index and ring doorbell to dongle */ - dhd_prot_ring_write_complete(dhd, ring, ring->start_addr, - ring->pend_items_count); - ring->pend_items_count = 0; - ring->start_addr = NULL; - } - - if (!in_lock) { - DHD_GENERAL_UNLOCK(dhd, flags); - } -#endif /* TXP_FLUSH_NITEMS */ -} - -#undef PKTBUF /* Only defined in the above routine */ - -int BCMFASTPATH -dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pkt, uchar *buf, uint *len) -{ - return 0; -} - -/** post a set of receive buffers to the dongle */ -static void BCMFASTPATH -dhd_prot_return_rxbuf(dhd_pub_t *dhd, uint32 pktid, uint32 rxcnt) -{ - dhd_prot_t *prot = dhd->prot; -#if defined(DHD_LB_RXC) - int elem_ix; - uint32 *elem; - bcm_workq_t *workq; - - workq = &prot->rx_compl_prod; - - /* Produce the work item */ - elem_ix = bcm_ring_prod(WORKQ_RING(workq), DHD_LB_WORKQ_SZ); - if (elem_ix == BCM_RING_FULL) { - DHD_ERROR(("%s LB RxCompl workQ is full\n", __FUNCTION__)); - ASSERT(0); - return; - } - - elem = WORKQ_ELEMENT(uint32, workq, elem_ix); - *elem = pktid; - - smp_wmb(); - - /* Sync WR index to consumer if the SYNC threshold has been reached */ - if (++prot->rx_compl_prod_sync >= DHD_LB_WORKQ_SYNC) { - bcm_workq_prod_sync(workq); - prot->rx_compl_prod_sync = 0; - } - - DHD_INFO(("%s: rx_compl_prod pktid<%u> sync<%d>\n", - __FUNCTION__, pktid, prot->rx_compl_prod_sync)); - -#endif /* DHD_LB_RXC */ - - if (prot->rxbufpost >= rxcnt) { - prot->rxbufpost -= (uint16)rxcnt; - } else { - /* ASSERT(0); */ - prot->rxbufpost = 0; - } - -#if !defined(DHD_LB_RXC) - if (prot->rxbufpost <= (prot->max_rxbufpost - RXBUFPOST_THRESHOLD)) - dhd_msgbuf_rxbuf_post(dhd, FALSE); /* alloc pkt ids */ -#endif /* !DHD_LB_RXC */ - return; -} - -/* called before an ioctl is sent to the dongle */ -static void -dhd_prot_wlioctl_intercept(dhd_pub_t *dhd, wl_ioctl_t * ioc, void * buf) -{ - dhd_prot_t *prot = dhd->prot; - - if (ioc->cmd == WLC_SET_VAR && buf != NULL && !strcmp(buf, "pcie_bus_tput")) { - int slen = 0; - pcie_bus_tput_params_t *tput_params; - - slen = strlen("pcie_bus_tput") + 1; - tput_params = (pcie_bus_tput_params_t*)((char *)buf + slen); - bcopy(&prot->host_bus_throughput_buf.pa, &tput_params->host_buf_addr, - sizeof(tput_params->host_buf_addr)); - tput_params->host_buf_len = DHD_BUS_TPUT_BUF_LEN; - } -} - - -/** Use protocol to issue ioctl to dongle. Only one ioctl may be in transit. */ -int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) -{ - int ret = -1; - uint8 action; - - 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; - } - - if (dhd->busstate == DHD_BUS_SUSPEND) { - DHD_ERROR(("%s : bus is suspended\n", __FUNCTION__)); - goto done; - } - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (ioc->cmd == WLC_SET_PM) { - DHD_TRACE_HW4(("%s: SET PM to %d\n", __FUNCTION__, buf ? *(char *)buf : 0)); - } - - ASSERT(len <= WLC_IOCTL_MAXLEN); - - if (len > WLC_IOCTL_MAXLEN) - goto done; - - action = ioc->set; - - dhd_prot_wlioctl_intercept(dhd, ioc, buf); - - if (action & WL_IOCTL_ACTION_SET) { - ret = dhd_msgbuf_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); - } else { - ret = dhd_msgbuf_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); - if (ret > 0) - ioc->used = ret; - } - - /* Too many programs assume ioctl() returns 0 on success */ - if (ret >= 0) { - ret = 0; - } else { - DHD_INFO(("%s: status ret value is %d \n", __FUNCTION__, ret)); - dhd->dongle_error = ret; - } - - if (!ret && ioc->cmd == WLC_SET_VAR && buf != NULL) { - /* Intercept the wme_dp ioctl here */ - if (!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); - } - - } - -done: - return ret; - -} /* dhd_prot_ioctl */ - -/** test / loopback */ - -int -dhdmsgbuf_lpbk_req(dhd_pub_t *dhd, uint len) -{ - unsigned long flags; - dhd_prot_t *prot = dhd->prot; - uint16 alloced = 0; - - ioct_reqst_hdr_t *ioct_rqst; - - uint16 hdrlen = sizeof(ioct_reqst_hdr_t); - uint16 msglen = len + hdrlen; - msgbuf_ring_t *ring = &prot->h2dring_ctrl_subn; - - msglen = ALIGN_SIZE(msglen, DMA_ALIGN_LEN); - msglen = LIMIT_TO_MAX(msglen, MSGBUF_MAX_MSG_SIZE); - -#ifdef PCIE_INB_DW - if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) - return BCME_ERROR; -#endif /* PCIE_INB_DW */ - - DHD_GENERAL_LOCK(dhd, flags); - - ioct_rqst = (ioct_reqst_hdr_t *) - dhd_prot_alloc_ring_space(dhd, ring, 1, &alloced, FALSE); - - if (ioct_rqst == NULL) { - DHD_GENERAL_UNLOCK(dhd, flags); -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - return 0; - } - - { - uint8 *ptr; - uint16 i; - - ptr = (uint8 *)ioct_rqst; - for (i = 0; i < msglen; i++) { - ptr[i] = i % 256; - } - } - - /* Common msg buf hdr */ - ioct_rqst->msg.epoch = ring->seqnum % H2D_EPOCH_MODULO; - ring->seqnum++; - - ioct_rqst->msg.msg_type = MSG_TYPE_LOOPBACK; - ioct_rqst->msg.if_id = 0; - ioct_rqst->msg.flags = ring->current_phase; - - bcm_print_bytes("LPBK REQ: ", (uint8 *)ioct_rqst, msglen); - - /* update ring's WR index and ring doorbell to dongle */ - dhd_prot_ring_write_complete(dhd, ring, ioct_rqst, 1); - DHD_GENERAL_UNLOCK(dhd, flags); -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - - return 0; -} - -/** test / loopback */ -void dmaxfer_free_dmaaddr(dhd_pub_t *dhd, dhd_dmaxfer_t *dmaxfer) -{ - if (dmaxfer == NULL) - return; - - dhd_dma_buf_free(dhd, &dmaxfer->srcmem); - dhd_dma_buf_free(dhd, &dmaxfer->dstmem); -} - -/** test / loopback */ -int -dhd_prepare_schedule_dmaxfer_free(dhd_pub_t *dhdp) -{ - dhd_prot_t *prot = dhdp->prot; - dhd_dmaxfer_t *dmaxfer = &prot->dmaxfer; - dmaxref_mem_map_t *dmap = NULL; - - dmap = MALLOCZ(dhdp->osh, sizeof(dmaxref_mem_map_t)); - if (!dmap) { - DHD_ERROR(("%s: dmap alloc failed\n", __FUNCTION__)); - goto mem_alloc_fail; - } - dmap->srcmem = &(dmaxfer->srcmem); - dmap->dstmem = &(dmaxfer->dstmem); - - DMAXFER_FREE(dhdp, dmap); - return BCME_OK; - -mem_alloc_fail: - if (dmap) { - MFREE(dhdp->osh, dmap, sizeof(dmaxref_mem_map_t)); - dmap = NULL; - } - return BCME_NOMEM; -} /* dhd_prepare_schedule_dmaxfer_free */ - - -/** test / loopback */ -void -dmaxfer_free_prev_dmaaddr(dhd_pub_t *dhdp, dmaxref_mem_map_t *dmmap) -{ - - dhd_dma_buf_free(dhdp, dmmap->srcmem); - dhd_dma_buf_free(dhdp, dmmap->dstmem); - - MFREE(dhdp->osh, dmmap, sizeof(dmaxref_mem_map_t)); - dmmap = NULL; - -} /* dmaxfer_free_prev_dmaaddr */ - - -/** test / loopback */ -int dmaxfer_prepare_dmaaddr(dhd_pub_t *dhd, uint len, - uint srcdelay, uint destdelay, dhd_dmaxfer_t *dmaxfer) -{ - uint i; - if (!dmaxfer) - return BCME_ERROR; - - /* First free up existing buffers */ - dmaxfer_free_dmaaddr(dhd, dmaxfer); - - if (dhd_dma_buf_alloc(dhd, &dmaxfer->srcmem, len)) { - return BCME_NOMEM; - } - - if (dhd_dma_buf_alloc(dhd, &dmaxfer->dstmem, len + 8)) { - dhd_dma_buf_free(dhd, &dmaxfer->srcmem); - return BCME_NOMEM; - } - - dmaxfer->len = len; - - /* Populate source with a pattern */ - for (i = 0; i < dmaxfer->len; i++) { - ((uint8*)dmaxfer->srcmem.va)[i] = i % 256; - } - OSL_CACHE_FLUSH(dmaxfer->srcmem.va, dmaxfer->len); - - dmaxfer->srcdelay = srcdelay; - dmaxfer->destdelay = destdelay; - - return BCME_OK; -} /* dmaxfer_prepare_dmaaddr */ - -static void -dhd_msgbuf_dmaxfer_process(dhd_pub_t *dhd, void *msg) -{ - dhd_prot_t *prot = dhd->prot; - uint64 end_usec; - pcie_dmaxfer_cmplt_t *cmplt = (pcie_dmaxfer_cmplt_t *)msg; - - BCM_REFERENCE(cmplt); - DHD_INFO(("DMA status: %d\n", cmplt->compl_hdr.status)); - OSL_CACHE_INV(prot->dmaxfer.dstmem.va, prot->dmaxfer.len); - if (prot->dmaxfer.srcmem.va && prot->dmaxfer.dstmem.va) { - if (memcmp(prot->dmaxfer.srcmem.va, - prot->dmaxfer.dstmem.va, prot->dmaxfer.len)) { - prhex("XFER SRC: ", - prot->dmaxfer.srcmem.va, prot->dmaxfer.len); - prhex("XFER DST: ", - prot->dmaxfer.dstmem.va, prot->dmaxfer.len); - DHD_ERROR(("DMA failed\n")); - } - else { - if (prot->dmaxfer.d11_lpbk) { - DHD_ERROR(("DMA successful with d11 loopback\n")); - } else { - DHD_ERROR(("DMA successful without d11 loopback\n")); - } - } - } - end_usec = OSL_SYSUPTIME_US(); - dhd_prepare_schedule_dmaxfer_free(dhd); - end_usec -= prot->dmaxfer.start_usec; - DHD_ERROR(("DMA loopback %d bytes in %llu usec, %u kBps\n", - prot->dmaxfer.len, end_usec, - (prot->dmaxfer.len * (1000 * 1000 / 1024) / (uint32)(end_usec + 1)))); - dhd->prot->dmaxfer.in_progress = FALSE; -} - -/** Test functionality. - * Transfers bytes from host to dongle and to host again using DMA - * This function is not reentrant, as prot->dmaxfer.in_progress is not protected - * by a spinlock. - */ -int -dhdmsgbuf_dmaxfer_req(dhd_pub_t *dhd, uint len, uint srcdelay, uint destdelay, uint d11_lpbk) -{ - unsigned long flags; - int ret = BCME_OK; - dhd_prot_t *prot = dhd->prot; - pcie_dma_xfer_params_t *dmap; - uint32 xferlen = LIMIT_TO_MAX(len, DMA_XFER_LEN_LIMIT); - uint16 alloced = 0; - msgbuf_ring_t *ring = &prot->h2dring_ctrl_subn; - - if (prot->dmaxfer.in_progress) { - DHD_ERROR(("DMA is in progress...\n")); - return ret; - } - - prot->dmaxfer.in_progress = TRUE; - if ((ret = dmaxfer_prepare_dmaaddr(dhd, xferlen, srcdelay, destdelay, - &prot->dmaxfer)) != BCME_OK) { - prot->dmaxfer.in_progress = FALSE; - return ret; - } - -#ifdef PCIE_INB_DW - if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) - return BCME_ERROR; -#endif /* PCIE_INB_DW */ - - DHD_GENERAL_LOCK(dhd, flags); - - dmap = (pcie_dma_xfer_params_t *) - dhd_prot_alloc_ring_space(dhd, ring, 1, &alloced, FALSE); - - if (dmap == NULL) { - dmaxfer_free_dmaaddr(dhd, &prot->dmaxfer); - prot->dmaxfer.in_progress = FALSE; - DHD_GENERAL_UNLOCK(dhd, flags); -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - return BCME_NOMEM; - } - - /* Common msg buf hdr */ - dmap->cmn_hdr.msg_type = MSG_TYPE_LPBK_DMAXFER; - dmap->cmn_hdr.request_id = htol32(DHD_FAKE_PKTID); - dmap->cmn_hdr.epoch = ring->seqnum % H2D_EPOCH_MODULO; - dmap->cmn_hdr.flags = ring->current_phase; - ring->seqnum++; - - dmap->host_input_buf_addr.high = htol32(PHYSADDRHI(prot->dmaxfer.srcmem.pa)); - dmap->host_input_buf_addr.low = htol32(PHYSADDRLO(prot->dmaxfer.srcmem.pa)); - dmap->host_ouput_buf_addr.high = htol32(PHYSADDRHI(prot->dmaxfer.dstmem.pa)); - dmap->host_ouput_buf_addr.low = htol32(PHYSADDRLO(prot->dmaxfer.dstmem.pa)); - dmap->xfer_len = htol32(prot->dmaxfer.len); - dmap->srcdelay = htol32(prot->dmaxfer.srcdelay); - dmap->destdelay = htol32(prot->dmaxfer.destdelay); - prot->dmaxfer.d11_lpbk = d11_lpbk ? 1 : 0; - dmap->flags = (prot->dmaxfer.d11_lpbk << PCIE_DMA_XFER_FLG_D11_LPBK_SHIFT) - & PCIE_DMA_XFER_FLG_D11_LPBK_MASK; - - /* update ring's WR index and ring doorbell to dongle */ - prot->dmaxfer.start_usec = OSL_SYSUPTIME_US(); - dhd_prot_ring_write_complete(dhd, ring, dmap, 1); - DHD_GENERAL_UNLOCK(dhd, flags); -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - - DHD_INFO(("DMA Started...\n")); - - return BCME_OK; -} /* dhdmsgbuf_dmaxfer_req */ - -/** Called in the process of submitting an ioctl to the dongle */ -static int -dhd_msgbuf_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) -{ - int ret = 0; - uint copylen = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (cmd == WLC_GET_VAR && buf) - { - if (!len || !*(uint8 *)buf) { - DHD_ERROR(("%s(): Zero length bailing\n", __FUNCTION__)); - ret = BCME_BADARG; - goto done; - } - - /* Respond "bcmerror" and "bcmerrorstr" with local cache */ - copylen = MIN(len, BCME_STRLEN); - - if ((len >= strlen("bcmerrorstr")) && - (!strcmp((char *)buf, "bcmerrorstr"))) { - - strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), copylen); - *(uint8 *)((uint8 *)buf + (copylen - 1)) = '\0'; - - goto done; - } else if ((len >= strlen("bcmerror")) && - !strcmp((char *)buf, "bcmerror")) { - - *(uint32 *)(uint32 *)buf = dhd->dongle_error; - - goto done; - } - } - - - DHD_CTL(("query_ioctl: ACTION %d ifdix %d cmd %d len %d \n", - action, ifidx, cmd, len)); -#ifdef REPORT_FATAL_TIMEOUTS - /* - * These timers "should" be started before sending H2D interrupt. - * Think of the scenario where H2D interrupt is fired and the Dongle - * responds back immediately. From the DPC we would stop the cmd, bus - * timers. But the process context could have switched out leading to - * a situation where the timers are Not started yet, but are actually stopped. - * - * Disable preemption from the time we start the timer until we are done - * with seding H2D interrupts. - */ - OSL_DISABLE_PREEMPTION(dhd->osh); - dhd_set_request_id(dhd, dhd->prot->ioctl_trans_id+1, cmd); - dhd_start_cmd_timer(dhd); - dhd_start_bus_timer(dhd); -#endif /* REPORT_FATAL_TIMEOUTS */ - - ret = dhd_fillup_ioct_reqst(dhd, (uint16)len, cmd, buf, ifidx); - -#ifdef REPORT_FATAL_TIMEOUTS - /* For some reason if we fail to ring door bell, stop the timers */ - if (ret < 0) { - DHD_ERROR(("%s(): dhd_fillup_ioct_reqst failed \r\n", __FUNCTION__)); - dhd_stop_cmd_timer(dhd); - dhd_stop_bus_timer(dhd); - OSL_ENABLE_PREEMPTION(dhd->osh); - goto done; - } - OSL_ENABLE_PREEMPTION(dhd->osh); -#else - if (ret < 0) { - DHD_ERROR(("%s(): dhd_fillup_ioct_reqst failed \r\n", __FUNCTION__)); - goto done; - } -#endif /* REPORT_FATAL_TIMEOUTS */ - - /* wait for IOCTL completion message from dongle and get first fragment */ - ret = dhd_msgbuf_wait_ioctl_cmplt(dhd, len, buf); - -done: - return ret; -} - -/** - * Waits for IOCTL completion message from the dongle, copies this into caller - * provided parameter 'buf'. - */ -static int -dhd_msgbuf_wait_ioctl_cmplt(dhd_pub_t *dhd, uint32 len, void *buf) -{ - dhd_prot_t *prot = dhd->prot; - int timeleft; - unsigned long flags; - int ret = 0; - static uint cnt = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (dhd_query_bus_erros(dhd)) { - ret = -EIO; - goto out; - } - - timeleft = dhd_os_ioctl_resp_wait(dhd, (uint *)&prot->ioctl_received, false); - -#ifdef DHD_RECOVER_TIMEOUT - if (prot->ioctl_received == 0) { - uint32 intstatus = 0; - uint32 intmask = 0; - intstatus = si_corereg(dhd->bus->sih, - dhd->bus->sih->buscoreidx, PCIMailBoxInt, 0, 0); - intmask = si_corereg(dhd->bus->sih, - dhd->bus->sih->buscoreidx, PCIMailBoxMask, 0, 0); - if ((intstatus) && (!intmask) && (timeleft == 0) && (!dhd_query_bus_erros(dhd))) - { - DHD_ERROR(("%s: iovar timeout trying again intstatus=%x intmask=%x\n", - __FUNCTION__, intstatus, intmask)); - DHD_ERROR(("\n ------- DUMPING INTR enable/disable counters\r\n")); - DHD_ERROR(("resume_intr_enable_count=%lu dpc_intr_enable_count=%lu\n" - "isr_intr_disable_count=%lu suspend_intr_disable_count=%lu\n" - "dpc_return_busdown_count=%lu\n", - dhd->bus->resume_intr_enable_count, dhd->bus->dpc_intr_enable_count, - dhd->bus->isr_intr_disable_count, - dhd->bus->suspend_intr_disable_count, - dhd->bus->dpc_return_busdown_count)); - - dhd_prot_process_ctrlbuf(dhd); - - timeleft = dhd_os_ioctl_resp_wait(dhd, (uint *)&prot->ioctl_received); - /* Enable Back Interrupts using IntMask */ - dhdpcie_bus_intr_enable(dhd->bus); - } - } -#endif /* DHD_RECOVER_TIMEOUT */ - - if (dhd->conf->ctrl_resched > 0 && timeleft == 0 && (!dhd_query_bus_erros(dhd))) { - cnt++; - if (cnt <= dhd->conf->ctrl_resched) { - uint32 intstatus = 0, intmask = 0; - intstatus = si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, PCIMailBoxInt, 0, 0); - intmask = si_corereg(dhd->bus->sih, dhd->bus->sih->buscoreidx, PCIMailBoxMask, 0, 0); - if (intstatus) { - DHD_ERROR(("%s: reschedule dhd_dpc, cnt=%d, intstatus=0x%x, intmask=0x%x\n", - __FUNCTION__, cnt, intstatus, intmask)); - dhd->bus->ipend = TRUE; - dhd->bus->dpc_sched = TRUE; - dhd_sched_dpc(dhd); - timeleft = dhd_os_ioctl_resp_wait(dhd, &prot->ioctl_received, true); - } - } - } else { - cnt = 0; - } - - if (timeleft == 0 && (!dhd_query_bus_erros(dhd))) { - uint32 intstatus; - - dhd->rxcnt_timeout++; - dhd->rx_ctlerrs++; - dhd->iovar_timeout_occured = TRUE; - DHD_ERROR(("%s: resumed on timeout rxcnt_timeout %d ioctl_cmd %d " - "trans_id %d state %d busstate=%d ioctl_received=%d\n", - __FUNCTION__, dhd->rxcnt_timeout, prot->curr_ioctl_cmd, - prot->ioctl_trans_id, prot->ioctl_state, - dhd->busstate, prot->ioctl_received)); - if (prot->curr_ioctl_cmd == WLC_SET_VAR || - prot->curr_ioctl_cmd == WLC_GET_VAR) { - char iovbuf[32]; - int i; - int dump_size = 128; - uint8 *ioctl_buf = (uint8 *)prot->ioctbuf.va; - memset(iovbuf, 0, sizeof(iovbuf)); - strncpy(iovbuf, ioctl_buf, sizeof(iovbuf) - 1); - iovbuf[sizeof(iovbuf) - 1] = '\0'; - DHD_ERROR(("Current IOVAR (%s): %s\n", - prot->curr_ioctl_cmd == WLC_SET_VAR ? - "WLC_SET_VAR" : "WLC_GET_VAR", iovbuf)); - DHD_ERROR(("========== START IOCTL REQBUF DUMP ==========\n")); - for (i = 0; i < dump_size; i++) { - DHD_ERROR(("%02X ", ioctl_buf[i])); - if ((i % 32) == 31) { - DHD_ERROR(("\n")); - } - } - DHD_ERROR(("\n========== END IOCTL REQBUF DUMP ==========\n")); - } - - /* Check the PCIe link status by reading intstatus register */ - intstatus = si_corereg(dhd->bus->sih, - dhd->bus->sih->buscoreidx, PCIMailBoxInt, 0, 0); - if (intstatus == (uint32)-1) { - DHD_ERROR(("%s : PCIe link might be down\n", __FUNCTION__)); - dhd->bus->is_linkdown = TRUE; - } - - dhd_bus_dump_console_buffer(dhd->bus); - dhd_prot_debug_info_print(dhd); - -#ifdef DHD_FW_COREDUMP - /* Collect socram dump */ - if (dhd->memdump_enabled) { - /* collect core dump */ - dhd->memdump_type = DUMP_TYPE_RESUMED_ON_TIMEOUT; - dhd_bus_mem_dump(dhd); - } -#endif /* DHD_FW_COREDUMP */ -#ifdef SUPPORT_LINKDOWN_RECOVERY -#ifdef CONFIG_ARCH_MSM - dhd->bus->no_cfg_restore = 1; -#endif /* CONFIG_ARCH_MSM */ -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - ret = -ETIMEDOUT; - goto out; - } else { - if (prot->ioctl_received != IOCTL_RETURN_ON_SUCCESS) { - DHD_ERROR(("%s: IOCTL failure due to ioctl_received = %d\n", - __FUNCTION__, prot->ioctl_received)); - ret = -EINVAL; - goto out; - } - dhd->rxcnt_timeout = 0; - dhd->rx_ctlpkts++; - DHD_CTL(("%s: ioctl resp resumed, got %d\n", - __FUNCTION__, prot->ioctl_resplen)); - } - - if (dhd->prot->ioctl_resplen > len) - dhd->prot->ioctl_resplen = (uint16)len; - if (buf) - bcopy(dhd->prot->retbuf.va, buf, dhd->prot->ioctl_resplen); - - ret = (int)(dhd->prot->ioctl_status); - -out: - DHD_GENERAL_LOCK(dhd, flags); - dhd->prot->ioctl_state = 0; - dhd->prot->ioctl_resplen = 0; - dhd->prot->ioctl_received = IOCTL_WAIT; - dhd->prot->curr_ioctl_cmd = 0; - DHD_GENERAL_UNLOCK(dhd, flags); - - return ret; -} /* dhd_msgbuf_wait_ioctl_cmplt */ - -static int -dhd_msgbuf_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) -{ - int ret = 0; - - DHD_TRACE(("%s: Enter \n", __FUNCTION__)); - - 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; - } - - DHD_CTL(("ACTION %d ifdix %d cmd %d len %d \n", - action, ifidx, cmd, len)); - -#ifdef REPORT_FATAL_TIMEOUTS - /* - * These timers "should" be started before sending H2D interrupt. - * Think of the scenario where H2D interrupt is fired and the Dongle - * responds back immediately. From the DPC we would stop the cmd, bus - * timers. But the process context could have switched out leading to - * a situation where the timers are Not started yet, but are actually stopped. - * - * Disable preemption from the time we start the timer until we are done - * with seding H2D interrupts. - */ - OSL_DISABLE_PREEMPTION(dhd->osh); - dhd_set_request_id(dhd, dhd->prot->ioctl_trans_id+1, cmd); - dhd_start_cmd_timer(dhd); - dhd_start_bus_timer(dhd); -#endif /* REPORT_FATAL_TIMEOUTS */ - - /* Fill up msgbuf for ioctl req */ - ret = dhd_fillup_ioct_reqst(dhd, (uint16)len, cmd, buf, ifidx); - -#ifdef REPORT_FATAL_TIMEOUTS - /* For some reason if we fail to ring door bell, stop the timers */ - if (ret < 0) { - DHD_ERROR(("%s(): dhd_fillup_ioct_reqst failed \r\n", __FUNCTION__)); - dhd_stop_cmd_timer(dhd); - dhd_stop_bus_timer(dhd); - OSL_ENABLE_PREEMPTION(dhd->osh); - goto done; - } - - OSL_ENABLE_PREEMPTION(dhd->osh); -#else - if (ret < 0) { - DHD_ERROR(("%s(): dhd_fillup_ioct_reqst failed \r\n", __FUNCTION__)); - goto done; - } -#endif /* REPORT_FATAL_TIMEOUTS */ - - ret = dhd_msgbuf_wait_ioctl_cmplt(dhd, len, buf); - -done: - return ret; -} - -/** Called by upper DHD layer. Handles a protocol control response asynchronously. */ -int dhd_prot_ctl_complete(dhd_pub_t *dhd) -{ - return 0; -} - -/** Called by upper DHD layer. Check for and handle local prot-specific iovar commands */ -int dhd_prot_iovar_op(dhd_pub_t *dhd, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - return BCME_UNSUPPORTED; -} - -/** Add prot dump output to a buffer */ -void dhd_prot_dump(dhd_pub_t *dhd, struct bcmstrbuf *b) -{ - - if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_SEQNUM) - bcm_bprintf(b, "\nd2h_sync: SEQNUM:"); - else if (dhd->d2h_sync_mode & PCIE_SHARED_D2H_SYNC_XORCSUM) - bcm_bprintf(b, "\nd2h_sync: XORCSUM:"); - else - bcm_bprintf(b, "\nd2h_sync: NONE:"); - bcm_bprintf(b, " d2h_sync_wait max<%lu> tot<%lu>\n", - dhd->prot->d2h_sync_wait_max, dhd->prot->d2h_sync_wait_tot); - - bcm_bprintf(b, "\nDongle DMA Indices: h2d %d d2h %d index size %d bytes\n", - dhd->dma_h2d_ring_upd_support, - dhd->dma_d2h_ring_upd_support, - dhd->prot->rw_index_sz); - bcm_bprintf(b, "h2d_max_txpost: %d, prot->h2d_max_txpost: %d\n", - h2d_max_txpost, dhd->prot->h2d_max_txpost); -} - -/* Update local copy of dongle statistics */ -void dhd_prot_dstats(dhd_pub_t *dhd) -{ - return; -} - -/** Called by upper DHD layer */ -int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, - uint reorder_info_len, void **pkt, uint32 *free_buf_count) -{ - return 0; -} - -/** Debug related, post a dummy message to interrupt dongle. Used to process cons commands. */ -int -dhd_post_dummy_msg(dhd_pub_t *dhd) -{ - unsigned long flags; - hostevent_hdr_t *hevent = NULL; - uint16 alloced = 0; - - dhd_prot_t *prot = dhd->prot; - msgbuf_ring_t *ring = &prot->h2dring_ctrl_subn; - -#ifdef PCIE_INB_DW - if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) - return BCME_ERROR; -#endif /* PCIE_INB_DW */ - - DHD_GENERAL_LOCK(dhd, flags); - - hevent = (hostevent_hdr_t *) - dhd_prot_alloc_ring_space(dhd, ring, 1, &alloced, FALSE); - - if (hevent == NULL) { - DHD_GENERAL_UNLOCK(dhd, flags); -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - return -1; - } - - /* CMN msg header */ - hevent->msg.epoch = ring->seqnum % H2D_EPOCH_MODULO; - ring->seqnum++; - hevent->msg.msg_type = MSG_TYPE_HOST_EVNT; - hevent->msg.if_id = 0; - hevent->msg.flags = ring->current_phase; - - /* Event payload */ - hevent->evnt_pyld = htol32(HOST_EVENT_CONS_CMD); - - /* Since, we are filling the data directly into the bufptr obtained - * from the msgbuf, we can directly call the write_complete - */ - dhd_prot_ring_write_complete(dhd, ring, hevent, 1); - DHD_GENERAL_UNLOCK(dhd, flags); -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - - return 0; -} - -/** - * If exactly_nitems is true, this function will allocate space for nitems or fail - * If exactly_nitems is false, this function will allocate space for nitems or less - */ -static void * BCMFASTPATH -dhd_prot_alloc_ring_space(dhd_pub_t *dhd, msgbuf_ring_t *ring, - uint16 nitems, uint16 * alloced, bool exactly_nitems) -{ - void * ret_buf; - - /* Alloc space for nitems in the ring */ - ret_buf = dhd_prot_get_ring_space(ring, nitems, alloced, exactly_nitems); - - if (ret_buf == NULL) { - /* if alloc failed , invalidate cached read ptr */ - if (dhd->dma_d2h_ring_upd_support) { - ring->rd = dhd_prot_dma_indx_get(dhd, H2D_DMA_INDX_RD_UPD, ring->idx); - } else { - dhd_bus_cmn_readshared(dhd->bus, &(ring->rd), RING_RD_UPD, ring->idx); -#ifdef SUPPORT_LINKDOWN_RECOVERY - /* Check if ring->rd is valid */ - if (ring->rd >= ring->max_items) { - dhd->bus->read_shm_fail = TRUE; - DHD_ERROR(("%s: Invalid rd idx=%d\n", ring->name, ring->rd)); - return NULL; - } -#endif /* SUPPORT_LINKDOWN_RECOVERY */ - } - - /* Try allocating once more */ - ret_buf = dhd_prot_get_ring_space(ring, nitems, alloced, exactly_nitems); - - if (ret_buf == NULL) { - DHD_INFO(("%s: Ring space not available \n", ring->name)); - return NULL; - } - } - - if (ret_buf == HOST_RING_BASE(ring)) { - DHD_INFO(("%s: setting the phase now\n", ring->name)); - ring->current_phase = ring->current_phase ? 0 : BCMPCIE_CMNHDR_PHASE_BIT_INIT; - } - - /* Return alloced space */ - return ret_buf; -} - -/** - * Non inline ioct request. - * Form a ioctl request first as per ioctptr_reqst_hdr_t header in the circular buffer - * Form a separate request buffer where a 4 byte cmn header is added in the front - * buf contents from parent function is copied to remaining section of this buffer - */ -static int -dhd_fillup_ioct_reqst(dhd_pub_t *dhd, uint16 len, uint cmd, void* buf, int ifidx) -{ - dhd_prot_t *prot = dhd->prot; - ioctl_req_msg_t *ioct_rqst; - void * ioct_buf; /* For ioctl payload */ - uint16 rqstlen, resplen; - unsigned long flags; - uint16 alloced = 0; - msgbuf_ring_t *ring = &prot->h2dring_ctrl_subn; - - if (dhd_query_bus_erros(dhd)) { - return -EIO; - } - - rqstlen = len; - resplen = len; - - /* Limit ioct request to MSGBUF_MAX_MSG_SIZE bytes including hdrs */ - /* 8K allocation of dongle buffer fails */ - /* dhd doesnt give separate input & output buf lens */ - /* so making the assumption that input length can never be more than 1.5k */ - rqstlen = MIN(rqstlen, MSGBUF_MAX_MSG_SIZE); - -#ifdef PCIE_INB_DW - if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) - return BCME_ERROR; -#endif /* PCIE_INB_DW */ - - DHD_GENERAL_LOCK(dhd, flags); - - if (prot->ioctl_state) { - DHD_ERROR(("%s: pending ioctl %02x\n", __FUNCTION__, prot->ioctl_state)); - DHD_GENERAL_UNLOCK(dhd, flags); -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - return BCME_BUSY; - } else { - prot->ioctl_state = MSGBUF_IOCTL_ACK_PENDING | MSGBUF_IOCTL_RESP_PENDING; - } - - /* Request for cbuf space */ - ioct_rqst = (ioctl_req_msg_t*) - dhd_prot_alloc_ring_space(dhd, ring, 1, &alloced, FALSE); - if (ioct_rqst == NULL) { - DHD_ERROR(("couldn't allocate space on msgring to send ioctl request\n")); - prot->ioctl_state = 0; - prot->curr_ioctl_cmd = 0; - prot->ioctl_received = IOCTL_WAIT; - DHD_GENERAL_UNLOCK(dhd, flags); -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - return -1; - } - - /* Common msg buf hdr */ - ioct_rqst->cmn_hdr.msg_type = MSG_TYPE_IOCTLPTR_REQ; - ioct_rqst->cmn_hdr.if_id = (uint8)ifidx; - ioct_rqst->cmn_hdr.flags = ring->current_phase; - ioct_rqst->cmn_hdr.request_id = htol32(DHD_IOCTL_REQ_PKTID); - ioct_rqst->cmn_hdr.epoch = ring->seqnum % H2D_EPOCH_MODULO; - ring->seqnum++; - - ioct_rqst->cmd = htol32(cmd); - prot->curr_ioctl_cmd = cmd; - ioct_rqst->output_buf_len = htol16(resplen); - prot->ioctl_trans_id++; - ioct_rqst->trans_id = prot->ioctl_trans_id; - - /* populate ioctl buffer info */ - ioct_rqst->input_buf_len = htol16(rqstlen); - ioct_rqst->host_input_buf_addr.high = htol32(PHYSADDRHI(prot->ioctbuf.pa)); - ioct_rqst->host_input_buf_addr.low = htol32(PHYSADDRLO(prot->ioctbuf.pa)); - /* copy ioct payload */ - ioct_buf = (void *) prot->ioctbuf.va; - - if (buf) - memcpy(ioct_buf, buf, len); - - OSL_CACHE_FLUSH((void *) prot->ioctbuf.va, len); - - if (!ISALIGNED(ioct_buf, DMA_ALIGN_LEN)) - DHD_ERROR(("host ioct address unaligned !!!!! \n")); - - DHD_CTL(("submitted IOCTL request request_id %d, cmd %d, output_buf_len %d, tx_id %d\n", - ioct_rqst->cmn_hdr.request_id, cmd, ioct_rqst->output_buf_len, - ioct_rqst->trans_id)); - - /* update ring's WR index and ring doorbell to dongle */ - dhd_prot_ring_write_complete(dhd, ring, ioct_rqst, 1); - DHD_GENERAL_UNLOCK(dhd, flags); -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - - return 0; -} /* dhd_fillup_ioct_reqst */ - - -/** - * dhd_prot_ring_attach - Initialize the msgbuf_ring object and attach a - * DMA-able buffer to it. The ring is NOT tagged as inited until all the ring - * information is posted to the dongle. - * - * Invoked in dhd_prot_attach for the common rings, and in dhd_prot_init for - * each flowring in pool of flowrings. - * - * returns BCME_OK=0 on success - * returns non-zero negative error value on failure. - */ -static int -dhd_prot_ring_attach(dhd_pub_t *dhd, msgbuf_ring_t *ring, const char *name, - uint16 max_items, uint16 item_len, uint16 ringid) -{ - int dma_buf_alloced = BCME_NOMEM; - uint32 dma_buf_len = max_items * item_len; - dhd_prot_t *prot = dhd->prot; - uint16 max_flowrings = dhd->bus->max_tx_flowrings; - - ASSERT(ring); - ASSERT(name); - ASSERT((max_items < 0xFFFF) && (item_len < 0xFFFF) && (ringid < 0xFFFF)); - - /* Init name */ - strncpy(ring->name, name, RING_NAME_MAX_LENGTH); - ring->name[RING_NAME_MAX_LENGTH - 1] = '\0'; - - ring->idx = ringid; - - ring->max_items = max_items; - ring->item_len = item_len; - - /* A contiguous space may be reserved for all flowrings */ - if (DHD_IS_FLOWRING(ringid, max_flowrings) && (prot->flowrings_dma_buf.va)) { - /* Carve out from the contiguous DMA-able flowring buffer */ - uint16 flowid; - uint32 base_offset; - - dhd_dma_buf_t *dma_buf = &ring->dma_buf; - dhd_dma_buf_t *rsv_buf = &prot->flowrings_dma_buf; - - flowid = DHD_RINGID_TO_FLOWID(ringid); - base_offset = (flowid - BCMPCIE_H2D_COMMON_MSGRINGS) * dma_buf_len; - - ASSERT(base_offset + dma_buf_len <= rsv_buf->len); - - dma_buf->len = dma_buf_len; - dma_buf->va = (void *)((uintptr)rsv_buf->va + base_offset); - PHYSADDRHISET(dma_buf->pa, PHYSADDRHI(rsv_buf->pa)); - PHYSADDRLOSET(dma_buf->pa, PHYSADDRLO(rsv_buf->pa) + base_offset); - - /* On 64bit, contiguous space may not span across 0x00000000FFFFFFFF */ - ASSERT(PHYSADDRLO(dma_buf->pa) >= PHYSADDRLO(rsv_buf->pa)); - - dma_buf->dmah = rsv_buf->dmah; - dma_buf->secdma = rsv_buf->secdma; - - (void)dhd_dma_buf_audit(dhd, &ring->dma_buf); - } else { - /* Allocate a dhd_dma_buf */ - dma_buf_alloced = dhd_dma_buf_alloc(dhd, &ring->dma_buf, dma_buf_len); - if (dma_buf_alloced != BCME_OK) { - return BCME_NOMEM; - } - } - - /* CAUTION: Save ring::base_addr in little endian format! */ - dhd_base_addr_htolpa(&ring->base_addr, ring->dma_buf.pa); - -#ifdef BCM_SECURE_DMA - if (SECURE_DMA_ENAB(prot->osh)) { - ring->dma_buf.secdma = MALLOCZ(prot->osh, sizeof(sec_cma_info_t)); - if (ring->dma_buf.secdma == NULL) { - goto free_dma_buf; - } - } -#endif /* BCM_SECURE_DMA */ - - DHD_INFO(("RING_ATTACH : %s Max item %d len item %d total size %d " - "ring start %p buf phys addr %x:%x \n", - ring->name, ring->max_items, ring->item_len, - dma_buf_len, ring->dma_buf.va, ltoh32(ring->base_addr.high_addr), - ltoh32(ring->base_addr.low_addr))); - - return BCME_OK; - -#ifdef BCM_SECURE_DMA -free_dma_buf: - if (dma_buf_alloced == BCME_OK) { - dhd_dma_buf_free(dhd, &ring->dma_buf); - } -#endif /* BCM_SECURE_DMA */ - - return BCME_NOMEM; - -} /* dhd_prot_ring_attach */ - - -/** - * dhd_prot_ring_init - Post the common ring information to dongle. - * - * Used only for common rings. - * - * The flowrings information is passed via the create flowring control message - * (tx_flowring_create_request_t) sent over the H2D control submission common - * ring. - */ -static void -dhd_prot_ring_init(dhd_pub_t *dhd, msgbuf_ring_t *ring) -{ - ring->wr = 0; - ring->rd = 0; - ring->curr_rd = 0; - - /* CAUTION: ring::base_addr already in Little Endian */ - dhd_bus_cmn_writeshared(dhd->bus, &ring->base_addr, - sizeof(sh_addr_t), RING_BUF_ADDR, ring->idx); - dhd_bus_cmn_writeshared(dhd->bus, &ring->max_items, - sizeof(uint16), RING_MAX_ITEMS, ring->idx); - dhd_bus_cmn_writeshared(dhd->bus, &ring->item_len, - sizeof(uint16), RING_ITEM_LEN, ring->idx); - - dhd_bus_cmn_writeshared(dhd->bus, &(ring->wr), - sizeof(uint16), RING_WR_UPD, ring->idx); - dhd_bus_cmn_writeshared(dhd->bus, &(ring->rd), - sizeof(uint16), RING_RD_UPD, ring->idx); - - /* ring inited */ - ring->inited = TRUE; - -} /* dhd_prot_ring_init */ - - -/** - * dhd_prot_ring_reset - bzero a ring's DMA-ble buffer and cache flush - * Reset WR and RD indices to 0. - */ -static void -dhd_prot_ring_reset(dhd_pub_t *dhd, msgbuf_ring_t *ring) -{ - DHD_TRACE(("%s\n", __FUNCTION__)); - - dhd_dma_buf_reset(dhd, &ring->dma_buf); - - ring->rd = ring->wr = 0; - ring->curr_rd = 0; - ring->inited = FALSE; - ring->create_pending = FALSE; -} - - -/** - * dhd_prot_ring_detach - Detach the DMA-able buffer and any other objects - * hanging off the msgbuf_ring. - */ -static void -dhd_prot_ring_detach(dhd_pub_t *dhd, msgbuf_ring_t *ring) -{ - dhd_prot_t *prot = dhd->prot; - uint16 max_flowrings = dhd->bus->max_tx_flowrings; - ASSERT(ring); - - ring->inited = FALSE; - /* rd = ~0, wr = ring->rd - 1, max_items = 0, len_item = ~0 */ - -#ifdef BCM_SECURE_DMA - if (SECURE_DMA_ENAB(prot->osh)) { - if (ring->dma_buf.secdma) { - SECURE_DMA_UNMAP_ALL(prot->osh, ring->dma_buf.secdma); - MFREE(prot->osh, ring->dma_buf.secdma, sizeof(sec_cma_info_t)); - ring->dma_buf.secdma = NULL; - } - } -#endif /* BCM_SECURE_DMA */ - - /* If the DMA-able buffer was carved out of a pre-reserved contiguous - * memory, then simply stop using it. - */ - if (DHD_IS_FLOWRING(ring->idx, max_flowrings) && (prot->flowrings_dma_buf.va)) { - (void)dhd_dma_buf_audit(dhd, &ring->dma_buf); - memset(&ring->dma_buf, 0, sizeof(dhd_dma_buf_t)); - } else { - dhd_dma_buf_free(dhd, &ring->dma_buf); - } - -} /* dhd_prot_ring_detach */ - - -/* - * +---------------------------------------------------------------------------- - * Flowring Pool - * - * Unlike common rings, which are attached very early on (dhd_prot_attach), - * flowrings are dynamically instantiated. Moreover, flowrings may require a - * larger DMA-able buffer. To avoid issues with fragmented cache coherent - * DMA-able memory, a pre-allocated pool of msgbuf_ring_t is allocated once. - * The DMA-able buffers are attached to these pre-allocated msgbuf_ring. - * - * Each DMA-able buffer may be allocated independently, or may be carved out - * of a single large contiguous region that is registered with the protocol - * layer into flowrings_dma_buf. On a 64bit platform, this contiguous region - * may not span 0x00000000FFFFFFFF (avoid dongle side 64bit ptr arithmetic). - * - * No flowring pool action is performed in dhd_prot_attach(), as the number - * of h2d rings is not yet known. - * - * In dhd_prot_init(), the dongle advertized number of h2d rings is used to - * determine the number of flowrings required, and a pool of msgbuf_rings are - * allocated and a DMA-able buffer (carved or allocated) is attached. - * See: dhd_prot_flowrings_pool_attach() - * - * A flowring msgbuf_ring object may be fetched from this pool during flowring - * creation, using the flowid. Likewise, flowrings may be freed back into the - * pool on flowring deletion. - * See: dhd_prot_flowrings_pool_fetch(), dhd_prot_flowrings_pool_release() - * - * In dhd_prot_detach(), the flowring pool is detached. The DMA-able buffers - * are detached (returned back to the carved region or freed), and the pool of - * msgbuf_ring and any objects allocated against it are freed. - * See: dhd_prot_flowrings_pool_detach() - * - * In dhd_prot_reset(), the flowring pool is simply reset by returning it to a - * state as-if upon an attach. All DMA-able buffers are retained. - * Following a dhd_prot_reset(), in a subsequent dhd_prot_init(), the flowring - * pool attach will notice that the pool persists and continue to use it. This - * will avoid the case of a fragmented DMA-able region. - * - * +---------------------------------------------------------------------------- - */ - -/* Conversion of a flowid to a flowring pool index */ -#define DHD_FLOWRINGS_POOL_OFFSET(flowid) \ - ((flowid) - BCMPCIE_H2D_COMMON_MSGRINGS) - -/* Fetch the msgbuf_ring_t from the flowring pool given a flowid */ -#define DHD_RING_IN_FLOWRINGS_POOL(prot, flowid) \ - (msgbuf_ring_t*)((prot)->h2d_flowrings_pool) + \ - DHD_FLOWRINGS_POOL_OFFSET(flowid) - -/* Traverse each flowring in the flowring pool, assigning ring and flowid */ -#define FOREACH_RING_IN_FLOWRINGS_POOL(prot, ring, flowid, total_flowrings) \ - for ((flowid) = DHD_FLOWRING_START_FLOWID, \ - (ring) = DHD_RING_IN_FLOWRINGS_POOL(prot, flowid); \ - (flowid) < ((total_flowrings) + DHD_FLOWRING_START_FLOWID); \ - (ring)++, (flowid)++) - -/* Fetch number of H2D flowrings given the total number of h2d rings */ -static uint16 -dhd_get_max_flow_rings(dhd_pub_t *dhd) -{ - if (dhd->bus->api.fw_rev >= PCIE_SHARED_VERSION_6) - return dhd->bus->max_tx_flowrings; - else - return (dhd->bus->max_tx_flowrings - BCMPCIE_H2D_COMMON_MSGRINGS); -} - -/** - * dhd_prot_flowrings_pool_attach - Initialize a pool of flowring msgbuf_ring_t. - * - * Allocate a pool of msgbuf_ring along with DMA-able buffers for flowrings. - * Dongle includes common rings when it advertizes the number of H2D rings. - * Allocates a pool of msgbuf_ring_t and invokes dhd_prot_ring_attach to - * allocate the DMA-able buffer and initialize each msgbuf_ring_t object. - * - * dhd_prot_ring_attach is invoked to perform the actual initialization and - * attaching the DMA-able buffer. - * - * Later dhd_prot_flowrings_pool_fetch() may be used to fetch a preallocated and - * initialized msgbuf_ring_t object. - * - * returns BCME_OK=0 on success - * returns non-zero negative error value on failure. - */ -static int -dhd_prot_flowrings_pool_attach(dhd_pub_t *dhd) -{ - uint16 flowid; - msgbuf_ring_t *ring; - uint16 h2d_flowrings_total; /* exclude H2D common rings */ - dhd_prot_t *prot = dhd->prot; - char ring_name[RING_NAME_MAX_LENGTH]; - - if (prot->h2d_flowrings_pool != NULL) - return BCME_OK; /* dhd_prot_init rentry after a dhd_prot_reset */ - - ASSERT(prot->h2d_rings_total == 0); - - /* h2d_rings_total includes H2D common rings: ctrl and rxbuf subn */ - prot->h2d_rings_total = (uint16)dhd_bus_max_h2d_queues(dhd->bus); - - if (prot->h2d_rings_total < BCMPCIE_H2D_COMMON_MSGRINGS) { - DHD_ERROR(("%s: h2d_rings_total advertized as %u\n", - __FUNCTION__, prot->h2d_rings_total)); - return BCME_ERROR; - } - - /* Subtract number of H2D common rings, to determine number of flowrings */ - h2d_flowrings_total = dhd_get_max_flow_rings(dhd); - - DHD_ERROR(("Attach flowrings pool for %d rings\n", h2d_flowrings_total)); - - /* Allocate pool of msgbuf_ring_t objects for all flowrings */ - prot->h2d_flowrings_pool = (msgbuf_ring_t *)MALLOCZ(prot->osh, - (h2d_flowrings_total * sizeof(msgbuf_ring_t))); - - if (prot->h2d_flowrings_pool == NULL) { - DHD_ERROR(("%s: flowrings pool for %d flowrings, alloc failure\n", - __FUNCTION__, h2d_flowrings_total)); - goto fail; - } - - /* Setup & Attach a DMA-able buffer to each flowring in the flowring pool */ - FOREACH_RING_IN_FLOWRINGS_POOL(prot, ring, flowid, h2d_flowrings_total) { - snprintf(ring_name, sizeof(ring_name), "h2dflr_%03u", flowid); - if (dhd_prot_ring_attach(dhd, ring, ring_name, - prot->h2d_max_txpost, H2DRING_TXPOST_ITEMSIZE, - DHD_FLOWID_TO_RINGID(flowid)) != BCME_OK) { - goto attach_fail; - } - } - - return BCME_OK; - -attach_fail: - dhd_prot_flowrings_pool_detach(dhd); /* Free entire pool of flowrings */ - -fail: - prot->h2d_rings_total = 0; - return BCME_NOMEM; - -} /* dhd_prot_flowrings_pool_attach */ - - -/** - * dhd_prot_flowrings_pool_reset - Reset all msgbuf_ring_t objects in the pool. - * Invokes dhd_prot_ring_reset to perform the actual reset. - * - * The DMA-able buffer is not freed during reset and neither is the flowring - * pool freed. - * - * dhd_prot_flowrings_pool_reset will be invoked in dhd_prot_reset. Following - * the dhd_prot_reset, dhd_prot_init will be re-invoked, and the flowring pool - * from a previous flowring pool instantiation will be reused. - * - * This will avoid a fragmented DMA-able memory condition, if multiple - * dhd_prot_reset were invoked to reboot the dongle without a full detach/attach - * cycle. - */ -static void -dhd_prot_flowrings_pool_reset(dhd_pub_t *dhd) -{ - uint16 flowid, h2d_flowrings_total; - msgbuf_ring_t *ring; - dhd_prot_t *prot = dhd->prot; - - if (prot->h2d_flowrings_pool == NULL) { - ASSERT(prot->h2d_rings_total == 0); - return; - } - h2d_flowrings_total = dhd_get_max_flow_rings(dhd); - /* Reset each flowring in the flowring pool */ - FOREACH_RING_IN_FLOWRINGS_POOL(prot, ring, flowid, h2d_flowrings_total) { - dhd_prot_ring_reset(dhd, ring); - ring->inited = FALSE; - } - - /* Flowring pool state must be as-if dhd_prot_flowrings_pool_attach */ -} - - -/** - * dhd_prot_flowrings_pool_detach - Free pool of msgbuf_ring along with - * DMA-able buffers for flowrings. - * dhd_prot_ring_detach is invoked to free the DMA-able buffer and perform any - * de-initialization of each msgbuf_ring_t. - */ -static void -dhd_prot_flowrings_pool_detach(dhd_pub_t *dhd) -{ - int flowid; - msgbuf_ring_t *ring; - uint16 h2d_flowrings_total; /* exclude H2D common rings */ - dhd_prot_t *prot = dhd->prot; - - if (prot->h2d_flowrings_pool == NULL) { - ASSERT(prot->h2d_rings_total == 0); - return; - } - - h2d_flowrings_total = dhd_get_max_flow_rings(dhd); - /* Detach the DMA-able buffer for each flowring in the flowring pool */ - FOREACH_RING_IN_FLOWRINGS_POOL(prot, ring, flowid, h2d_flowrings_total) { - dhd_prot_ring_detach(dhd, ring); - } - - - MFREE(prot->osh, prot->h2d_flowrings_pool, - (h2d_flowrings_total * sizeof(msgbuf_ring_t))); - - prot->h2d_flowrings_pool = (msgbuf_ring_t*)NULL; - prot->h2d_rings_total = 0; - -} /* dhd_prot_flowrings_pool_detach */ - - -/** - * dhd_prot_flowrings_pool_fetch - Fetch a preallocated and initialized - * msgbuf_ring from the flowring pool, and assign it. - * - * Unlike common rings, which uses a dhd_prot_ring_init() to pass the common - * ring information to the dongle, a flowring's information is passed via a - * flowring create control message. - * - * Only the ring state (WR, RD) index are initialized. - */ -static msgbuf_ring_t * -dhd_prot_flowrings_pool_fetch(dhd_pub_t *dhd, uint16 flowid) -{ - msgbuf_ring_t *ring; - dhd_prot_t *prot = dhd->prot; - - ASSERT(flowid >= DHD_FLOWRING_START_FLOWID); - ASSERT(flowid < prot->h2d_rings_total); - ASSERT(prot->h2d_flowrings_pool != NULL); - - ring = DHD_RING_IN_FLOWRINGS_POOL(prot, flowid); - - /* ASSERT flow_ring->inited == FALSE */ - - ring->wr = 0; - ring->rd = 0; - ring->curr_rd = 0; - ring->inited = TRUE; - /** - * Every time a flowring starts dynamically, initialize current_phase with 0 - * then flip to BCMPCIE_CMNHDR_PHASE_BIT_INIT - */ - ring->current_phase = 0; - return ring; -} - - -/** - * dhd_prot_flowrings_pool_release - release a previously fetched flowring's - * msgbuf_ring back to the flow_ring pool. - */ -void -dhd_prot_flowrings_pool_release(dhd_pub_t *dhd, uint16 flowid, void *flow_ring) -{ - msgbuf_ring_t *ring; - dhd_prot_t *prot = dhd->prot; - - ASSERT(flowid >= DHD_FLOWRING_START_FLOWID); - ASSERT(flowid < prot->h2d_rings_total); - ASSERT(prot->h2d_flowrings_pool != NULL); - - ring = DHD_RING_IN_FLOWRINGS_POOL(prot, flowid); - - ASSERT(ring == (msgbuf_ring_t*)flow_ring); - /* ASSERT flow_ring->inited == TRUE */ - - (void)dhd_dma_buf_audit(dhd, &ring->dma_buf); - - ring->wr = 0; - ring->rd = 0; - ring->inited = FALSE; - - ring->curr_rd = 0; -} - - -/* Assumes only one index is updated at a time */ -/* If exactly_nitems is true, this function will allocate space for nitems or fail */ -/* Exception: when wrap around is encountered, to prevent hangup (last nitems of ring buffer) */ -/* If exactly_nitems is false, this function will allocate space for nitems or less */ -static void *BCMFASTPATH -dhd_prot_get_ring_space(msgbuf_ring_t *ring, uint16 nitems, uint16 * alloced, - bool exactly_nitems) -{ - void *ret_ptr = NULL; - uint16 ring_avail_cnt; - - ASSERT(nitems <= ring->max_items); - - ring_avail_cnt = CHECK_WRITE_SPACE(ring->rd, ring->wr, ring->max_items); - - if ((ring_avail_cnt == 0) || - (exactly_nitems && (ring_avail_cnt < nitems) && - ((ring->max_items - ring->wr) >= nitems))) { - DHD_INFO(("Space not available: ring %s items %d write %d read %d\n", - ring->name, nitems, ring->wr, ring->rd)); - return NULL; - } - *alloced = MIN(nitems, ring_avail_cnt); - - /* Return next available space */ - ret_ptr = (char *)DHD_RING_BGN_VA(ring) + (ring->wr * ring->item_len); - - /* Update write index */ - if ((ring->wr + *alloced) == ring->max_items) - ring->wr = 0; - else if ((ring->wr + *alloced) < ring->max_items) - ring->wr += *alloced; - else { - /* Should never hit this */ - ASSERT(0); - return NULL; - } - - return ret_ptr; -} /* dhd_prot_get_ring_space */ - - -/** - * dhd_prot_ring_write_complete - Host updates the new WR index on producing - * new messages in a H2D ring. The messages are flushed from cache prior to - * posting the new WR index. The new WR index will be updated in the DMA index - * array or directly in the dongle's ring state memory. - * A PCIE doorbell will be generated to wake up the dongle. - * This is a non-atomic function, make sure the callers - * always hold appropriate locks. - */ -static void BCMFASTPATH -dhd_prot_ring_write_complete(dhd_pub_t *dhd, msgbuf_ring_t * ring, void* p, - uint16 nitems) -{ - dhd_prot_t *prot = dhd->prot; - uint8 db_index; - uint16 max_flowrings = dhd->bus->max_tx_flowrings; - - /* cache flush */ - OSL_CACHE_FLUSH(p, ring->item_len * nitems); - - if (IDMA_DS_ACTIVE(dhd) && IDMA_ACTIVE(dhd)) { - dhd_bus_cmn_writeshared(dhd->bus, &(ring->wr), - sizeof(uint16), RING_WR_UPD, ring->idx); - } else if (IDMA_ACTIVE(dhd) || dhd->dma_h2d_ring_upd_support) { - dhd_prot_dma_indx_set(dhd, ring->wr, - H2D_DMA_INDX_WR_UPD, ring->idx); - } else if (IFRM_ACTIVE(dhd) && DHD_IS_FLOWRING(ring->idx, max_flowrings)) { - dhd_prot_dma_indx_set(dhd, ring->wr, - H2D_IFRM_INDX_WR_UPD, ring->idx); - } else { - dhd_bus_cmn_writeshared(dhd->bus, &(ring->wr), - sizeof(uint16), RING_WR_UPD, ring->idx); - } - - /* raise h2d interrupt */ - if (IDMA_ACTIVE(dhd) || - (IFRM_ACTIVE(dhd) && DHD_IS_FLOWRING(ring->idx, max_flowrings))) { - if (IDMA_DS_ACTIVE(dhd)) { - prot->mb_ring_fn(dhd->bus, ring->wr); - } else { - db_index = IDMA_IDX0; - prot->mb_2_ring_fn(dhd->bus, db_index, TRUE); - } - } else { - prot->mb_ring_fn(dhd->bus, ring->wr); - } -} - -/** - * dhd_prot_upd_read_idx - Host updates the new RD index on consuming messages - * from a D2H ring. The new RD index will be updated in the DMA Index array or - * directly in dongle's ring state memory. - */ -static void -dhd_prot_upd_read_idx(dhd_pub_t *dhd, msgbuf_ring_t * ring) -{ - dhd_prot_t *prot = dhd->prot; - uint8 db_index; - - /* update read index */ - /* If dma'ing h2d indices supported - * update the r -indices in the - * host memory o/w in TCM - */ - if (IDMA_ACTIVE(dhd)) { - dhd_prot_dma_indx_set(dhd, ring->rd, - D2H_DMA_INDX_RD_UPD, ring->idx); - if (IDMA_DS_ACTIVE(dhd)) { - dhd_bus_cmn_writeshared(dhd->bus, &(ring->rd), - sizeof(uint16), RING_RD_UPD, ring->idx); - } else { - db_index = IDMA_IDX1; - prot->mb_2_ring_fn(dhd->bus, db_index, FALSE); - } - } else if (dhd->dma_h2d_ring_upd_support) { - dhd_prot_dma_indx_set(dhd, ring->rd, - D2H_DMA_INDX_RD_UPD, ring->idx); - } else { - dhd_bus_cmn_writeshared(dhd->bus, &(ring->rd), - sizeof(uint16), RING_RD_UPD, ring->idx); - } -} - -static int -dhd_send_d2h_ringcreate(dhd_pub_t *dhd, msgbuf_ring_t *ring_to_create) -{ - unsigned long flags; - d2h_ring_create_req_t *d2h_ring; - uint16 alloced = 0; - int ret = BCME_OK; - uint16 max_h2d_rings = dhd->bus->max_submission_rings; - -#ifdef PCIE_INB_DW - if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) - return BCME_ERROR; -#endif /* PCIE_INB_DW */ - DHD_GENERAL_LOCK(dhd, flags); - - DHD_TRACE(("%s trying to send D2H ring create Req\n", __FUNCTION__)); - - if (ring_to_create == NULL) { - DHD_ERROR(("%s: FATAL: ring_to_create is NULL\n", __FUNCTION__)); - ret = BCME_ERROR; - goto err; - } - - /* Request for ring buffer space */ - d2h_ring = (d2h_ring_create_req_t *) dhd_prot_alloc_ring_space(dhd, - &dhd->prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, - &alloced, FALSE); - - if (d2h_ring == NULL) { - DHD_ERROR(("%s: FATAL: No space in control ring to send D2H ring create\n", - __FUNCTION__)); - ret = BCME_NOMEM; - goto err; - } - ring_to_create->create_req_id = DHD_D2H_DBGRING_REQ_PKTID; - ring_to_create->create_pending = TRUE; - - /* Common msg buf hdr */ - d2h_ring->msg.msg_type = MSG_TYPE_D2H_RING_CREATE; - d2h_ring->msg.if_id = 0; - d2h_ring->msg.flags = dhd->prot->h2dring_ctrl_subn.current_phase; - d2h_ring->msg.request_id = htol32(ring_to_create->create_req_id); - d2h_ring->ring_id = htol16(DHD_D2H_RING_OFFSET(ring_to_create->idx, max_h2d_rings)); - d2h_ring->ring_type = BCMPCIE_D2H_RING_TYPE_DBGBUF_CPL; - d2h_ring->max_items = htol16(D2HRING_DYNAMIC_INFO_MAX_ITEM); - d2h_ring->len_item = htol16(D2HRING_INFO_BUFCMPLT_ITEMSIZE); - d2h_ring->ring_ptr.low_addr = ring_to_create->base_addr.low_addr; - d2h_ring->ring_ptr.high_addr = ring_to_create->base_addr.high_addr; - - d2h_ring->flags = 0; - d2h_ring->msg.epoch = - dhd->prot->h2dring_ctrl_subn.seqnum % H2D_EPOCH_MODULO; - dhd->prot->h2dring_ctrl_subn.seqnum++; - - /* Update the flow_ring's WRITE index */ - dhd_prot_ring_write_complete(dhd, &dhd->prot->h2dring_ctrl_subn, d2h_ring, - DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); - -err: - DHD_GENERAL_UNLOCK(dhd, flags); -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - return ret; -} - -static int -dhd_send_h2d_ringcreate(dhd_pub_t *dhd, msgbuf_ring_t *ring_to_create) -{ - unsigned long flags; - h2d_ring_create_req_t *h2d_ring; - uint16 alloced = 0; - uint8 i = 0; - int ret = BCME_OK; - - -#ifdef PCIE_INB_DW - if (dhd_prot_inc_hostactive_devwake_assert(dhd->bus) != BCME_OK) - return BCME_ERROR; -#endif /* PCIE_INB_DW */ - DHD_GENERAL_LOCK(dhd, flags); - - DHD_TRACE(("%s trying to send H2D ring create Req\n", __FUNCTION__)); - - if (ring_to_create == NULL) { - DHD_ERROR(("%s: FATAL: ring_to_create is NULL\n", __FUNCTION__)); - ret = BCME_ERROR; - goto err; - } - - /* Request for ring buffer space */ - h2d_ring = (h2d_ring_create_req_t *)dhd_prot_alloc_ring_space(dhd, - &dhd->prot->h2dring_ctrl_subn, DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D, - &alloced, FALSE); - - if (h2d_ring == NULL) { - DHD_ERROR(("%s: FATAL: No space in control ring to send H2D ring create\n", - __FUNCTION__)); - ret = BCME_NOMEM; - goto err; - } - ring_to_create->create_req_id = DHD_H2D_DBGRING_REQ_PKTID; - ring_to_create->create_pending = TRUE; - - /* Common msg buf hdr */ - h2d_ring->msg.msg_type = MSG_TYPE_H2D_RING_CREATE; - h2d_ring->msg.if_id = 0; - h2d_ring->msg.request_id = htol32(ring_to_create->create_req_id); - h2d_ring->msg.flags = dhd->prot->h2dring_ctrl_subn.current_phase; - h2d_ring->ring_id = htol16(DHD_H2D_RING_OFFSET(ring_to_create->idx)); - h2d_ring->ring_type = BCMPCIE_H2D_RING_TYPE_DBGBUF_SUBMIT; - h2d_ring->max_items = htol16(H2DRING_DYNAMIC_INFO_MAX_ITEM); - h2d_ring->n_completion_ids = ring_to_create->n_completion_ids; - h2d_ring->len_item = htol16(H2DRING_INFO_BUFPOST_ITEMSIZE); - h2d_ring->ring_ptr.low_addr = ring_to_create->base_addr.low_addr; - h2d_ring->ring_ptr.high_addr = ring_to_create->base_addr.high_addr; - - for (i = 0; i < ring_to_create->n_completion_ids; i++) { - h2d_ring->completion_ring_ids[i] = htol16(ring_to_create->compeltion_ring_ids[i]); - } - - h2d_ring->flags = 0; - h2d_ring->msg.epoch = - dhd->prot->h2dring_ctrl_subn.seqnum % H2D_EPOCH_MODULO; - dhd->prot->h2dring_ctrl_subn.seqnum++; - - /* Update the flow_ring's WRITE index */ - dhd_prot_ring_write_complete(dhd, &dhd->prot->h2dring_ctrl_subn, h2d_ring, - DHD_FLOWRING_DEFAULT_NITEMS_POSTED_H2D); - -err: - DHD_GENERAL_UNLOCK(dhd, flags); -#ifdef PCIE_INB_DW - dhd_prot_dec_hostactive_ack_pending_dsreq(dhd->bus); -#endif - return ret; -} - -/** - * dhd_prot_dma_indx_set - set a new WR or RD index in the DMA index array. - * Dongle will DMA the entire array (if DMA_INDX feature is enabled). - * See dhd_prot_dma_indx_init() - */ -void -dhd_prot_dma_indx_set(dhd_pub_t *dhd, uint16 new_index, uint8 type, uint16 ringid) -{ - uint8 *ptr; - uint16 offset; - dhd_prot_t *prot = dhd->prot; - uint16 max_h2d_rings = dhd->bus->max_submission_rings; - - switch (type) { - case H2D_DMA_INDX_WR_UPD: - ptr = (uint8 *)(prot->h2d_dma_indx_wr_buf.va); - offset = DHD_H2D_RING_OFFSET(ringid); - break; - - case D2H_DMA_INDX_RD_UPD: - ptr = (uint8 *)(prot->d2h_dma_indx_rd_buf.va); - offset = DHD_D2H_RING_OFFSET(ringid, max_h2d_rings); - break; - - case H2D_IFRM_INDX_WR_UPD: - ptr = (uint8 *)(prot->h2d_ifrm_indx_wr_buf.va); - offset = DHD_H2D_FRM_FLOW_RING_OFFSET(ringid); - break; - - default: - DHD_ERROR(("%s: Invalid option for DMAing read/write index\n", - __FUNCTION__)); - return; - } - - ASSERT(prot->rw_index_sz != 0); - ptr += offset * prot->rw_index_sz; - - *(uint16*)ptr = htol16(new_index); - - OSL_CACHE_FLUSH((void *)ptr, prot->rw_index_sz); - - DHD_TRACE(("%s: data %d type %d ringid %d ptr 0x%p offset %d\n", - __FUNCTION__, new_index, type, ringid, ptr, offset)); - -} /* dhd_prot_dma_indx_set */ - - -/** - * dhd_prot_dma_indx_get - Fetch a WR or RD index from the dongle DMA-ed index - * array. - * Dongle DMAes an entire array to host memory (if the feature is enabled). - * See dhd_prot_dma_indx_init() - */ -static uint16 -dhd_prot_dma_indx_get(dhd_pub_t *dhd, uint8 type, uint16 ringid) -{ - uint8 *ptr; - uint16 data; - uint16 offset; - dhd_prot_t *prot = dhd->prot; - uint16 max_h2d_rings = dhd->bus->max_submission_rings; - - switch (type) { - case H2D_DMA_INDX_WR_UPD: - ptr = (uint8 *)(prot->h2d_dma_indx_wr_buf.va); - offset = DHD_H2D_RING_OFFSET(ringid); - break; - - case H2D_DMA_INDX_RD_UPD: - ptr = (uint8 *)(prot->h2d_dma_indx_rd_buf.va); - offset = DHD_H2D_RING_OFFSET(ringid); - break; - - case D2H_DMA_INDX_WR_UPD: - ptr = (uint8 *)(prot->d2h_dma_indx_wr_buf.va); - offset = DHD_D2H_RING_OFFSET(ringid, max_h2d_rings); - break; - - case D2H_DMA_INDX_RD_UPD: - ptr = (uint8 *)(prot->d2h_dma_indx_rd_buf.va); - offset = DHD_D2H_RING_OFFSET(ringid, max_h2d_rings); - break; - - default: - DHD_ERROR(("%s: Invalid option for DMAing read/write index\n", - __FUNCTION__)); - return 0; - } - - ASSERT(prot->rw_index_sz != 0); - ptr += offset * prot->rw_index_sz; - - OSL_CACHE_INV((void *)ptr, prot->rw_index_sz); - - data = LTOH16(*((uint16*)ptr)); - - DHD_TRACE(("%s: data %d type %d ringid %d ptr 0x%p offset %d\n", - __FUNCTION__, data, type, ringid, ptr, offset)); - - return (data); - -} /* dhd_prot_dma_indx_get */ - -/** - * An array of DMA read/write indices, containing information about host rings, can be maintained - * either in host memory or in device memory, dependent on preprocessor options. This function is, - * dependent on these options, called during driver initialization. It reserves and initializes - * blocks of DMA'able host memory containing an array of DMA read or DMA write indices. The physical - * address of these host memory blocks are communicated to the dongle later on. By reading this host - * memory, the dongle learns about the state of the host rings. - */ - -static INLINE int -dhd_prot_dma_indx_alloc(dhd_pub_t *dhd, uint8 type, - dhd_dma_buf_t *dma_buf, uint32 bufsz) -{ - int rc; - - if ((dma_buf->len == bufsz) || (dma_buf->va != NULL)) - return BCME_OK; - - rc = dhd_dma_buf_alloc(dhd, dma_buf, bufsz); - - return rc; -} - -int -dhd_prot_dma_indx_init(dhd_pub_t *dhd, uint32 rw_index_sz, uint8 type, uint32 length) -{ - uint32 bufsz; - dhd_prot_t *prot = dhd->prot; - dhd_dma_buf_t *dma_buf; - - if (prot == NULL) { - DHD_ERROR(("prot is not inited\n")); - return BCME_ERROR; - } - - /* Dongle advertizes 2B or 4B RW index size */ - ASSERT(rw_index_sz != 0); - prot->rw_index_sz = rw_index_sz; - - bufsz = rw_index_sz * length; - - switch (type) { - case H2D_DMA_INDX_WR_BUF: - dma_buf = &prot->h2d_dma_indx_wr_buf; - if (dhd_prot_dma_indx_alloc(dhd, type, dma_buf, bufsz)) - goto ret_no_mem; - DHD_ERROR(("H2D DMA WR INDX : array size %d = %d * %d\n", - dma_buf->len, rw_index_sz, length)); - break; - - case H2D_DMA_INDX_RD_BUF: - dma_buf = &prot->h2d_dma_indx_rd_buf; - if (dhd_prot_dma_indx_alloc(dhd, type, dma_buf, bufsz)) - goto ret_no_mem; - DHD_ERROR(("H2D DMA RD INDX : array size %d = %d * %d\n", - dma_buf->len, rw_index_sz, length)); - break; - - case D2H_DMA_INDX_WR_BUF: - dma_buf = &prot->d2h_dma_indx_wr_buf; - if (dhd_prot_dma_indx_alloc(dhd, type, dma_buf, bufsz)) - goto ret_no_mem; - DHD_ERROR(("D2H DMA WR INDX : array size %d = %d * %d\n", - dma_buf->len, rw_index_sz, length)); - break; - - case D2H_DMA_INDX_RD_BUF: - dma_buf = &prot->d2h_dma_indx_rd_buf; - if (dhd_prot_dma_indx_alloc(dhd, type, dma_buf, bufsz)) - goto ret_no_mem; - DHD_ERROR(("D2H DMA RD INDX : array size %d = %d * %d\n", - dma_buf->len, rw_index_sz, length)); - break; - - case H2D_IFRM_INDX_WR_BUF: - dma_buf = &prot->h2d_ifrm_indx_wr_buf; - if (dhd_prot_dma_indx_alloc(dhd, type, dma_buf, bufsz)) - goto ret_no_mem; - DHD_ERROR(("H2D IFRM WR INDX : array size %d = %d * %d\n", - dma_buf->len, rw_index_sz, length)); - break; - - default: - DHD_ERROR(("%s: Unexpected option\n", __FUNCTION__)); - return BCME_BADOPTION; - } - - return BCME_OK; - -ret_no_mem: - DHD_ERROR(("%s: dhd_prot_dma_indx_alloc type %d buf_sz %d failure\n", - __FUNCTION__, type, bufsz)); - return BCME_NOMEM; - -} /* dhd_prot_dma_indx_init */ - - -/** - * Called on checking for 'completion' messages from the dongle. Returns next host buffer to read - * from, or NULL if there are no more messages to read. - */ -static uint8* -dhd_prot_get_read_addr(dhd_pub_t *dhd, msgbuf_ring_t *ring, uint32 *available_len) -{ - uint16 wr; - uint16 rd; - uint16 depth; - uint16 items; - void *read_addr = NULL; /* address of next msg to be read in ring */ - uint16 d2h_wr = 0; - - DHD_TRACE(("%s: d2h_dma_indx_rd_buf %p, d2h_dma_indx_wr_buf %p\n", - __FUNCTION__, (uint32 *)(dhd->prot->d2h_dma_indx_rd_buf.va), - (uint32 *)(dhd->prot->d2h_dma_indx_wr_buf.va))); - - /* Remember the read index in a variable. - * This is becuase ring->rd gets updated in the end of this function - * So if we have to print the exact read index from which the - * message is read its not possible. - */ - ring->curr_rd = ring->rd; - - /* update write pointer */ - if (dhd->dma_d2h_ring_upd_support) { - /* DMAing write/read indices supported */ - d2h_wr = dhd_prot_dma_indx_get(dhd, D2H_DMA_INDX_WR_UPD, ring->idx); - ring->wr = d2h_wr; - } else { - dhd_bus_cmn_readshared(dhd->bus, &(ring->wr), RING_WR_UPD, ring->idx); - } - - wr = ring->wr; - rd = ring->rd; - depth = ring->max_items; - - /* check for avail space, in number of ring items */ - items = READ_AVAIL_SPACE(wr